Skip to content

Commit

Permalink
feat(cli): add install-npm tool (#1343)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice authored Aug 22, 2023
1 parent b929c3c commit 4bacc2a
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 10 deletions.
9 changes: 8 additions & 1 deletion src/cli/command/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Cli } from 'clipanion';
import type { CliMode } from '../utils';
import { logger } from '../utils/logger';
import { DownloadFileCommand } from './download-file';
import { InstallNpmCommand, InstallNpmShortCommand } from './install-npm';
import { InstallToolCommand, InstallToolShortCommand } from './install-tool';
import { PrepareToolCommand, PrepareToolShortCommand } from './prepare-tool';
import { prepareToolVersion } from './utils';
Expand All @@ -17,6 +18,7 @@ export function prepareCommands(
* Workaround for linking the cli tool as different executables.
* So it can be called as
* - `install-tool node 1.2.3`
* - `install-npm corepack 1.2.3`
* - `prepare-tool node`
*/
if (mode === 'install-tool') {
Expand All @@ -25,11 +27,16 @@ export function prepareCommands(
} else if (mode === 'prepare-tool') {
cli.register(PrepareToolShortCommand);
return args;
} else if (mode === 'install-npm') {
cli.register(InstallNpmShortCommand);
return prepareToolVersion(mode, args);
}

cli.register(DownloadFileCommand);
cli.register(InstallNpmCommand);
cli.register(InstallToolCommand);
cli.register(PrepareToolCommand);
cli.register(DownloadFileCommand);

return prepareToolVersion(mode, args);
}

Expand Down
64 changes: 64 additions & 0 deletions src/cli/command/install-npm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Command, Option } from 'clipanion';
import prettyMilliseconds from 'pretty-ms';
import * as t from 'typanion';
import { installTool } from '../install-tool';
import { logger, validateVersion } from '../utils';

export class InstallNpmCommand extends Command {
static override paths = [['install', 'npm']];

static override usage = Command.Usage({
description: 'Installs a npm package into the container.',
examples: [
['Installs corepack 0.9.0', '$0 install npm corepack 0.9.0'],
[
'Installs corepack with version via environment variable',
'COREPACK_VERSION=0.9.0 $0 install npm corepack',
],
],
});

name = Option.String({ required: true });

version = Option.String({
required: true,
validator: t.cascade(t.isString(), validateVersion()),
});

dryRun = Option.Boolean('-d,--dry-run', false);

async execute(): Promise<number | void> {
const start = Date.now();
let error = false;

logger.info(`Installing npm package ${this.name} v${this.version}...`);
try {
return await installTool(this.name, this.version, this.dryRun, 'npm');
} catch (err) {
logger.fatal(err);
error = true;
return 1;
} finally {
logger.info(
`Installed npm package ${this.name} ${
error ? 'with errors ' : ''
}in ${prettyMilliseconds(Date.now() - start)}.`,
);
}
}
}

export class InstallNpmShortCommand extends InstallNpmCommand {
static override paths = [];

static override usage = Command.Usage({
description: 'Installs a npm package into the container.',
examples: [
['Installs corepack v0.9.0', '$0 corepack 0.9.0'],
[
'Installs corepack with version via environment variable',
'NODE_VERSION=0.9.0 $0 corepack',
],
],
});
}
7 changes: 5 additions & 2 deletions src/cli/command/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ export function prepareToolVersion(
switch (mode) {
case 'prepare-tool':
break;
case 'install-tool': {
case 'install-tool':
case 'install-npm': {
if (args.length === 1) {
// install-tool node
// install-npm corepack
appendVersion(args, 0);
}
break;
Expand All @@ -22,9 +24,10 @@ export function prepareToolVersion(
} else if (
args.length === 3 &&
args[0] === 'install' &&
args[1] === 'tool'
(args[1] === 'tool' || args[1] === 'npm')
) {
// containerbase-cli install tool node
// containerbase-cli install npm corepack
appendVersion(args, 2);
}
break;
Expand Down
31 changes: 30 additions & 1 deletion src/cli/install-tool/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Container } from 'inversify';
import { Container, injectable } from 'inversify';
import { rootContainer } from '../services';
import { InstallDartService } from '../tools/dart';
import { InstallDockerService } from '../tools/docker';
Expand All @@ -14,10 +14,13 @@ import {
InstallYarnService,
InstallYarnSlimService,
} from '../tools/node/npm';
import { InstallNodeBaseService } from '../tools/node/utils';
import { logger } from '../utils';
import { InstallLegacyToolService } from './install-legacy-tool.service';
import { INSTALL_TOOL_TOKEN, InstallToolService } from './install-tool.service';

export type InstallToolType = 'npm';

function prepareContainer(): Container {
logger.trace('preparing container');
const container = new Container();
Expand Down Expand Up @@ -49,7 +52,33 @@ export function installTool(
tool: string,
version: string,
dryRun = false,
type?: InstallToolType,
): Promise<number | void> {
const container = prepareContainer();
if (type) {
switch (type) {
case 'npm': {
@injectable()
class InstallGenericNpmService extends InstallNodeBaseService {
override readonly name: string = tool;

override needsPrepare(): boolean {
return false;
}

override async test(version: string): Promise<void> {
try {
// some npm packages may not have a `--version` flag
await super.test(version);
} catch (err) {
logger.debug(err);
}
}
}
container.bind(INSTALL_TOOL_TOKEN).to(InstallGenericNpmService);
break;
}
}
}
return container.get(InstallToolService).execute(tool, version, dryRun);
}
6 changes: 4 additions & 2 deletions src/cli/utils/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ vi.mock('node:process', () => procMocks);
describe('index', () => {
test('cliMode', async () => {
expect(cliMode()).toBeNull();
procMocks.argv0 = 'containerbase-cli';
expect((await import('.')).cliMode()).toBe('containerbase-cli');
procMocks.argv0 = 'install-npm';
expect((await import('.')).cliMode()).toBe('install-npm');
procMocks.argv0 = 'install-tool';
expect((await import('.')).cliMode()).toBe('install-tool');
procMocks.argv0 = 'prepare-tool';
expect((await import('.')).cliMode()).toBe('prepare-tool');
procMocks.argv0 = 'containerbase-cli';
expect((await import('.')).cliMode()).toBe('containerbase-cli');
});
});
9 changes: 6 additions & 3 deletions src/cli/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ export * from './logger';
export * from './common';

export function cliMode(): CliMode | null {
if (argv0.endsWith('/containerbase-cli') || argv0 === 'containerbase-cli') {
return 'containerbase-cli';
}
if (argv0.endsWith('/install-npm') || argv0 === 'install-npm') {
return 'install-npm';
}
if (argv0.endsWith('/install-tool') || argv0 === 'install-tool') {
return 'install-tool';
}
if (argv0.endsWith('/prepare-tool') || argv0 === 'prepare-tool') {
return 'prepare-tool';
}
if (argv0.endsWith('/containerbase-cli') || argv0 === 'containerbase-cli') {
return 'containerbase-cli';
}

return null;
}
6 changes: 5 additions & 1 deletion src/cli/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export interface Distro {
readonly versionId: string;
}

export type CliMode = 'containerbase-cli' | 'install-tool' | 'prepare-tool';
export type CliMode =
| 'containerbase-cli'
| 'install-npm'
| 'install-tool'
| 'prepare-tool';

export type Arch = 'arm64' | 'amd64';
1 change: 1 addition & 0 deletions src/usr/local/bin/install-containerbase
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ function link_tool () {
arch=arm64
fi
ln -sf /usr/local/containerbase/bin/containerbase-cli-${arch} /usr/local/bin/containerbase-cli
ln -sf /usr/local/containerbase/bin/containerbase-cli-${arch} /usr/local/bin/install-npm
ln -sf /usr/local/containerbase/bin/containerbase-cli-${arch} /usr/local/bin/install-tool
ln -sf /usr/local/containerbase/bin/containerbase-cli-${arch} /usr/local/bin/prepare-tool

Expand Down
4 changes: 4 additions & 0 deletions test/node/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ RUN set -ex; \

RUN set -ex; cd test/a; npm i

# renovate: datasource=npm
RUN install-npm del-cli 5.0.0
RUN del -d test/a/**

#--------------------------------------
# test: npm (install-tool npm)
#--------------------------------------
Expand Down

0 comments on commit 4bacc2a

Please sign in to comment.