Skip to content

Commit 6c99ca6

Browse files
authored
fix: offer update options for all dependencies in manifest (#638)
This PR removes the logic from the 'Update Dependency' command that hides dependencies that are already up-to-date relative to the manifest and removes the revision information from the selection dialog. The reason for this is that the manifest is not an up-to-date representation of the set of dependencies in the `lakefile.lean` or the `lakefile.toml`, e.g. if the input revision in the Lake configuration file was changed. I don't know of a way to query this information from Lake without also updating all the revisions of the manifest in the process, so we now just avoid this situation entirely by considering the revision information in the manifest to be unreliable. Note that there is still a shortcoming of this approach: When adding a new dependency to the `lakefile.lean` or the `lakefile.toml`, we won't display it in the update dialog until the manifest is updated. This came up at [#general > Updating Mathlib via VSCode menu does not work @ 💬](https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/Updating.20Mathlib.20via.20VSCode.20menu.20does.20not.20work/near/526969295).
1 parent e74069a commit 6c99ca6

File tree

3 files changed

+53
-59
lines changed

3 files changed

+53
-59
lines changed
-26.7 KB
Loading

vscode-lean4/src/projectoperations.ts

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as fs from 'fs'
22
import { join } from 'path'
33
import { commands, Disposable, OutputChannel, QuickPickItem, window } from 'vscode'
44
import { LeanClient } from './leanclient'
5-
import { batchExecute, ExecutionExitCode, ExecutionResult } from './utils/batch'
65
import { LeanClientProvider } from './utils/clientProvider'
76
import {
87
CacheGetAvailabilityResult,
@@ -226,28 +225,11 @@ export class ProjectOperationProvider implements Disposable {
226225
return
227226
}
228227

229-
const dependencies: (DirectGitDependency & { remoteRevision?: string | undefined })[] =
230-
await this.findUpdateableDependencies(manifestResult.directGitDependencies)
231-
if (dependencies.length === 0) {
232-
displayNotification('Information', 'Nothing to update - all dependencies are up-to-date.')
233-
return
234-
}
235-
236-
const items: GitDependencyQuickPickItem[] = dependencies.map(gitDep => {
237-
const shortLocalRevision: string = gitDep.revision.substring(0, 7)
238-
const shortRemoteRevision: string | undefined = gitDep.remoteRevision?.substring(0, 7)
239-
240-
const detail: string = shortRemoteRevision
241-
? `Current: ${shortLocalRevision} ⟹ New: ${shortRemoteRevision}`
242-
: `Current: ${shortLocalRevision}`
243-
244-
return {
245-
label: `${gitDep.name} @ ${gitDep.inputRevision}`,
246-
description: gitDep.uri.toString(),
247-
detail,
248-
...gitDep,
249-
}
250-
})
228+
const items: GitDependencyQuickPickItem[] = manifestResult.directGitDependencies.map(gitDep => ({
229+
label: gitDep.name,
230+
description: gitDep.uri.toString(),
231+
...gitDep,
232+
}))
251233

252234
const dependencyChoice: GitDependencyQuickPickItem | undefined = await window.showQuickPick(items, {
253235
title: 'Choose a dependency to update',
@@ -306,38 +288,6 @@ export class ProjectOperationProvider implements Disposable {
306288
})
307289
}
308290

309-
private async findUpdateableDependencies(dependencies: DirectGitDependency[]) {
310-
const augmented: (DirectGitDependency & { remoteRevision?: string | undefined })[] = []
311-
312-
for (const dependency of dependencies) {
313-
const result: ExecutionResult = await batchExecute('git', [
314-
'ls-remote',
315-
dependency.uri.toString(),
316-
dependency.inputRevision,
317-
])
318-
if (result.exitCode !== ExecutionExitCode.Success) {
319-
augmented.push(dependency)
320-
continue
321-
}
322-
323-
const matches: RegExpMatchArray | null = result.stdout.match(/^[a-z0-9]+/)
324-
if (!matches) {
325-
augmented.push(dependency)
326-
continue
327-
}
328-
329-
const remoteRevision: string = matches[0]
330-
if (dependency.revision === remoteRevision) {
331-
// Cannot be updated - filter it
332-
continue
333-
}
334-
335-
augmented.push({ remoteRevision, ...dependency })
336-
}
337-
338-
return augmented
339-
}
340-
341291
private async determineDependencyToolchain(
342292
localToolchainPath: string,
343293
dependencyToolchainPath: string,

vscode-lean4/src/utils/lake.ts

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as os from 'os'
22
import { OutputChannel } from 'vscode'
3+
import { z } from 'zod'
34
import { displayOutputError, ExecutionExitCode } from './batch'
45
import { FileUri } from './exturi'
56
import { leanRunner, ToolchainUpdateMode } from './leanCmdRunner'
@@ -15,8 +16,9 @@ export type LakeRunnerOptions = {
1516
export type LakeRunnerErrorDiagnosis =
1617
| { kind: 'WindowsFetchError'; details: string }
1718
| { kind: 'CommandNotFound'; details: string }
19+
| { kind: 'SubCommandNotFound'; details: string }
1820
export type LakeRunnerError = { kind: 'Error'; diagnosis: LakeRunnerErrorDiagnosis | undefined; output: string }
19-
export type LakeRunnerResult = { kind: 'Success' } | { kind: 'Cancelled' } | LakeRunnerError
21+
export type LakeRunnerResult = { kind: 'Success'; output: string } | { kind: 'Cancelled' } | LakeRunnerError
2022

2123
export function displayLakeRunnerError(error: LakeRunnerError, message: string) {
2224
if (error.diagnosis === undefined) {
@@ -27,7 +29,7 @@ export function displayLakeRunnerError(error: LakeRunnerError, message: string)
2729
}
2830

2931
export type FetchMathlibCacheResult =
30-
| { kind: 'Success' }
32+
| { kind: 'Success'; output: string }
3133
| { kind: 'CacheUnavailable' }
3234
| { kind: 'Cancelled' }
3335
| LakeRunnerError
@@ -38,6 +40,13 @@ export type CacheGetAvailabilityResult =
3840
| { kind: 'Cancelled' }
3941
| LakeRunnerError
4042

43+
export type QueryDepsResult =
44+
| { kind: 'Success'; deps: string[] }
45+
| { kind: 'InvalidOutput'; output: string }
46+
| { kind: 'QueryUnavailable' }
47+
| { kind: 'Cancelled' }
48+
| LakeRunnerError
49+
4150
export class LakeRunner {
4251
constructor(readonly options: LakeRunnerOptions) {}
4352

@@ -62,6 +71,35 @@ export class LakeRunner {
6271
return this.runLakeCommandWithProgress('clean', [], 'Cleaning Lean project')
6372
}
6473

74+
async queryDeps(): Promise<QueryDepsResult> {
75+
const queryResult = await this.runLakeCommandWithProgress(
76+
'query',
77+
[':deps', '--json'],
78+
'Querying project dependencies',
79+
)
80+
switch (queryResult.kind) {
81+
case 'Success':
82+
let parsedJson: any
83+
try {
84+
parsedJson = JSON.parse(queryResult.output)
85+
} catch (e) {
86+
return { kind: 'InvalidOutput', output: queryResult.output }
87+
}
88+
const r = z.array(z.string()).safeParse(parsedJson)
89+
if (!r.success) {
90+
return { kind: 'InvalidOutput', output: queryResult.output }
91+
}
92+
return { kind: 'Success', deps: r.data }
93+
case 'Cancelled':
94+
return { kind: 'Cancelled' }
95+
case 'Error':
96+
if (queryResult.diagnosis?.kind === 'SubCommandNotFound') {
97+
return { kind: 'QueryUnavailable' }
98+
}
99+
return queryResult
100+
}
101+
}
102+
65103
private async runFetchMathlibCacheCommand(args: string[], prompt: string): Promise<FetchMathlibCacheResult> {
66104
const availabilityResult = await this.isMathlibCacheGetAvailable()
67105
if (availabilityResult.kind !== 'CacheAvailable') {
@@ -73,7 +111,7 @@ export class LakeRunner {
73111
private async tryRunFetchMathlibCacheCommand(args: string[], prompt: string): Promise<LakeRunnerResult> {
74112
const fetchResult = await this.runFetchMathlibCacheCommand(args, prompt)
75113
if (fetchResult.kind === 'CacheUnavailable') {
76-
return { kind: 'Success' }
114+
return { kind: 'Success', output: '' }
77115
}
78116
return fetchResult
79117
}
@@ -143,7 +181,7 @@ export class LakeRunner {
143181
})
144182
switch (r.exitCode) {
145183
case ExecutionExitCode.Success:
146-
return { kind: 'Success' }
184+
return { kind: 'Success', output: r.stdout }
147185
case ExecutionExitCode.CannotLaunch:
148186
return {
149187
kind: 'Error',
@@ -152,6 +190,12 @@ export class LakeRunner {
152190
}
153191
case ExecutionExitCode.ExecutionError:
154192
let diagnosis: LakeRunnerErrorDiagnosis | undefined
193+
if (r.combined.includes(`error: unknown command '${subCommand}'`)) {
194+
diagnosis = {
195+
kind: 'SubCommandNotFound',
196+
details: `Lake sub-command '${subCommand}' is not available.`,
197+
}
198+
}
155199
if (
156200
os.platform() === 'win32' &&
157201
(r.combined.includes('failed to fetch GitHub release') ||

0 commit comments

Comments
 (0)