core/src/npm/executor.ts

133 lines
3.3 KiB
TypeScript
Raw Normal View History

2020-11-21 15:41:08 +00:00
import * as fs from 'fs-extra';
import * as path from 'path';
2021-09-18 22:18:33 +00:00
import semver from 'semver';
2020-11-21 15:41:08 +00:00
import { IEnvironment } from '../types/environment';
2020-12-07 18:48:15 +00:00
import { spawnProcess } from '../util/run';
2020-11-21 15:41:08 +00:00
2021-10-02 08:07:01 +00:00
/**
* Execute NPM commands
*/
2020-11-21 15:41:08 +00:00
export class NPMExecutor {
2021-09-18 22:18:33 +00:00
private installed: Record<string, string> = {};
2023-08-07 13:19:32 +00:00
private packageFile: string = path.join(
this.environment.path,
'package.json'
);
2020-11-21 15:41:08 +00:00
2023-08-07 13:19:32 +00:00
constructor(private environment: IEnvironment, private coreModule: string) {}
2020-11-21 15:41:08 +00:00
2021-10-02 08:07:01 +00:00
/**
* Create a package.json file and install the core.
*/
2020-11-21 15:41:08 +00:00
public async init(): Promise<void> {
// Initialize npm environment
const c1 = await spawnProcess('npm', ['init', '-y'], this.environment);
if (c1.code > 0) {
throw new Error(c1.stderr.join('\n'));
}
// Install core module
2023-08-07 13:19:32 +00:00
const c2 = await spawnProcess(
'npm',
['install', this.coreModule],
this.environment
);
2020-11-21 15:41:08 +00:00
if (c2.code > 0) {
throw new Error(c2.stderr.join('\n'));
}
}
2021-10-02 08:07:01 +00:00
/**
* Load a package.json file into memory
*/
2020-11-21 15:41:08 +00:00
public async loadPackageFile(): Promise<void> {
2023-08-07 13:19:32 +00:00
if (!(await fs.pathExists(this.packageFile))) {
2020-11-21 15:41:08 +00:00
await this.init();
}
const jsonData = await fs.readJson(this.packageFile);
if (!jsonData.dependencies) {
return;
}
2021-09-18 22:18:33 +00:00
this.installed = jsonData.dependencies;
2020-11-21 15:41:08 +00:00
}
2021-10-02 08:07:01 +00:00
/**
* Install a npm package (examples: `@squeebot/core`, `@squeebot/core@3.3.3`, `node-ical`)
* @param pkg Package name
* @param development Install as devDependency
2021-10-02 08:07:01 +00:00
*/
public async installPackage(pkg: string, development = false): Promise<void> {
2023-08-07 13:19:32 +00:00
if (!(await fs.pathExists(this.packageFile))) {
2020-11-21 15:41:08 +00:00
await this.init();
}
2020-12-07 18:48:15 +00:00
let spi = 0;
if (pkg.indexOf('@') === 0) {
spi = 1;
}
2021-09-18 22:18:33 +00:00
const pkgRefSplit = pkg.split('@');
const pkgFullName = (spi === 1 ? '@' : '') + pkgRefSplit[spi];
2023-08-07 13:19:32 +00:00
const pkgVersion =
this.removeVersionWildcard(pkgRefSplit[spi + 1]) || 'latest';
2021-09-18 22:18:33 +00:00
const installedVersion = this.installed[pkgFullName];
2023-08-07 13:19:32 +00:00
if (installedVersion) {
// Ignore git or http version
if (
installedVersion.startsWith('http') ||
installedVersion.startsWith('git+') ||
installedVersion.startsWith('github:')
)
2021-09-18 22:18:33 +00:00
return;
2023-08-07 13:19:32 +00:00
if (installedVersion !== 'latest' && pkgVersion !== 'latest') {
const cardless = this.removeVersionWildcard(installedVersion) as string;
if (semver.lte(pkgVersion, cardless)) {
return;
}
2021-09-18 22:18:33 +00:00
}
2020-11-21 15:41:08 +00:00
}
2023-08-07 13:19:32 +00:00
const { code, stderr, stdout } = await spawnProcess(
'npm',
development ? ['install', '--save-dev', pkg] : ['install', pkg],
2023-08-07 13:19:32 +00:00
this.environment
);
2020-11-21 15:41:08 +00:00
if (code > 0) {
throw new Error(stderr.join('\n'));
}
await this.loadPackageFile();
}
2021-10-02 08:07:01 +00:00
/**
* Uninstall a npm package.
*
* See `installPackage` for more info.
* @param pkg Package name
*/
2020-11-21 15:41:08 +00:00
public async uninstallPackage(pkg: string): Promise<void> {
2023-08-07 13:19:32 +00:00
if (!(await fs.pathExists(this.packageFile))) {
2020-11-21 15:41:08 +00:00
await this.init();
}
2023-08-07 13:19:32 +00:00
const { code, stderr, stdout } = await spawnProcess(
'npm',
['remove', pkg],
this.environment
);
2020-11-21 15:41:08 +00:00
if (code > 0) {
throw new Error(stderr.join('\n'));
}
await this.loadPackageFile();
}
2021-09-18 22:18:33 +00:00
private removeVersionWildcard(str?: string): string | undefined {
return str?.replace(/\^|>|=/, '');
2021-09-18 22:18:33 +00:00
}
2020-11-21 15:41:08 +00:00
}