Use lockfile when downloading CodeQL distribution
This commit is contained in:
45
extensions/ql-vscode/package-lock.json
generated
45
extensions/ql-vscode/package-lock.json
generated
@@ -28,6 +28,7 @@
|
||||
"msw": "^2.2.13",
|
||||
"nanoid": "^5.0.7",
|
||||
"p-queue": "^8.0.1",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"semver": "^7.6.2",
|
||||
@@ -82,6 +83,7 @@
|
||||
"@types/js-yaml": "^4.0.6",
|
||||
"@types/nanoid": "^3.0.0",
|
||||
"@types/node": "20.16.*",
|
||||
"@types/proper-lockfile": "^4.1.4",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/sarif": "^2.1.2",
|
||||
@@ -6267,6 +6269,16 @@
|
||||
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/proper-lockfile": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/proper-lockfile/-/proper-lockfile-4.1.4.tgz",
|
||||
"integrity": "sha512-uo2ABllncSqg9F1D4nugVl9v93RmjxF6LJzQLMLDdPaXCUIDPeOJ21Gbqi43xNKzBi/WQ0Q0dICqufzQbMjipQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/retry": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
|
||||
@@ -6304,6 +6316,13 @@
|
||||
"integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/retry": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz",
|
||||
"integrity": "sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/sarif": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz",
|
||||
@@ -19752,6 +19771,23 @@
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/proper-lockfile": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
|
||||
"integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"retry": "^0.12.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/proper-lockfile/node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -20575,6 +20611,15 @@
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
|
||||
@@ -1986,6 +1986,7 @@
|
||||
"msw": "^2.2.13",
|
||||
"nanoid": "^5.0.7",
|
||||
"p-queue": "^8.0.1",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"semver": "^7.6.2",
|
||||
@@ -2040,6 +2041,7 @@
|
||||
"@types/js-yaml": "^4.0.6",
|
||||
"@types/nanoid": "^3.0.0",
|
||||
"@types/node": "20.16.*",
|
||||
"@types/proper-lockfile": "^4.1.4",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/sarif": "^2.1.2",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { WriteStream } from "fs";
|
||||
import { createWriteStream, mkdtemp, pathExists, remove } from "fs-extra";
|
||||
import {
|
||||
createWriteStream,
|
||||
mkdtemp,
|
||||
pathExists,
|
||||
remove,
|
||||
writeJson,
|
||||
} from "fs-extra";
|
||||
import { tmpdir } from "os";
|
||||
import { delimiter, dirname, join } from "path";
|
||||
import { Range, satisfies } from "semver";
|
||||
@@ -28,6 +34,7 @@ import { reportUnzipProgress } from "../common/vscode/unzip-progress";
|
||||
import type { Release } from "./distribution/release";
|
||||
import { ReleasesApiConsumer } from "./distribution/releases-api-consumer";
|
||||
import { createTimeoutSignal } from "../common/fetch-stream";
|
||||
import { withDistributionUpdateLock } from "./lock";
|
||||
|
||||
/**
|
||||
* distribution.ts
|
||||
@@ -350,9 +357,24 @@ class ExtensionSpecificDistributionManager {
|
||||
release: Release,
|
||||
progressCallback?: ProgressCallback,
|
||||
): Promise<void> {
|
||||
await this.downloadDistribution(release, progressCallback);
|
||||
// Store the installed release within the global extension state.
|
||||
await this.storeInstalledRelease(release);
|
||||
const distributionStatePath = join(
|
||||
this.extensionContext.globalStorageUri.fsPath,
|
||||
ExtensionSpecificDistributionManager._distributionStateFilename,
|
||||
);
|
||||
if (!(await pathExists(distributionStatePath))) {
|
||||
// This may result in a race condition, but when this happens both processes should write the same file.
|
||||
await writeJson(distributionStatePath, {});
|
||||
}
|
||||
|
||||
await withDistributionUpdateLock(
|
||||
// .lock will be appended to this filename
|
||||
distributionStatePath,
|
||||
async () => {
|
||||
await this.downloadDistribution(release, progressCallback);
|
||||
// Store the installed release within the global extension state.
|
||||
await this.storeInstalledRelease(release);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private async downloadDistribution(
|
||||
@@ -615,6 +637,7 @@ class ExtensionSpecificDistributionManager {
|
||||
"distributionFolderIndex";
|
||||
private static readonly _installedReleaseStateKey = "distributionRelease";
|
||||
private static readonly _codeQlExtractedFolderName = "codeql";
|
||||
private static readonly _distributionStateFilename = "distribution.json";
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
22
extensions/ql-vscode/src/codeql-cli/lock.ts
Normal file
22
extensions/ql-vscode/src/codeql-cli/lock.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { lock } from "proper-lockfile";
|
||||
|
||||
export async function withDistributionUpdateLock(
|
||||
lockFile: string,
|
||||
f: () => Promise<void>,
|
||||
) {
|
||||
const release = await lock(lockFile, {
|
||||
stale: 60_000, // 1 minute. We can take the lock longer than this because that's based on the update interval.
|
||||
update: 10_000, // 10 seconds
|
||||
retries: {
|
||||
minTimeout: 10_000,
|
||||
maxTimeout: 60_000,
|
||||
retries: 100,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await f();
|
||||
} finally {
|
||||
await release();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user