Skip to content

Commit 9145f5e

Browse files
committed
refactor(@angular/cli): remove old package manager utilities
This removes the old implementation of the package-manager.
1 parent 68bc648 commit 9145f5e

File tree

8 files changed

+142
-420
lines changed

8 files changed

+142
-420
lines changed

packages/angular/cli/src/command-builder/command-module.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import { logging, schema } from '@angular-devkit/core';
9+
import { schema } from '@angular-devkit/core';
1010
import { readFileSync } from 'node:fs';
11-
import * as path from 'node:path';
11+
import { join, posix } from 'node:path';
1212
import type { ArgumentsCamelCase, Argv, CommandModule as YargsCommandModule } from 'yargs';
1313
import { Parser as yargsParser } from 'yargs/helpers';
1414
import { getAnalyticsUserId } from '../analytics/analytics';
@@ -17,7 +17,6 @@ import { EventCustomDimension, EventCustomMetric } from '../analytics/analytics-
1717
import { considerSettingUpAutocompletion } from '../utilities/completion';
1818
import { AngularWorkspace } from '../utilities/config';
1919
import { memoize } from '../utilities/memoize';
20-
import { PackageManagerUtils } from '../utilities/package-manager';
2120
import { CommandContext, CommandScope, Options, OtherOptions } from './definitions';
2221
import { Option, addSchemaOptionsToCommand } from './utilities/json-schema';
2322

@@ -75,8 +74,8 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
7574
...(this.longDescriptionPath
7675
? {
7776
longDescriptionRelativePath: path
78-
.relative(path.join(__dirname, '../../../../'), this.longDescriptionPath)
79-
.replace(/\\/g, path.posix.sep),
77+
.relative(join(__dirname, '../../../../'), this.longDescriptionPath)
78+
.replace(/\\/g, posix.sep),
8079
longDescription: readFileSync(this.longDescriptionPath, 'utf8').replace(
8180
/\r\n/g,
8281
'\n',
@@ -156,7 +155,7 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
156155
return userId
157156
? new AnalyticsCollector(this.context.logger, userId, {
158157
name: this.context.packageManager.name,
159-
version: this.context.packageManager.version,
158+
version: await this.context.packageManager.getVersion(),
160159
})
161160
: undefined;
162161
}

packages/angular/cli/src/command-builder/command-runner.ts

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import { logging } from '@angular-devkit/core';
9+
import { JsonValue, isJsonObject, logging } from '@angular-devkit/core';
10+
import { readFile } from 'node:fs/promises';
11+
import { join } from 'node:path';
1012
import yargs from 'yargs';
1113
import { Parser as yargsParser } from 'yargs/helpers';
14+
import { getCacheConfig } from '../commands/cache/utilities';
1215
import {
1316
CommandConfig,
1417
CommandNames,
1518
RootCommands,
1619
RootCommandsAliases,
1720
} from '../commands/command-config';
21+
import { PackageManagerName, createPackageManager } from '../package-managers';
1822
import { colors } from '../utilities/color';
19-
import { AngularWorkspace, getWorkspace } from '../utilities/config';
23+
import { AngularWorkspace, getProjectByCwd, getWorkspace } from '../utilities/config';
2024
import { assertIsError } from '../utilities/error';
21-
import { PackageManagerUtils } from '../utilities/package-manager';
2225
import { VERSION } from '../utilities/version';
2326
import { CommandContext, CommandModuleError } from './command-module';
2427
import {
@@ -34,11 +37,12 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis
3437
$0,
3538
_,
3639
help = false,
40+
dryRun = false,
3741
jsonHelp = false,
3842
getYargsCompletions = false,
3943
...rest
4044
} = yargsParser(args, {
41-
boolean: ['help', 'json-help', 'get-yargs-completions'],
45+
boolean: ['help', 'json-help', 'get-yargs-completions', 'dry-run'],
4246
alias: { 'collection': 'c' },
4347
});
4448

@@ -60,16 +64,29 @@ export async function runCommand(args: string[], logger: logging.Logger): Promis
6064
}
6165

6266
const root = workspace?.basePath ?? process.cwd();
63-
const localYargs = yargs(args);
6467

68+
const cacheConfig = getCacheConfig(workspace);
69+
const packageManager = await createPackageManager({
70+
cwd: root,
71+
logger,
72+
dryRun,
73+
tempDirectory: cacheConfig.enabled ? cacheConfig.path : undefined,
74+
configuredPackageManager: await getConfiguredPackageManager(
75+
root,
76+
workspace,
77+
globalConfiguration,
78+
),
79+
});
80+
81+
const localYargs = yargs(args);
6582
const context: CommandContext = {
6683
globalConfiguration,
6784
workspace,
6885
logger,
6986
currentDirectory: process.cwd(),
7087
yargsInstance: localYargs,
7188
root,
72-
packageManager: new PackageManagerUtils({ globalConfiguration, workspace, root }),
89+
packageManager,
7390
args: {
7491
positional: positional.map((v) => v.toString()),
7592
options: {
@@ -163,3 +180,58 @@ async function getCommandsToRegister(
163180

164181
return Promise.all(commands.map((command) => command.factory().then((m) => m.default)));
165182
}
183+
184+
/**
185+
* Gets the configured package manager by checking package.json, or the local and global angular.json files.
186+
*
187+
* @param root The root directory of the workspace.
188+
* @param localWorkspace The local workspace.
189+
* @param globalWorkspace The global workspace.
190+
* @returns The package manager name.
191+
*/
192+
async function getConfiguredPackageManager(
193+
root: string,
194+
localWorkspace: AngularWorkspace | undefined,
195+
globalWorkspace: AngularWorkspace,
196+
): Promise<PackageManagerName | undefined> {
197+
let result: PackageManagerName | undefined;
198+
199+
try {
200+
const packageJsonPath = join(root, 'package.json');
201+
const pkgJson = JSON.parse(await readFile(packageJsonPath, 'utf-8')) as JsonValue;
202+
result = getPackageManager(pkgJson);
203+
} catch {}
204+
205+
if (result) {
206+
return result;
207+
}
208+
209+
if (localWorkspace) {
210+
const project = getProjectByCwd(localWorkspace);
211+
if (project) {
212+
result = getPackageManager(localWorkspace.projects.get(project)?.extensions['cli']);
213+
}
214+
215+
result ??= getPackageManager(localWorkspace.extensions['cli']);
216+
}
217+
218+
result ??= getPackageManager(globalWorkspace.extensions['cli']);
219+
220+
return result;
221+
}
222+
223+
/**
224+
* Get the package manager name from a JSON value.
225+
* @param source The JSON value to get the package manager name from.
226+
* @returns The package manager name.
227+
*/
228+
function getPackageManager(source: JsonValue | undefined): PackageManagerName | undefined {
229+
if (source && isJsonObject(source)) {
230+
const value = source['packageManager'];
231+
if (typeof value === 'string') {
232+
return value.split('@', 1)[0] as unknown as PackageManagerName;
233+
}
234+
}
235+
236+
return undefined;
237+
}

packages/angular/cli/src/command-builder/definitions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
import { logging } from '@angular-devkit/core';
1010
import type { Argv, CamelCaseKey } from 'yargs';
11+
import { PackageManager } from '../package-managers/package-manager';
1112
import { AngularWorkspace } from '../utilities/config';
12-
import { PackageManagerUtils } from '../utilities/package-manager';
1313

1414
export enum CommandScope {
1515
/** Command can only run inside an Angular workspace. */
@@ -28,7 +28,7 @@ export interface CommandContext {
2828
workspace?: AngularWorkspace;
2929
globalConfiguration: AngularWorkspace;
3030
logger: logging.Logger;
31-
packageManager: PackageManagerUtils;
31+
packageManager: PackageManager;
3232
yargsInstance: Argv<{}>;
3333

3434
/** Arguments parsed in free-from without parser configuration. */

packages/angular/cli/src/commands/add/cli.ts

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Listr, ListrRenderer, ListrTaskWrapper, color, figures } from 'listr2';
1010
import assert from 'node:assert';
1111
import fs from 'node:fs/promises';
1212
import { createRequire } from 'node:module';
13-
import { dirname, join, relative, resolve } from 'node:path';
13+
import { dirname, join } from 'node:path';
1414
import npa from 'npm-package-arg';
1515
import semver, { Range, compare, intersects, prerelease, satisfies, valid } from 'semver';
1616
import { Argv } from 'yargs';
@@ -25,16 +25,13 @@ import {
2525
} from '../../command-builder/schematics-command-module';
2626
import {
2727
NgAddSaveDependency,
28-
PackageManager,
2928
PackageManagerError,
3029
PackageManifest,
3130
PackageMetadata,
32-
createPackageManager,
3331
} from '../../package-managers';
3432
import { assertIsError } from '../../utilities/error';
3533
import { isTTY } from '../../utilities/tty';
3634
import { VERSION } from '../../utilities/version';
37-
import { getCacheConfig } from '../cache/utilities';
3835

3936
class CommandError extends Error {}
4037

@@ -46,7 +43,6 @@ interface AddCommandArgs extends SchematicsCommandArgs {
4643
}
4744

4845
interface AddCommandTaskContext {
49-
packageManager: PackageManager;
5046
packageIdentifier: npa.Result;
5147
savePackage?: NgAddSaveDependency;
5248
collectionName?: string;
@@ -198,7 +194,8 @@ export default class AddCommandModule
198194
[
199195
{
200196
title: 'Determining Package Manager',
201-
task: (context, task) => this.determinePackageManagerTask(context, task),
197+
task: (_context, task) =>
198+
(task.output = `Using package manager: ${color.dim(this.context.packageManager.name)}`),
202199
rendererOptions: { persistentOutput: true },
203200
},
204201
{
@@ -309,47 +306,14 @@ export default class AddCommandModule
309306
}
310307
}
311308

312-
private async determinePackageManagerTask(
313-
context: AddCommandTaskContext,
314-
task: AddCommandTaskWrapper,
315-
): Promise<void> {
316-
let tempDirectory: string | undefined;
317-
const tempOptions = ['node_modules'];
318-
319-
const cacheConfig = getCacheConfig(this.context.workspace);
320-
if (cacheConfig.enabled) {
321-
const cachePath = resolve(this.context.root, cacheConfig.path);
322-
if (!relative(this.context.root, cachePath).startsWith('..')) {
323-
tempOptions.push(cachePath);
324-
}
325-
}
326-
327-
for (const tempOption of tempOptions) {
328-
try {
329-
const directory = resolve(this.context.root, tempOption);
330-
if ((await fs.stat(directory)).isDirectory()) {
331-
tempDirectory = directory;
332-
break;
333-
}
334-
} catch {}
335-
}
336-
337-
context.packageManager = await createPackageManager({
338-
cwd: this.context.root,
339-
logger: this.context.logger,
340-
dryRun: context.dryRun,
341-
tempDirectory,
342-
});
343-
task.output = `Using package manager: ${color.dim(context.packageManager.name)}`;
344-
}
345-
346309
private async findCompatiblePackageVersionTask(
347310
context: AddCommandTaskContext,
348311
task: AddCommandTaskWrapper,
349312
options: Options<AddCommandArgs>,
350313
): Promise<void> {
351314
const { registry, verbose } = options;
352-
const { packageManager, packageIdentifier } = context;
315+
const { packageIdentifier } = context;
316+
const { packageManager } = this.context;
353317
const packageName = packageIdentifier.name;
354318

355319
assert(packageName, 'Registry package identifiers should always have a name.');
@@ -446,7 +410,8 @@ export default class AddCommandModule
446410
rejectionReasons: string[];
447411
},
448412
): Promise<PackageManifest | null> {
449-
const { packageManager, packageIdentifier } = context;
413+
const { packageIdentifier } = context;
414+
const { packageManager } = this.context;
450415
const { registry, verbose, rejectionReasons } = options;
451416
const packageName = packageIdentifier.name;
452417
assert(packageName, 'Package name must be defined.');
@@ -524,9 +489,12 @@ export default class AddCommandModule
524489

525490
let manifest;
526491
try {
527-
manifest = await context.packageManager.getManifest(context.packageIdentifier.toString(), {
528-
registry,
529-
});
492+
manifest = await this.context.packageManager.getManifest(
493+
context.packageIdentifier.toString(),
494+
{
495+
registry,
496+
},
497+
);
530498
} catch (e) {
531499
assertIsError(e);
532500
throw new CommandError(
@@ -585,7 +553,8 @@ export default class AddCommandModule
585553
options: Options<AddCommandArgs>,
586554
): Promise<void> {
587555
const { registry } = options;
588-
const { packageManager, packageIdentifier, savePackage } = context;
556+
const { packageIdentifier, savePackage } = context;
557+
const { packageManager } = this.context;
589558

590559
// Only show if installation will actually occur
591560
task.title = 'Installing package';

packages/angular/cli/src/commands/update/cli.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ import {
2020
Options,
2121
} from '../../command-builder/command-module';
2222
import { SchematicEngineHost } from '../../command-builder/utilities/schematic-engine-host';
23-
import {
24-
InstalledPackage,
25-
PackageManager,
26-
PackageManifest,
27-
createPackageManager,
28-
} from '../../package-managers';
23+
import { InstalledPackage, PackageManager, PackageManifest } from '../../package-managers';
2924
import { colors } from '../../utilities/color';
3025
import { disableVersionCheck } from '../../utilities/environment-options';
3126
import { assertIsError } from '../../utilities/error';
@@ -168,13 +163,7 @@ export default class UpdateCommandModule extends CommandModule<UpdateCommandArgs
168163
}
169164

170165
async run(options: Options<UpdateCommandArgs>): Promise<number | void> {
171-
const { logger } = this.context;
172-
// Instantiate the package manager
173-
const packageManager = await createPackageManager({
174-
cwd: this.context.root,
175-
logger,
176-
configuredPackageManager: this.context.packageManager.name,
177-
});
166+
const { logger, packageManager } = this.context;
178167

179168
// Check if the current installed CLI version is older than the latest compatible version.
180169
// Skip when running `ng update` without a package name as this will not trigger an actual update.

packages/angular/cli/src/package-managers/host.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
*/
1515

1616
import { type SpawnOptions, spawn } from 'node:child_process';
17-
import { Stats, constants } from 'node:fs';
18-
import { copyFile, mkdtemp, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
17+
import { Stats, constants, existsSync } from 'node:fs';
18+
import { copyFile, mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
1919
import { platform, tmpdir } from 'node:os';
2020
import { join } from 'node:path';
2121
import { PackageManagerError } from './error';
@@ -24,6 +24,13 @@ import { PackageManagerError } from './error';
2424
* An abstraction layer for side-effectful operations.
2525
*/
2626
export interface Host {
27+
/**
28+
* Creates a directory.
29+
* @param path The path to the directory.
30+
* @returns A promise that resolves when the directory is created.
31+
*/
32+
mkdir(path: string): Promise<void>;
33+
2734
/**
2835
* Gets the stats of a file or directory.
2936
* @param path The path to the file or directory.
@@ -101,10 +108,12 @@ export interface Host {
101108
export const NodeJS_HOST: Host = {
102109
stat,
103110
readdir,
111+
mkdir,
104112
readFile: (path: string) => readFile(path, { encoding: 'utf8' }),
105113
copyFile: (src, dest) => copyFile(src, dest, constants.COPYFILE_FICLONE),
106114
writeFile,
107-
createTempDirectory: (baseDir?: string) => mkdtemp(join(baseDir ?? tmpdir(), 'angular-cli-')),
115+
createTempDirectory: (baseDir?: string) =>
116+
mkdtemp(join(baseDir ?? tmpdir(), 'angular-cli-tmp-packages-')),
108117
deleteDirectory: (path: string) => rm(path, { recursive: true, force: true }),
109118
runCommand: async (
110119
command: string,

0 commit comments

Comments
 (0)