Skip to content

Commit 9152b01

Browse files
authored
Move VS Code test isolates to the user cache (#14646)
* Move VS Code test isolates to user cache * Validate VS Code test root override * Validate platform cache environment paths * Require fully qualified Windows cache paths
1 parent b02a2f8 commit 9152b01

4 files changed

Lines changed: 177 additions & 9 deletions

File tree

Extension/.scripts/vscode.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
* ------------------------------------------------------------------------------------------ */
55

66
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath } from '@vscode/test-electron';
7-
import { createHash } from 'crypto';
8-
import { tmpdir } from 'os';
97
import { resolve } from 'path';
108
import { verbose } from '../src/Utility/Text/streams';
119
import { mkdir, readJson, rimraf, write } from './common';
10+
import { getVSCodeTestIsolate } from './vscodeTestPath';
1211

13-
export const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(__dirname).digest('hex').substring(0, 6));
12+
export const isolated = getVSCodeTestIsolate(__dirname);
1413
export const extensionsDir = resolve(isolated, 'extensions');
1514
export const userDir = resolve(isolated, 'user-data');
1615
export const settings = resolve(userDir, "User", 'settings.json');
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All Rights Reserved.
3+
* See 'LICENSE' in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
6+
import { createHash } from 'crypto';
7+
import { homedir } from 'os';
8+
import { posix, win32 } from 'path';
9+
10+
function isFullyQualifiedPath(value: string, platform: NodeJS.Platform): boolean {
11+
const path = platform === 'win32' ? win32 : posix;
12+
return path.isAbsolute(value) && (platform !== 'win32' || path.parse(value).root.length > 1);
13+
}
14+
15+
export function getVSCodeTestIsolate(
16+
scriptDirectory: string,
17+
platform: NodeJS.Platform = process.platform,
18+
environment: NodeJS.ProcessEnv = process.env,
19+
homeDirectory: string = homedir()): string {
20+
const path = platform === 'win32' ? win32 : posix;
21+
const override = environment.CPPTOOLS_VSCODE_TEST_ROOT;
22+
let root: string;
23+
24+
if (override) {
25+
if (!isFullyQualifiedPath(override, platform)) {
26+
throw new Error('CPPTOOLS_VSCODE_TEST_ROOT must be a fully qualified absolute path.');
27+
}
28+
root = override;
29+
} else {
30+
switch (platform) {
31+
case 'win32': {
32+
const localAppData = environment.LOCALAPPDATA;
33+
const cacheDirectory = localAppData && isFullyQualifiedPath(localAppData, platform) ? localAppData : path.resolve(homeDirectory, 'AppData', 'Local');
34+
root = path.resolve(cacheDirectory, 'Microsoft', 'vscode-cpptools', 'vscode-test');
35+
break;
36+
}
37+
case 'darwin':
38+
root = path.resolve(homeDirectory, 'Library', 'Caches', 'vscode-cpptools', 'vscode-test');
39+
break;
40+
default: {
41+
const xdgCacheHome = environment.XDG_CACHE_HOME;
42+
const cacheDirectory = xdgCacheHome && isFullyQualifiedPath(xdgCacheHome, platform) ? xdgCacheHome : path.resolve(homeDirectory, '.cache');
43+
root = path.resolve(cacheDirectory, 'vscode-cpptools', 'vscode-test');
44+
break;
45+
}
46+
}
47+
}
48+
49+
const worktreeHash = createHash('sha256').update(scriptDirectory).digest('hex').substring(0, 6);
50+
return path.resolve(root, worktreeHash);
51+
}

Extension/readme.developer.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,33 @@ The scripts for this repository now support running VS Code and the extension in
8181
completely isolated environment (separate install of VS Code, private extensions and
8282
user folders, etc).
8383

84-
The scripts that install VS Code place it in a `$ENV:TMP/.vscode-test/<UID>` folder where
85-
`<UID>` is a has calculated from the extension folder (this permits multiple checkouts of
86-
the source repository and each gets it's own isolated environment).
84+
The scripts that install VS Code retain it in a per-user cache directory:
85+
86+
* Windows: `%LOCALAPPDATA%\Microsoft\vscode-cpptools\vscode-test\<UID>` (or
87+
`%USERPROFILE%\AppData\Local\Microsoft\vscode-cpptools\vscode-test\<UID>` if `%LOCALAPPDATA%` is unavailable)
88+
* macOS: `~/Library/Caches/vscode-cpptools/vscode-test/<UID>`
89+
* Linux: `${XDG_CACHE_HOME:-~/.cache}/vscode-cpptools/vscode-test/<UID>`
90+
91+
The environment-based cache locations are used only when they are fully qualified. On Windows,
92+
they must include a drive or UNC share. Unsupported values fall back to the per-user locations shown above.
93+
94+
`<UID>` is a six-character hash calculated from the checkout's `.scripts` directory path. This permits multiple
95+
checkouts of the source repository, with each checkout retaining its own isolated `cache`,
96+
`extensions`, and `user-data` folders across runs. Set `CPPTOOLS_VSCODE_TEST_ROOT` to a fully qualified
97+
absolute directory to override the platform-specific `vscode-test` root. The same Windows drive or UNC
98+
share requirement applies. The checkout-specific `<UID>` is still appended to the override.
8799

88100
The [`test scripts`](#yarn-test) will automatically install and use this isolated environment.
89101

90102
You can invoke VS Code from the command line using the [`yarn code`](#yarn-code) script.
91103

92-
If you want to remove the isolate environment use the `yarn code reset` or `yarn test reset` scripts
93-
to delete the folders and remove all of the configuration files. Next time you use the `yarn test` or
94-
`yarn code` commands, it will reinstall a fresh isolated environment.
104+
If you want to remove the isolated environment use the `yarn code reset` or `yarn test reset` scripts
105+
to delete only the current checkout's hashed folder and remove all of its configuration files. Next
106+
time you use the `yarn test` or `yarn code` commands, it will reinstall a fresh isolated environment.
107+
108+
Isolates created by earlier versions under the system temporary directory are not migrated or
109+
removed automatically. After ensuring that no test runs are using them, you can remove the old
110+
`.vscode-test` folder from the system temporary directory once to reclaim that space.
95111

96112
The Isolated environment has the theme automatically set to blue so that it is visually distinct from
97113
your normal VS Code environment.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All Rights Reserved.
3+
* See 'LICENSE' in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
6+
import * as assert from 'assert';
7+
import { createHash } from 'crypto';
8+
import { describe, it } from 'mocha';
9+
import { posix, win32 } from 'path';
10+
import { getVSCodeTestIsolate } from '../../.scripts/vscodeTestPath';
11+
12+
const posixScriptDirectory = '/worktrees/agent/Extension/.scripts';
13+
const windowsScriptDirectory = 'C:\\worktrees\\agent\\Extension\\.scripts';
14+
15+
function getWorktreeHash(scriptDirectory: string): string {
16+
return createHash('sha256').update(scriptDirectory).digest('hex').substring(0, 6);
17+
}
18+
19+
describe('VS Code test isolate path', () => {
20+
it('uses XDG_CACHE_HOME on Linux', () => {
21+
assert.strictEqual(
22+
getVSCodeTestIsolate(posixScriptDirectory, 'linux', { XDG_CACHE_HOME: '/cache' }, '/home/developer'),
23+
posix.resolve('/cache', 'vscode-cpptools', 'vscode-test', getWorktreeHash(posixScriptDirectory)));
24+
});
25+
26+
it('falls back to the user cache directory on Linux', () => {
27+
const expected = posix.resolve('/home/developer', '.cache', 'vscode-cpptools', 'vscode-test', getWorktreeHash(posixScriptDirectory));
28+
29+
assert.strictEqual(
30+
getVSCodeTestIsolate(posixScriptDirectory, 'linux', {}, '/home/developer'),
31+
expected);
32+
assert.strictEqual(
33+
getVSCodeTestIsolate(posixScriptDirectory, 'linux', { XDG_CACHE_HOME: 'relative-cache' }, '/home/developer'),
34+
expected);
35+
});
36+
37+
it('uses the user cache directory on macOS', () => {
38+
assert.strictEqual(
39+
getVSCodeTestIsolate(posixScriptDirectory, 'darwin', {}, '/Users/developer'),
40+
posix.resolve('/Users/developer', 'Library', 'Caches', 'vscode-cpptools', 'vscode-test', getWorktreeHash(posixScriptDirectory)));
41+
});
42+
43+
it('uses LOCALAPPDATA on Windows', () => {
44+
assert.strictEqual(
45+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { LOCALAPPDATA: 'D:\\LocalAppData' }, 'C:\\Users\\developer'),
46+
win32.resolve('D:\\LocalAppData', 'Microsoft', 'vscode-cpptools', 'vscode-test', getWorktreeHash(windowsScriptDirectory)));
47+
});
48+
49+
it('falls back to the user profile on Windows', () => {
50+
const expected = win32.resolve('C:\\Users\\developer', 'AppData', 'Local', 'Microsoft', 'vscode-cpptools', 'vscode-test', getWorktreeHash(windowsScriptDirectory));
51+
52+
assert.strictEqual(
53+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', {}, 'C:\\Users\\developer'),
54+
expected);
55+
assert.strictEqual(
56+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { LOCALAPPDATA: 'relative-cache' }, 'C:\\Users\\developer'),
57+
expected);
58+
assert.strictEqual(
59+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { LOCALAPPDATA: '\\relative-cache' }, 'C:\\Users\\developer'),
60+
expected);
61+
});
62+
63+
it('honors CPPTOOLS_VSCODE_TEST_ROOT without sharing worktree isolates', () => {
64+
const environment = { CPPTOOLS_VSCODE_TEST_ROOT: '/test-root', XDG_CACHE_HOME: '/cache' };
65+
const first = getVSCodeTestIsolate('/worktrees/first/Extension/.scripts', 'linux', environment, '/home/developer');
66+
const firstAgain = getVSCodeTestIsolate('/worktrees/first/Extension/.scripts', 'linux', environment, '/home/developer');
67+
const second = getVSCodeTestIsolate('/worktrees/second/Extension/.scripts', 'linux', environment, '/home/developer');
68+
69+
assert.strictEqual(first, firstAgain);
70+
assert.match(posix.basename(first), /^[0-9a-f]{6}$/);
71+
assert.notStrictEqual(first, second);
72+
assert.strictEqual(posix.dirname(first), '/test-root');
73+
assert.strictEqual(posix.dirname(second), '/test-root');
74+
});
75+
76+
it('accepts fully qualified Windows CPPTOOLS_VSCODE_TEST_ROOT values', () => {
77+
const driveRoot = 'D:\\test-root';
78+
const uncRoot = '\\\\server\\share\\test-root';
79+
80+
assert.strictEqual(
81+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { CPPTOOLS_VSCODE_TEST_ROOT: driveRoot }, 'C:\\Users\\developer'),
82+
win32.resolve(driveRoot, getWorktreeHash(windowsScriptDirectory)));
83+
assert.strictEqual(
84+
getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { CPPTOOLS_VSCODE_TEST_ROOT: uncRoot }, 'C:\\Users\\developer'),
85+
win32.resolve(uncRoot, getWorktreeHash(windowsScriptDirectory)));
86+
});
87+
88+
it('rejects non-fully-qualified CPPTOOLS_VSCODE_TEST_ROOT values', () => {
89+
assert.throws(
90+
() => getVSCodeTestIsolate(posixScriptDirectory, 'linux', { CPPTOOLS_VSCODE_TEST_ROOT: 'test-root' }, '/home/developer'),
91+
/CPPTOOLS_VSCODE_TEST_ROOT must be a fully qualified absolute path/);
92+
assert.throws(
93+
() => getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { CPPTOOLS_VSCODE_TEST_ROOT: 'C:' }, 'C:\\Users\\developer'),
94+
/CPPTOOLS_VSCODE_TEST_ROOT must be a fully qualified absolute path/);
95+
assert.throws(
96+
() => getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { CPPTOOLS_VSCODE_TEST_ROOT: '\\test-root' }, 'C:\\Users\\developer'),
97+
/CPPTOOLS_VSCODE_TEST_ROOT must be a fully qualified absolute path/);
98+
assert.throws(
99+
() => getVSCodeTestIsolate(windowsScriptDirectory, 'win32', { CPPTOOLS_VSCODE_TEST_ROOT: '/test-root' }, 'C:\\Users\\developer'),
100+
/CPPTOOLS_VSCODE_TEST_ROOT must be a fully qualified absolute path/);
101+
});
102+
});

0 commit comments

Comments
 (0)