Skip to content

Commit 5bf1866

Browse files
MeAkibdgp1130
authored andcommitted
fix(@angular/cli): report the worktree-local cache in ng cache info
In a Git worktree the development server keeps its Vite cache in the worktree's own cache directory while the configured path resolves to the shared cache of the main checkout. `ng cache clean` removes both since the `getCacheConfig` localPath addition, but `ng cache info` still reports only the shared path and its size, so the cache that the development server actually writes to in that checkout is invisible. (cherry picked from commit acb3c8b)
1 parent 413c164 commit 5bf1866

2 files changed

Lines changed: 110 additions & 8 deletions

File tree

‎packages/angular/cli/src/commands/cache/info/cli.ts‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,16 @@ export class CacheInfoCommandModule extends CommandModule implements CommandModu
3030

3131
async run(): Promise<void> {
3232
const cacheConfig = getCacheConfig(this.context.workspace);
33-
const { path, environment, enabled } = cacheConfig;
33+
const { path, localPath, environment, enabled } = cacheConfig;
3434

3535
const effectiveStatus = this.effectiveEnabledStatus(cacheConfig);
36-
const sizeOnDisk = await this.getSizeOfDirectory(path);
36+
37+
// In a Git worktree, `path` is shared with the main checkout while `localPath` holds the
38+
// development server's Vite cache. Both are the same path outside of a worktree.
39+
const [sizeOnDisk, localSizeOnDisk] = await Promise.all([
40+
this.getSizeOfDirectory(path),
41+
localPath !== path ? this.getSizeOfDirectory(localPath) : undefined,
42+
]);
3743

3844
const info: { label: string; value: string }[] = [
3945
{
@@ -52,14 +58,27 @@ export class CacheInfoCommandModule extends CommandModule implements CommandModu
5258
label: 'Size on disk',
5359
value: colors.cyan(sizeOnDisk),
5460
},
55-
{
56-
label: 'Effective Status',
57-
value:
58-
(effectiveStatus ? colors.green('Enabled') : colors.red('Disabled')) +
59-
' (current machine)',
60-
},
6161
];
6262

63+
if (localSizeOnDisk !== undefined) {
64+
info.push(
65+
{
66+
label: 'Local path',
67+
value: colors.cyan(localPath),
68+
},
69+
{
70+
label: 'Local size on disk',
71+
value: colors.cyan(localSizeOnDisk),
72+
},
73+
);
74+
}
75+
76+
info.push({
77+
label: 'Effective Status',
78+
value:
79+
(effectiveStatus ? colors.green('Enabled') : colors.red('Disabled')) + ' (current machine)',
80+
});
81+
6382
const maxLabelLength = Math.max(...info.map((l) => l.label.length));
6483

6584
const output = info
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import type { workspaces } from '@angular-devkit/core';
10+
import assert from 'node:assert';
11+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
12+
import { join } from 'node:path';
13+
import type { CommandContext } from '../../../command-builder/command-module';
14+
import type { AngularWorkspace } from '../../../utilities/config';
15+
import { CacheInfoCommandModule } from './cli';
16+
17+
describe('CacheInfoCommandModule', () => {
18+
let tempDir: string;
19+
20+
beforeEach(async () => {
21+
const baseTmpDir = process.env['TEST_TMPDIR'];
22+
assert(baseTmpDir, 'TEST_TMPDIR is not set');
23+
tempDir = await mkdtemp(join(baseTmpDir, 'angular-cli-cache-info-spec-'));
24+
});
25+
26+
afterEach(async () => {
27+
await rm(tempDir, { recursive: true, force: true });
28+
});
29+
30+
async function runInfo(basePath: string): Promise<string> {
31+
const workspace = {
32+
basePath,
33+
extensions: {},
34+
projects: {} as unknown as workspaces.ProjectDefinitionCollection,
35+
filePath: join(basePath, 'angular.json'),
36+
getCli: () => undefined,
37+
getProjectCli: () => undefined,
38+
save: () => Promise.resolve(),
39+
} as unknown as AngularWorkspace;
40+
41+
const logs: string[] = [];
42+
const logger = { info: (message: string) => void logs.push(message) };
43+
44+
await new CacheInfoCommandModule({ workspace, logger } as unknown as CommandContext).run();
45+
46+
return logs.join('\n');
47+
}
48+
49+
it('should print only the shared cache path in a standard repository', async () => {
50+
const workspaceRoot = join(tempDir, 'project');
51+
await mkdir(join(workspaceRoot, '.git'), { recursive: true });
52+
await mkdir(join(workspaceRoot, '.angular/cache/app'), { recursive: true });
53+
54+
const output = await runInfo(workspaceRoot);
55+
56+
expect(output).toContain(join(workspaceRoot, '.angular/cache'));
57+
expect(output).not.toContain('Local path');
58+
});
59+
60+
it('should also print the worktree-local cache in a git worktree', async () => {
61+
const mainRepoRoot = join(tempDir, 'main-repo');
62+
const mainGitDir = join(mainRepoRoot, '.git');
63+
const worktreeRoot = join(tempDir, 'worktree');
64+
const worktreeMetadataDir = join(mainGitDir, 'worktrees/wt-1');
65+
66+
await mkdir(worktreeMetadataDir, { recursive: true });
67+
await mkdir(worktreeRoot, { recursive: true });
68+
await writeFile(join(worktreeRoot, '.git'), `gitdir: ${worktreeMetadataDir}`);
69+
await writeFile(join(worktreeMetadataDir, 'commondir'), '../..');
70+
71+
// The shared cache lives in the main checkout, while the development server keeps
72+
// its Vite cache in the worktree itself.
73+
await mkdir(join(mainRepoRoot, '.angular/cache/app'), { recursive: true });
74+
await mkdir(join(worktreeRoot, '.angular/cache/app/dev-server/vite'), { recursive: true });
75+
76+
const output = await runInfo(worktreeRoot);
77+
78+
expect(output).toContain(join(mainRepoRoot, '.angular/cache'));
79+
expect(output).toContain('Local path');
80+
expect(output).toContain(join(worktreeRoot, '.angular/cache'));
81+
expect(output).toContain('Local size on disk');
82+
});
83+
});

0 commit comments

Comments
 (0)