Skip to content

Commit b71ccf3

Browse files
committed
Handle rewriting of submodule cloner's out-of-tree clone (hand-wavingly)
1 parent b8acdfa commit b71ccf3

7 files changed

Lines changed: 67 additions & 7 deletions

File tree

commands.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fetchServerRefInfo, gitClone, RefEntry } from '$gitops'
1+
import { fetchServerRefInfo, gitClone, maybeRewriteGitSubmodulePath, RefEntry } from '$gitops'
22
import {
33
type ExtensionContext,
44
FileType,
@@ -149,6 +149,8 @@ async function pickAndInstallFromLibraryCatalog(context: ExtensionContext) {
149149

150150
qp.busy = false
151151
qp.items = [...tags, ...branches]
152+
// the user might be interrupted to install the missing the extension dependency
153+
qp.show()
152154

153155
const def = tags.find(it => it.label === libPicked.descriptor.defaultRef)
154156
if (def) qp.activeItems = [def]
@@ -318,11 +320,11 @@ async function _listInstalledLibraries(context: ExtensionContext) {
318320
}
319321
}
320322

321-
export async function listConfiguredLibraries(): Promise<ConfiguredLibraryEntry[]> {
323+
function probeLibraryConfig() {
322324
const CONFIG_SECTION = 'alsWasmLoader'
323325
const CONFIG_KEY = 'libraryFilePaths'
324326

325-
const configsFound: ConfiguredLibraryEntry[] = []
327+
const configsFound: (ConfiguredLibraryEntry & { base: string, prefix?: Uri })[] = []
326328

327329
const unscopedConfig = workspace.getConfiguration(CONFIG_SECTION)
328330
const unscopedConfigSources = unscopedConfig.inspect<string[]>(CONFIG_KEY)
@@ -347,6 +349,7 @@ export async function listConfiguredLibraries(): Promise<ConfiguredLibraryEntry[
347349
configsFound.push({
348350
source: 'workspace',
349351
base: '/workspace',
352+
prefix: folders[0].uri,
350353
paths: wsPaths,
351354
})
352355
}
@@ -367,6 +370,7 @@ export async function listConfiguredLibraries(): Promise<ConfiguredLibraryEntry[
367370
configsFound.push({
368371
source: 'workspaceFolder',
369372
base: `/workspaces/${wsf.name}`,
373+
prefix: wsf.uri,
370374
paths: wsfPaths,
371375
})
372376
}
@@ -382,6 +386,24 @@ export async function listConfiguredLibraries(): Promise<ConfiguredLibraryEntry[
382386
return configsFound.reverse()
383387
}
384388

389+
export async function listConfiguredLibraries(): Promise<ConfiguredLibraryEntry[]> {
390+
391+
async function resolvePath(p: string, base: string, prefix: Uri | undefined) {
392+
const resolved = p[0] === '/' ? p : base + '/' + p
393+
if (prefix?.scheme === 'github-vfs') {
394+
return maybeRewriteGitSubmodulePath(resolved, prefix)
395+
}
396+
return resolved
397+
}
398+
399+
function mapAsync<A, B>(arr: A[], mapper: (a: A) => Promise<B>): Promise<B[]> {
400+
return Promise.all(arr.map(mapper))
401+
}
402+
403+
return mapAsync(probeLibraryConfig(), async ({source, base, prefix, paths}) => (
404+
{ source, paths: await mapAsync(paths, p => resolvePath(p, base, prefix)) }))
405+
}
406+
385407
async function _manageLibraries(context: ExtensionContext, ..._args: any[]) {
386408
let showInvalid = false
387409
let items: InstalledLibraryQuickPickItem[] = []

extension.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ export async function activate(context: ExtensionContext): Promise<ALSWasmLoader
121121
)
122122
}
123123

124+
const submodClonerStorageUri = Uri.joinPath(context.globalStorageUri, '../qbane.vscode-git-submodule-cloner')
125+
if (await workspace.fs.stat(submodClonerStorageUri)) {
126+
presetMountPoints.push(
127+
{ kind: 'vscodeFileSystem', uri: submodClonerStorageUri, mountPoint: '/submodules' }
128+
)
129+
}
130+
124131
await options.presetupCallback?.({ memfsTempDir, memfsHome })
125132
}
126133

gitops/lib-common.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ interface GitCloneOptions {
1818

1919
export function fetchServerRefInfo(url: string): Promise<ServerRefInfo>
2020
export function gitClone(url: string, dest: Uri, ref?: string, options?: GitCloneOptions): Promise<void>
21+
export function maybeRewriteGitSubmodulePath(path: string, wsuri: Uri): Promise<string>
2122

2223
type LibAPI = {
2324
fetchServerRefInfo: typeof fetchServerRefInfo,
2425
gitClone: typeof gitClone,
26+
maybeRewriteGitSubmodulePath: typeof maybeRewriteGitSubmodulePath,
2527
}

gitops/lib-desktop.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,12 @@ export async function gitClone(url: string, dest: Uri, ref?: string, options?: G
103103
await commands.executeCommand('git.close', dest)
104104
}
105105

106+
function maybeRewriteGitSubmodulePath(): never {
107+
throw new Error('Not supported on desktop version')
108+
}
109+
106110
;({
107111
fetchServerRefInfo,
108112
gitClone,
113+
maybeRewriteGitSubmodulePath,
109114
} satisfies LibAPI)

gitops/lib-web.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { commands, extensions, Uri, window } from 'vscode'
1+
import { commands, env, extensions, UIKind, Uri, window } from 'vscode'
22
import type { LibAPI, ServerRefInfo, GitCloneOptions } from '$gitops'
33

4+
type GitSubmoduleClonerAPI = LibAPI & {
5+
getWorkspaceId(uri: Uri): string
6+
listSubmodules(uri: Uri): { name: string, path: string, url: string }[]
7+
}
48

59
async function ensureExtensionCommon(extensionID: string, extensionName: string = extensionID) {
610
const openExtensionPage = () => commands.executeCommand('extension.open', `${extensionID}`)
711

812
do {
9-
const ext = extensions.getExtension<LibAPI>(extensionID)
13+
const ext = extensions.getExtension<GitSubmoduleClonerAPI>(extensionID)
1014
if (ext != null) {
1115
if (!ext.isActive) {
1216
await ext.activate()
@@ -77,7 +81,26 @@ export async function gitClone(url: string, dest: Uri, ref?: string, options?: G
7781
return gitCloner.gitClone(url, dest, ref, options)
7882
}
7983

84+
async function maybeRewriteGitSubmodulePath(path: string, wsuri: Uri) {
85+
if (env.uiKind !== UIKind.Web) {
86+
// bail out rather than return path silently
87+
throw new Error('can only rewrite submodule URI on web')
88+
}
89+
const gitCloner = await ensureExtension()
90+
const submodules = gitCloner.listSubmodules(wsuri)
91+
92+
for (let {name, path: submodPath} of submodules) {
93+
const prefix = '/workspace/' + submodPath + '/'
94+
if (path.startsWith(prefix)) {
95+
return `/submodules/${gitCloner.getWorkspaceId(wsuri)}/${name}/` + path.slice(prefix.length)
96+
}
97+
}
98+
99+
return path
100+
}
101+
80102
;({
81103
fetchServerRefInfo,
82104
gitClone,
105+
maybeRewriteGitSubmodulePath,
83106
} satisfies LibAPI)

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@
6565
"properties": {
6666
"alsWasmLoader.libraryFilePaths": {
6767
"type": "array",
68-
"items": { "type": "string" },
68+
"items": {
69+
"type": "string"
70+
},
6971
"default": [],
7072
"scope": "resource",
7173
"markdownDescription": "Paths to [library files](https://agda.readthedocs.io/en/latest/tools/package-system.html#library-files) to be loaded by ALS-WASM inside its VFS. Each member will be inserted as a line after resolution in the `libraries` file.\n\nA path *not* beginning with `/` is interpreted as a relative path, resolved according to the scope it is defined. In user settings it is resolved against `/`, while in workspace (when single-rooted) or workspace-folder (when multi-rooted) settings, relative paths are resolved against the corresponding workspace folder.\n\nNote that the lists from all scopes will be combined per window."

types.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ interface LibraryEntry {
8989

9090
export interface ConfiguredLibraryEntry {
9191
source: 'global' | 'workspace' | 'workspaceFolder'
92-
base: string
9392
paths: string[]
9493
}
9594

0 commit comments

Comments
 (0)