From 12a2915a45ad4ad27d1e6c6d0e1612718340224a Mon Sep 17 00:00:00 2001 From: filip mertens Date: Thu, 9 Nov 2023 15:51:22 +0100 Subject: [PATCH] support submodules --- apps/remix-ide/src/app/files/dgitProvider.js | 116 ++++++++++++++++-- apps/remix-ide/src/app/files/fileManager.ts | 9 +- .../workspace/src/lib/actions/payload.ts | 7 ++ .../workspace/src/lib/actions/workspace.ts | 19 ++- .../workspace/src/lib/contexts/index.ts | 1 + .../src/lib/providers/FileSystemProvider.tsx | 10 +- .../workspace/src/lib/reducers/workspace.ts | 17 +++ .../workspace/src/lib/remix-ui-workspace.tsx | 16 ++- .../remix-ui/workspace/src/lib/types/index.ts | 1 + package.json | 2 +- yarn.lock | 37 +++--- 11 files changed, 194 insertions(+), 41 deletions(-) diff --git a/apps/remix-ide/src/app/files/dgitProvider.js b/apps/remix-ide/src/app/files/dgitProvider.js index d4c78d8099..4988cffaf9 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.js +++ b/apps/remix-ide/src/app/files/dgitProvider.js @@ -21,7 +21,7 @@ const profile = { description: 'Decentralized git provider', icon: 'assets/img/fileManager.webp', version: '0.0.1', - methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem'], + methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'updateSubmodules'], kind: 'file-system' } class DGitProvider extends Plugin { @@ -48,13 +48,13 @@ class DGitProvider extends Plugin { this.ipfsSources = [this.remixIPFS, this.globalIPFSConfig, this.ipfsconfig] } - async getGitConfig () { + async getGitConfig (dir = '') { const workspace = await this.call('filePanel', 'getCurrentWorkspace') if (!workspace) return return { fs: window.remixFileSystemCallback, - dir: addSlash(workspace.absolutePath) + dir: addSlash(path.join(workspace.absolutePath, dir || '')), } } @@ -105,15 +105,37 @@ class DGitProvider extends Plugin { } async checkout (cmd, refresh = true) { + const gitmodules = await this.parseGitmodules() || [] await git.checkout({ ...await this.getGitConfig(), ...cmd }) - if (refresh) { + const newgitmodules = await this.parseGitmodules() || [] + // find the difference between the two gitmodule versions + const toRemove = gitmodules.filter((module) => { + return !newgitmodules.find((newmodule) => { + return newmodule.name === module.name + }) + }) + + for (const module of toRemove) { + const path = (await this.getGitConfig(module.path)).dir + if (await window.remixFileSystem.exists(path)) { + const stat = await window.remixFileSystem.stat(path) + try { + if (stat.isDirectory()) { + await window.remixFileSystem.unlink((await this.getGitConfig(module.path)).dir) + } + } catch (e) { + } + } + } + + if (refresh) setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) - } + this.emit('checkout') } @@ -150,19 +172,19 @@ class DGitProvider extends Plugin { } async currentbranch (config) { - try{ + try { const defaultConfig = await this.getGitConfig() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const name = await git.currentBranch(cmd) return name - }catch(e){ + } catch (e) { return '' } } async branches (config) { - try{ + try { const defaultConfig = await this.getGitConfig() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const remotes = await this.remotes(config) @@ -174,7 +196,7 @@ class DGitProvider extends Plugin { branches = [...branches, ...remotebranches] } return branches - }catch(e){ + } catch (e) { return [] } } @@ -261,6 +283,7 @@ class DGitProvider extends Plugin { } const result = await git.clone(cmd) + await this.updateSubmodules(input) if (!workspaceExists) { setTimeout(async () => { await this.call('fileManager', 'refresh') @@ -270,7 +293,80 @@ class DGitProvider extends Plugin { return result } - async push (input) { + async parseGitmodules () { + try { + const gitmodules = await this.call('fileManager', 'readFile', '.gitmodules') + if (gitmodules) { + const lines = gitmodules.split('\n') + let currentModule = {} + let modules = [] + for (let line of lines) { + line = line.trim() + if (line.startsWith('[')) { + if (currentModule.path) { + modules.push(currentModule) + } + currentModule = {} + currentModule.name = line.replace('[submodule "', '').replace('"]', '') + } else if (line.startsWith('url')) { + currentModule.url = line.replace('url = ', '') + } else if (line.startsWith('path')) { + currentModule.path = line.replace('path = ', '') + } + } + if (currentModule.path) { + modules.push(currentModule) + } + return modules + } + } catch (e) { + // do nothing + } + } + + async updateSubmodules(input) { + try { + const gitmodules = await this.parseGitmodules() + //parse gitmodules + if (gitmodules) { + for (let module of gitmodules) { + const path = (await this.getGitConfig(module.path)).dir + if (await window.remixFileSystem.exists(path)) { + const stat = await window.remixFileSystem.stat(path) + try { + if (stat.isDirectory()) { + await window.remixFileSystem.unlink((await this.getGitConfig(module.path)).dir) + } + } catch (e) { + } + } + } + for (let module of gitmodules) { + try { + const cmd = { + url: module.url, + singleBranch: true, + depth: 1, + ...await this.parseInput(input), + ...await this.getGitConfig(module.path) + } + await git.clone(cmd) + } catch (e) { + console.log(e) + + } + } + setTimeout(async () => { + await this.call('fileManager', 'refresh') + }, 1000) + } + } catch (e) { + console.log(e) + // do nothing + } + } + + async push(input) { const cmd = { force: input.force, ref: input.ref, diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index 154e571bb0..9b80a5fcf7 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -25,7 +25,7 @@ const profile = { methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', - 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory' + 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule' ], kind: 'file-system' } @@ -919,6 +919,13 @@ class FileManager extends Plugin { return exists } + async hasGitSubmodules(): Promise { + const path = '.gitmodules' + const exists = await this.exists(path) + + return exists + } + async moveFileIsAllowed (src: string, dest: string) { try { diff --git a/libs/remix-ui/workspace/src/lib/actions/payload.ts b/libs/remix-ui/workspace/src/lib/actions/payload.ts index 6f5d5793cb..e023c4eaf7 100644 --- a/libs/remix-ui/workspace/src/lib/actions/payload.ts +++ b/libs/remix-ui/workspace/src/lib/actions/payload.ts @@ -294,6 +294,13 @@ export const setCurrentWorkspaceIsGitRepo = (isRepo: boolean): Action<'SET_CURRE } } +export const setCurrentWorkspaceHasGitSubmodules = (hasGitSubmodules: boolean): Action<'SET_CURRENT_WORKSPACE_HAS_GIT_SUBMODULES'> => { + return { + type: 'SET_CURRENT_WORKSPACE_HAS_GIT_SUBMODULES', + payload: hasGitSubmodules + } +} + export const setGitConfig = (config: {username: string, token: string, email: string}): Action<'SET_GIT_CONFIG'> => { return { type: 'SET_GIT_CONFIG', diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index c4818c8d90..1bfcc59376 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -25,6 +25,7 @@ import { setRenameWorkspace, setCurrentWorkspaceIsGitRepo, setGitConfig, + setCurrentWorkspaceHasGitSubmodules, } from './payload' import { addSlash, checkSlash, checkSpecialChars } from '@remix-ui/helper' @@ -423,7 +424,7 @@ export const switchToWorkspace = async (name: string) => { await plugin.fileProviders.workspace.setWorkspace(name) await plugin.setWorkspace({ name, isLocalhost: false }) const isGitRepo = await plugin.fileManager.isGitRepo() - + const hasGitSubmodule = await plugin.fileManager.hasGitSubmodules() if (isGitRepo) { const isActive = await plugin.call('manager', 'isActive', 'dgit') if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit') @@ -513,9 +514,9 @@ export const uploadFolder = async (target, targetFolder: string, cb?: (err: Erro } } -export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolean; branches?: { remote: any; name: string }[]; currentBranch?: string }[]> | undefined => { +export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolean; hasGitSubmodules: boolean; branches?: { remote: any; name: string }[]; currentBranch?: string }[]> | undefined => { try { - const workspaces: { name: string; isGitRepo: boolean; branches?: { remote: any; name: string }[]; currentBranch?: string }[] = await new Promise((resolve, reject) => { + const workspaces: { name: string; isGitRepo: boolean; hasGitSubmodules: boolean; branches?: { remote: any; name: string }[]; currentBranch?: string }[] = await new Promise((resolve, reject) => { const workspacesPath = plugin.fileProviders.workspace.workspacesPath plugin.fileProviders.browser.resolveDirectory('/' + workspacesPath, (error, items) => { @@ -527,7 +528,7 @@ export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolea .filter((item) => items[item].isDirectory) .map(async (folder) => { const isGitRepo: boolean = await plugin.fileProviders.browser.exists('/' + folder + '/.git') - + const hasGitSubmodules: boolean = await plugin.fileProviders.browser.exists('/' + folder + '/.gitmodules') if (isGitRepo) { let branches = [] let currentBranch = null @@ -539,11 +540,13 @@ export const getWorkspaces = async (): Promise<{ name: string; isGitRepo: boolea isGitRepo, branches, currentBranch, + hasGitSubmodules } } else { return { name: folder.replace(workspacesPath + '/', ''), isGitRepo, + hasGitSubmodules } } }) @@ -608,7 +611,9 @@ export const cloneRepository = async (url: string) => { export const checkGit = async () => { const isGitRepo = await plugin.fileManager.isGitRepo() + const hasGitSubmodule = await plugin.fileManager.hasGitSubmodules() dispatch(setCurrentWorkspaceIsGitRepo(isGitRepo)) + dispatch(setCurrentWorkspaceHasGitSubmodules(hasGitSubmodule)) await refreshBranches() const currentBranch = await plugin.call('dGitProvider', 'currentbranch') dispatch(setCurrentWorkspaceCurrentBranch(currentBranch)) @@ -773,6 +778,12 @@ export const createHelperScripts = async (script: string) => { plugin.call('notification', 'toast', 'scripts added in the "scripts" folder') } +export const updateGitSubmodules = async () => { + dispatch(cloneRepositoryRequest()) + await plugin.call('dGitProvider', 'updateSubmodules') + dispatch(cloneRepositorySuccess()) +} + export const checkoutRemoteBranch = async (branch: string, remote: string) => { const localChanges = await hasLocalChanges() diff --git a/libs/remix-ui/workspace/src/lib/contexts/index.ts b/libs/remix-ui/workspace/src/lib/contexts/index.ts index d0b578d85e..23337569a6 100644 --- a/libs/remix-ui/workspace/src/lib/contexts/index.ts +++ b/libs/remix-ui/workspace/src/lib/contexts/index.ts @@ -46,6 +46,7 @@ export const FileSystemContext = createContext<{ dispatchCreateTsSolGithubAction: () => Promise, dispatchCreateSlitherGithubAction: () => Promise dispatchCreateHelperScripts: (script: string) => Promise + dispatchUpdateGitSubmodules: () => Promise }>(null) \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx index 13adb71235..0ddbe42ac9 100644 --- a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx +++ b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx @@ -45,7 +45,8 @@ import { createSolidityGithubAction, createTsSolGithubAction, createSlitherGithubAction, - createHelperScripts + createHelperScripts, + updateGitSubmodules } from '../actions' import {Modal, WorkspaceProps, WorkspaceTemplate} from '../types' // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -224,6 +225,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await createHelperScripts(script) } + const dispatchUpdateGitSubmodules = async () => { + await updateGitSubmodules() + } + useEffect(() => { dispatchInitWorkspace() }, []) @@ -341,7 +346,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => { dispatchCreateSolidityGithubAction, dispatchCreateTsSolGithubAction, dispatchCreateSlitherGithubAction, - dispatchCreateHelperScripts + dispatchCreateHelperScripts, + dispatchUpdateGitSubmodules } return ( diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index adec39d281..93a0a34069 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -9,6 +9,7 @@ export interface BrowserState { workspaces: { name: string isGitRepo: boolean + hasGitSubmodules?: boolean branches?: { remote: any name: string @@ -807,6 +808,22 @@ export const browserReducer = (state = browserInitialState, action: Actions) => } } + case 'SET_CURRENT_WORKSPACE_HAS_GIT_SUBMODULES': { + const payload = action.payload + + return { + ...state, + browser: { + ...state.browser, + workspaces: state.browser.workspaces.map((workspace) => { + if (workspace.name === state.browser.currentWorkspace) + workspace.hasGitSubmodules = payload + return workspace + }) + } + } + } + case 'SET_GIT_CONFIG': { const payload = action.payload diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 236f0be705..058238eba2 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -24,6 +24,7 @@ export function Workspace() { const [selectedWorkspace, setSelectedWorkspace] = useState<{ name: string isGitRepo: boolean + hasGitSubmodules?: boolean branches?: {remote: any; name: string}[] currentBranch?: string }>(null) @@ -139,7 +140,6 @@ export function Workspace() { useEffect(() => { const workspace = global.fs.browser.workspaces.find((workspace) => workspace.name === currentWorkspace) - setSelectedWorkspace(workspace) }, [currentWorkspace]) @@ -649,6 +649,14 @@ export function Workspace() { setShowBranches(isOpen) } + const updateSubModules = async () => { + try { + await global.dispatchUpdateGitSubmodules() + } catch (e) { + console.error(e) + } + } + const handleBranchFilterChange = (e: ChangeEvent) => { const branchFilter = e.target.value @@ -1122,6 +1130,12 @@ export function Workspace() {
GIT
+ {selectedWorkspace.hasGitSubmodules? +
+ {global.fs.browser.isRequestingCloning ?
updating submodules
: +
update submodules
} +
+ : null}