mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 01:54:04 +08:00
feat(@angular/cli): use PNPM as package manager when pnpm-lock.yaml
exists
While supported, we didn't automatically try to determine if PNPM was used through the lock files like we do for other package managers.
This commit is contained in:
parent
fbc4c3bfde
commit
9e69331fa6
@ -261,20 +261,9 @@ export abstract class ArchitectCommand<
|
||||
}
|
||||
|
||||
const packageManager = await getPackageManager(basePath);
|
||||
let installSuggestion = 'Try installing with ';
|
||||
switch (packageManager) {
|
||||
case 'npm':
|
||||
installSuggestion += `'npm install'`;
|
||||
break;
|
||||
case 'yarn':
|
||||
installSuggestion += `'yarn'`;
|
||||
break;
|
||||
default:
|
||||
installSuggestion += `the project's package manager`;
|
||||
break;
|
||||
}
|
||||
|
||||
this.logger.warn(`Node packages may not be installed. ${installSuggestion}.`);
|
||||
this.logger.warn(
|
||||
`Node packages may not be installed. Try installing with '${packageManager} install'.`,
|
||||
);
|
||||
}
|
||||
|
||||
async run(options: ArchitectCommandOptions & Arguments) {
|
||||
|
@ -10,6 +10,7 @@ import { json, workspaces } from '@angular-devkit/core';
|
||||
import { existsSync, readFileSync, statSync, writeFileSync } from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { PackageManager } from '../lib/config/workspace-schema';
|
||||
import { findUp } from './find-up';
|
||||
import { JSONFile, readAndParseJson } from './json-file';
|
||||
|
||||
@ -298,18 +299,19 @@ export function getProjectByCwd(workspace: AngularWorkspace): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getConfiguredPackageManager(): Promise<string | null> {
|
||||
const getPackageManager = (source: json.JsonValue | undefined): string | undefined => {
|
||||
export async function getConfiguredPackageManager(): Promise<PackageManager | null> {
|
||||
const getPackageManager = (source: json.JsonValue | undefined): PackageManager | null => {
|
||||
if (isJsonObject(source)) {
|
||||
const value = source['packageManager'];
|
||||
if (value && typeof value === 'string') {
|
||||
return value;
|
||||
return value as PackageManager;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
let result: string | undefined | null;
|
||||
|
||||
let result: PackageManager | null = null;
|
||||
const workspace = await getWorkspace('local');
|
||||
if (workspace) {
|
||||
const project = getProjectByCwd(workspace);
|
||||
@ -317,21 +319,15 @@ export async function getConfiguredPackageManager(): Promise<string | null> {
|
||||
result = getPackageManager(workspace.projects.get(project)?.extensions['cli']);
|
||||
}
|
||||
|
||||
result = result ?? getPackageManager(workspace.extensions['cli']);
|
||||
result ??= getPackageManager(workspace.extensions['cli']);
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
if (!result) {
|
||||
const globalOptions = await getWorkspace('global');
|
||||
result = getPackageManager(globalOptions?.extensions['cli']);
|
||||
|
||||
if (!workspace && !globalOptions) {
|
||||
// Only check legacy if updated workspace is not found
|
||||
result = getLegacyPackageManager();
|
||||
}
|
||||
}
|
||||
|
||||
// Default to null
|
||||
return result ?? null;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function migrateLegacyGlobalConfig(): boolean {
|
||||
@ -385,30 +381,6 @@ export function migrateLegacyGlobalConfig(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fallback, check for packageManager in config file in v1.* global config.
|
||||
function getLegacyPackageManager(): string | null {
|
||||
const homeDir = os.homedir();
|
||||
if (homeDir) {
|
||||
const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json');
|
||||
if (existsSync(legacyGlobalConfigPath)) {
|
||||
const legacy = readAndParseJson(legacyGlobalConfigPath);
|
||||
if (!isJsonObject(legacy)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
legacy.packageManager &&
|
||||
typeof legacy.packageManager === 'string' &&
|
||||
legacy.packageManager !== 'default'
|
||||
) {
|
||||
return legacy.packageManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getSchematicDefaults(
|
||||
collection: string,
|
||||
schematic: string,
|
||||
@ -480,3 +452,27 @@ export async function isWarningEnabled(warning: string): Promise<boolean> {
|
||||
// All warnings are enabled by default
|
||||
return result ?? true;
|
||||
}
|
||||
|
||||
// Fallback, check for packageManager in config file in v1.* global config.
|
||||
function getLegacyPackageManager(): string | null {
|
||||
const homeDir = os.homedir();
|
||||
if (homeDir) {
|
||||
const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json');
|
||||
if (existsSync(legacyGlobalConfigPath)) {
|
||||
const legacy = readAndParseJson(legacyGlobalConfigPath);
|
||||
if (!isJsonObject(legacy)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
legacy.packageManager &&
|
||||
typeof legacy.packageManager === 'string' &&
|
||||
legacy.packageManager !== 'default'
|
||||
) {
|
||||
return legacy.packageManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -6,16 +6,18 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
import { existsSync } from 'fs';
|
||||
import { exec as execCb, execSync } from 'child_process';
|
||||
import { constants, promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { satisfies, valid } from 'semver';
|
||||
import { promisify } from 'util';
|
||||
import { PackageManager } from '../lib/config/workspace-schema';
|
||||
import { getConfiguredPackageManager } from './config';
|
||||
|
||||
function supports(name: string): boolean {
|
||||
const exec = promisify(execCb);
|
||||
async function supports(name: PackageManager): Promise<boolean> {
|
||||
try {
|
||||
execSync(`${name} --version`, { stdio: 'ignore' });
|
||||
await exec(`${name} --version`);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
@ -23,38 +25,68 @@ function supports(name: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export function supportsYarn(): boolean {
|
||||
return supports('yarn');
|
||||
async function hasLockfile(root: string, packageManager: PackageManager): Promise<boolean> {
|
||||
try {
|
||||
let lockfileName: string;
|
||||
switch (packageManager) {
|
||||
case PackageManager.Yarn:
|
||||
lockfileName = 'yarn.lock';
|
||||
break;
|
||||
case PackageManager.Pnpm:
|
||||
lockfileName = 'pnpm-lock.yaml';
|
||||
break;
|
||||
case PackageManager.Npm:
|
||||
default:
|
||||
lockfileName = 'package-lock.json';
|
||||
break;
|
||||
}
|
||||
|
||||
export function supportsNpm(): boolean {
|
||||
return supports('npm');
|
||||
await fs.access(join(root, lockfileName), constants.F_OK);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPackageManager(root: string): Promise<PackageManager> {
|
||||
let packageManager = (await getConfiguredPackageManager()) as PackageManager | null;
|
||||
const packageManager = await getConfiguredPackageManager();
|
||||
if (packageManager) {
|
||||
return packageManager;
|
||||
}
|
||||
|
||||
const hasYarn = supportsYarn();
|
||||
const hasYarnLock = existsSync(join(root, 'yarn.lock'));
|
||||
const hasNpm = supportsNpm();
|
||||
const hasNpmLock = existsSync(join(root, 'package-lock.json'));
|
||||
const [hasYarnLock, hasNpmLock, hasPnpmLock] = await Promise.all([
|
||||
hasLockfile(root, PackageManager.Yarn),
|
||||
hasLockfile(root, PackageManager.Npm),
|
||||
hasLockfile(root, PackageManager.Pnpm),
|
||||
]);
|
||||
|
||||
const hasYarn = await supports(PackageManager.Yarn);
|
||||
if (hasYarn && hasYarnLock && !hasNpmLock) {
|
||||
packageManager = PackageManager.Yarn;
|
||||
} else if (hasNpm && hasNpmLock && !hasYarnLock) {
|
||||
packageManager = PackageManager.Npm;
|
||||
} else if (hasYarn && !hasNpm) {
|
||||
packageManager = PackageManager.Yarn;
|
||||
} else if (hasNpm && !hasYarn) {
|
||||
packageManager = PackageManager.Npm;
|
||||
return PackageManager.Yarn;
|
||||
}
|
||||
|
||||
const hasPnpm = await supports(PackageManager.Pnpm);
|
||||
if (hasPnpm && hasPnpmLock && !hasNpmLock) {
|
||||
return PackageManager.Pnpm;
|
||||
}
|
||||
|
||||
const hasNpm = await supports(PackageManager.Npm);
|
||||
if (hasNpm && hasNpmLock && !hasYarnLock && !hasPnpmLock) {
|
||||
return PackageManager.Npm;
|
||||
}
|
||||
|
||||
if (hasYarn && !hasNpm && !hasPnpm) {
|
||||
return PackageManager.Yarn;
|
||||
}
|
||||
|
||||
if (hasPnpm && !hasYarn && !hasNpm) {
|
||||
return PackageManager.Pnpm;
|
||||
}
|
||||
|
||||
// TODO: This should eventually inform the user of ambiguous package manager usage.
|
||||
// Potentially with a prompt to choose and optionally set as the default.
|
||||
return packageManager || PackageManager.Npm;
|
||||
return PackageManager.Npm;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user