18d3f3824SCedric van Puttenimport spawnAsync, { SpawnPromise, SpawnResult } from '@expo/spawn-async'; 28d3f3824SCedric van Puttenimport assert from 'assert'; 38d3f3824SCedric van Puttenimport fs from 'fs'; 48d3f3824SCedric van Puttenimport path from 'path'; 58d3f3824SCedric van Putten 68d3f3824SCedric van Puttenimport { PackageManager, PackageManagerOptions } from '../PackageManager'; 78d3f3824SCedric van Puttenimport { PendingSpawnPromise } from '../utils/spawn'; 88d3f3824SCedric van Putten 98d3f3824SCedric van Puttenexport abstract class BasePackageManager implements PackageManager { 108d3f3824SCedric van Putten readonly silent: boolean; 118d3f3824SCedric van Putten readonly log?: (...args: any) => void; 128d3f3824SCedric van Putten readonly options: PackageManagerOptions; 138d3f3824SCedric van Putten 148d3f3824SCedric van Putten constructor({ silent, log, env = process.env, ...options }: PackageManagerOptions = {}) { 158d3f3824SCedric van Putten this.silent = !!silent; 168d3f3824SCedric van Putten this.log = log ?? (!silent ? console.log : undefined); 178d3f3824SCedric van Putten this.options = { 18*efdcf92fSCedric van Putten stdio: silent ? undefined : 'inherit', 198d3f3824SCedric van Putten ...options, 208d3f3824SCedric van Putten env: { ...this.getDefaultEnvironment(), ...env }, 218d3f3824SCedric van Putten }; 228d3f3824SCedric van Putten } 238d3f3824SCedric van Putten 248d3f3824SCedric van Putten /** Get the name of the package manager */ 258d3f3824SCedric van Putten abstract readonly name: string; 268d3f3824SCedric van Putten /** Get the executable binary of the package manager */ 278d3f3824SCedric van Putten abstract readonly bin: string; 288d3f3824SCedric van Putten /** Get the lockfile for this package manager */ 298d3f3824SCedric van Putten abstract readonly lockFile: string; 308d3f3824SCedric van Putten 318d3f3824SCedric van Putten /** Get the default environment variables used when running the package manager. */ 328d3f3824SCedric van Putten protected getDefaultEnvironment(): Record<string, string> { 338d3f3824SCedric van Putten return { 348d3f3824SCedric van Putten ADBLOCK: '1', 358d3f3824SCedric van Putten DISABLE_OPENCOLLECTIVE: '1', 368d3f3824SCedric van Putten }; 378d3f3824SCedric van Putten } 388d3f3824SCedric van Putten 398d3f3824SCedric van Putten abstract addAsync( 408d3f3824SCedric van Putten namesOrFlags: string[] 418d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 428d3f3824SCedric van Putten abstract addDevAsync( 438d3f3824SCedric van Putten namesOrFlags: string[] 448d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 458d3f3824SCedric van Putten abstract addGlobalAsync( 468d3f3824SCedric van Putten namesOrFlags: string[] 478d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 488d3f3824SCedric van Putten 498d3f3824SCedric van Putten abstract removeAsync( 508d3f3824SCedric van Putten namesOrFlags: string[] 518d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 528d3f3824SCedric van Putten abstract removeDevAsync( 538d3f3824SCedric van Putten namesOrFlags: string[] 548d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 558d3f3824SCedric van Putten abstract removeGlobalAsync( 568d3f3824SCedric van Putten namesOrFlags: string[] 578d3f3824SCedric van Putten ): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>; 588d3f3824SCedric van Putten 598d3f3824SCedric van Putten abstract workspaceRoot(): PackageManager | null; 608d3f3824SCedric van Putten 618d3f3824SCedric van Putten /** Ensure the CWD is set to a non-empty string */ 628d3f3824SCedric van Putten protected ensureCwdDefined(method?: string): string { 638d3f3824SCedric van Putten const cwd = this.options.cwd?.toString(); 648d3f3824SCedric van Putten const className = (this.constructor as typeof BasePackageManager).name; 658d3f3824SCedric van Putten const methodName = method ? `.${method}` : ''; 668d3f3824SCedric van Putten assert(cwd, `cwd is required for ${className}${methodName}`); 678d3f3824SCedric van Putten return cwd; 688d3f3824SCedric van Putten } 698d3f3824SCedric van Putten 708d3f3824SCedric van Putten runAsync(command: string[]) { 718d3f3824SCedric van Putten this.log?.(`> ${this.name} ${command.join(' ')}`); 72*efdcf92fSCedric van Putten return spawnAsync(this.bin, command, this.options); 738d3f3824SCedric van Putten } 748d3f3824SCedric van Putten 758d3f3824SCedric van Putten async versionAsync() { 768d3f3824SCedric van Putten return await this.runAsync(['--version']).then(({ stdout }) => stdout.trim()); 778d3f3824SCedric van Putten } 788d3f3824SCedric van Putten 798d3f3824SCedric van Putten async getConfigAsync(key: string) { 808d3f3824SCedric van Putten return await this.runAsync(['config', 'get', key]).then(({ stdout }) => stdout.trim()); 818d3f3824SCedric van Putten } 828d3f3824SCedric van Putten 838d3f3824SCedric van Putten async removeLockfileAsync() { 848d3f3824SCedric van Putten const cwd = this.ensureCwdDefined('removeLockFile'); 858d3f3824SCedric van Putten const filePath = path.join(cwd, this.lockFile); 868d3f3824SCedric van Putten await fs.promises.rm(filePath, { force: true }); 878d3f3824SCedric van Putten } 888d3f3824SCedric van Putten 898d3f3824SCedric van Putten installAsync(flags: string[] = []): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult> { 908d3f3824SCedric van Putten return this.runAsync(['install', ...flags]); 918d3f3824SCedric van Putten } 928d3f3824SCedric van Putten 938d3f3824SCedric van Putten async uninstallAsync() { 948d3f3824SCedric van Putten const cwd = this.ensureCwdDefined('uninstallAsync'); 958d3f3824SCedric van Putten const modulesPath = path.join(cwd, 'node_modules'); 968d3f3824SCedric van Putten await fs.promises.rm(modulesPath, { force: true, recursive: true }); 978d3f3824SCedric van Putten } 988d3f3824SCedric van Putten} 99