Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ca70662
feat: new tool installer
viceice May 25, 2023
3c15b54
fix: simplify version handling
viceice May 25, 2023
d691016
add help
viceice May 26, 2023
3126ba0
link plain cli
viceice May 26, 2023
53d3635
revert ci exclusions
viceice May 26, 2023
2b39778
force relative paths
viceice May 26, 2023
a0249c7
update build
viceice May 26, 2023
54dabaf
add more tools preparations
viceice May 26, 2023
242094c
fix build
viceice May 26, 2023
141b292
optimize help output
viceice May 26, 2023
837896c
fix arch check
viceice May 26, 2023
f6efcb7
fix version validation
viceice May 26, 2023
c9a1c46
support esbuild on arm and darwin
viceice May 30, 2023
dc86eb4
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice May 30, 2023
0278e79
fix typo
viceice May 30, 2023
79cf7d9
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice May 30, 2023
fc13d5b
fix lint issues
viceice May 30, 2023
5aa08d9
small optimizations
viceice May 30, 2023
cc8261b
wrap prepare-tool
viceice May 30, 2023
a6293a2
add issue link for esm
viceice May 30, 2023
55e168d
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice Jun 1, 2023
0ebf290
update binary paths
viceice Jun 1, 2023
6cef9b1
remove obsolete code
viceice Jun 1, 2023
53556ca
register commands
viceice Jun 1, 2023
6fdcd65
use nestjs and dependency injection
viceice Jun 1, 2023
2e82f17
use inversify
viceice Jun 2, 2023
21f8d5a
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice Jun 2, 2023
cdb986a
use more dependency injection
viceice Jun 2, 2023
21bd4fc
add prepare docker command
viceice Jun 2, 2023
b44ccf1
add docker installer
viceice Jun 2, 2023
c9886c3
refactor
viceice Jun 2, 2023
8e565e0
revert changes
viceice Jun 2, 2023
b353038
write version file and skip linking
viceice Jun 2, 2023
76ce394
create shell wrapper and fix access rights
viceice Jun 2, 2023
847325a
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice Jun 2, 2023
9680786
better error handling
viceice Jun 2, 2023
875861f
use node-tar
viceice Jun 2, 2023
65461ff
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice Jun 13, 2023
2d0e902
Merge remote-tracking branch 'origin/main' into feat/tool-v3
viceice Jun 16, 2023
27838d8
feat: add cache
viceice Jun 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*
!src
!test
src/cli
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/dist
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ jobs:
- name: prepare apt proxy
run: sudo yarn prepare:proxy

- name: build
run: yarn build

- name: test distro
run: docker buildx bake

Expand Down Expand Up @@ -149,6 +152,9 @@ jobs:
- name: prepare apt proxy
run: sudo yarn prepare:proxy

- name: build
run: yarn build

- name: test distro
run: docker buildx bake test-distro

Expand Down Expand Up @@ -208,6 +214,9 @@ jobs:
- name: prepare apt proxy
run: sudo yarn prepare:proxy

- name: build
run: yarn build

- name: test
run: docker buildx bake test
env:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
.cache/
node_modules/
/bin
/dist

# generated files
/src/usr/local/containerbase/version
/src/usr/local/containerbase/bin/containerbase-cli-*

.eslintcache

Expand Down
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ COPY src/ /

RUN install-containerbase


# renovate: datasource=github-tags packageName=git/git
RUN install-tool git v2.41.0

Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ Commits to `main` branch are automatically build and published.

You need a recent [docker](https://www.docker.com) version with [buildx](https://github.com/docker/buildx) [`>= v0.4.0`](https://github.com/docker/buildx/releases/tag/v0.4.0) plugin installed.

You should use
You first need to build the cli before building the docker images.

```console
> yarn install
> yarn build
```

### Base image

Expand Down
23 changes: 22 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
},
"scripts": {
"bats": "node_modules/bats/bin/bats --timing --verbose-run",
"build": "release:prepare",
"build": "run-s 'build:*'",
"build:cli": "node tools/esbuild.js",
"eslint": "eslint --cache --report-unused-disable-directives .",
"eslint-fix": "eslint --cache --fix --report-unused-disable-directives .",
"lint": "run-s prettier eslint",
Expand All @@ -22,21 +23,39 @@
"prettier-fix": "prettier --cache -w -u \"**/*.*\"",
"release:prepare": "node tools/prepare-release.js",
"release:publish": "node tools/publish-release.js",
"start": "tsx src/cli/index.ts",
"test:bats": "node_modules/bats/bin/bats --timing --verbose-run test/bash/ test/bash/v2",
"test:docker": "node tools/test.js"
},
"dependencies": {
"clipanion": "3.2.0",
"execa": "7.1.1",
"got": "12.6.0",
"hasha": "5.2.2",
"inversify": "6.0.1",
"pino": "8.14.1",
"pino-pretty": "10.0.0",
"reflect-metadata": "0.1.13",
"semver": "7.5.1",
"tar": "6.1.15",
"typanion": "3.12.1"
},
"devDependencies": {
"@semantic-release/exec": "6.0.3",
"@tsconfig/node18": "2.0.1",
"@types/node": "18.16.16",
"@types/semver": "7.5.0",
"@types/shelljs": "0.8.12",
"@types/tar": "6.1.5",
"@typescript-eslint/eslint-plugin": "5.59.9",
"@typescript-eslint/parser": "5.59.9",
"bats": "1.9.0",
"bats-assert": "2.0.0",
"bats-support": "0.3.0",
"clipanion": "3.2.1",
"conventional-changelog-conventionalcommits": "6.0.0",
"esbuild": "0.17.19",
"esbuild-plugin-pino": "2.0.0",
"eslint": "8.42.0",
"eslint-config-prettier": "8.8.0",
"eslint-formatter-gha": "1.4.2",
Expand All @@ -49,10 +68,12 @@
"husky": "8.0.3",
"lint-staged": "13.2.2",
"npm-run-all": "4.1.5",
"pkg": "5.8.1",
"prettier": "2.8.8",
"prettier-plugin-package": "1.3.0",
"semantic-release": "21.0.3",
"shelljs": "0.8.5",
"tsx": "3.12.7",
"typescript": "5.1.3"
},
"contributors": [
Expand Down
44 changes: 44 additions & 0 deletions src/cli/command/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { argv0 } from 'node:process';
import type { Cli } from 'clipanion';
import type { CliMode } from '../utils';
import { logger } from '../utils/logger';
import { InstallToolCommand, InstallToolShortCommand } from './install-tool';
import { PrepareToolCommand, PrepareToolShortCommand } from './prepare-tool';
import { prepareToolVersion } from './utils';

export function prepareCommands(
cli: Cli,
mode: CliMode | null,
args: string[]
): string[] {
logger.debug('prepare commands');
/*
* Workaround for linking the cli tool as different executables.
* So it can be called as
* - `install-tool node 1.2.3`
* - `prepare-tool node`
*/
if (mode === 'install-tool') {
cli.register(InstallToolShortCommand);
return prepareToolVersion(mode, args);
} else if (mode === 'prepare-tool') {
cli.register(PrepareToolShortCommand);
return args;
}

cli.register(InstallToolCommand);
cli.register(PrepareToolCommand);
return prepareToolVersion(mode, args);
}

export function parseBinaryName(
mode: CliMode | null,
node: string,
app: string
): string | undefined {
if (mode) {
return mode;
}

return argv0.endsWith('/node') || argv0 === 'node' ? `${node} ${app}` : argv0;
}
57 changes: 57 additions & 0 deletions src/cli/command/install-tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Command, Option } from 'clipanion';
import * as t from 'typanion';
import { installTool } from '../install-tool';
import { logger, validateVersion } from '../utils';

export class InstallToolCommand extends Command {
static override paths = [['install', 'tool'], ['it']];

static override usage = Command.Usage({
description: 'Installs a tool into the container.',
examples: [
['Installs node 14.17.0', '$0 install tool node 14.17.0'],
[
'Installs node with version via environment variable',
'NODE_VERSION=14.17.0 $0 install tool node',
],
],
});

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();

logger.info(`Installing tool ${this.name} v${this.version}...`);
try {
return await installTool(this.name, this.version, this.dryRun);
} catch (err) {
logger.fatal(err);
return 1;
} finally {
logger.info(`Installed tool ${this.name} in ${Date.now() - start}ms.`);
}
}
}

export class InstallToolShortCommand extends InstallToolCommand {
static override paths = [];

static override usage = Command.Usage({
description: 'Installs a tool into the container.',
examples: [
['Installs node v14.17.0', '$0 node 14.17.0'],
[
'Installs node with version via environment variable',
'NODE_VERSION=14.17.0 $0 node',
],
],
});
}
46 changes: 46 additions & 0 deletions src/cli/command/prepare-tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Command, Option } from 'clipanion';
import { prepareTools } from '../prepare-tool';
import { logger } from '../utils';

export class PrepareToolCommand extends Command {
static override paths = [['prepare', 'tool'], ['pt']];

static override usage = Command.Usage({
description: 'Prepares a tool into the container.',
examples: [
['Prepares node', '$0 prepare tool node'],
['Prepares all tools', '$0 prepare tool all'],
],
});

tools = Option.Rest({ required: 1 });

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

async execute(): Promise<number | void> {
const start = Date.now();
logger.info(`Preparing tools ${this.tools.join(', ')}...`);
try {
return await prepareTools(this.tools, this.dryRun);
} catch (err) {
logger.fatal(err);
return 1;
} finally {
logger.info(
`Prepared tools ${this.tools.join(', ')} in ${Date.now() - start}ms.`
);
}
}
}

export class PrepareToolShortCommand extends PrepareToolCommand {
static override paths = [];

static override usage = Command.Usage({
description: 'Prepares a tool into the container.',
examples: [
['Prepares node', '$0 node'],
['Prepares all tools', '$0'],
],
});
}
37 changes: 37 additions & 0 deletions src/cli/command/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { CliMode } from '../utils';

export function prepareToolVersion(
mode: CliMode | null,
args: string[]
): string[] {
switch (mode) {
case 'install-tool': {
if (args.length === 1) {
// install-tool node
appendVersion(args, 0);
}
break;
}
case 'containerbase-cli':
default: {
if (args.length === 2) {
// containerbase-cli it node
appendVersion(args, 1);
} else if (args.length === 3) {
// containerbase-cli install tool node
appendVersion(args, 2);
}
break;
}
}
return args;
}

function appendVersion(args: string[], index: number): void {
const tool = args.at(index)!;
const version =
process.env[tool.replace('-', '_').toUpperCase() + '_VERSION'];
if (version) {
args.push(version);
}
}
6 changes: 6 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node

import 'reflect-metadata';
import { main } from './main';

void main();
31 changes: 31 additions & 0 deletions src/cli/install-tool/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Container } from 'inversify';
import { rootContainer } from '../services';
import { InstallDockerService } from '../tools/docker';
import { logger } from '../utils';
import { InstallLegacyToolService } from './install-legacy-tool.service';
import { INSTALL_TOOL_TOKEN, InstallToolService } from './install-tool.service';

function prepareContainer(): Container {
logger.trace('preparing container');
const container = new Container();
container.parent = rootContainer;

// core services
container.bind(InstallToolService).toSelf();
container.bind(InstallLegacyToolService).toSelf();

// tool services
container.bind(INSTALL_TOOL_TOKEN).to(InstallDockerService);

logger.trace('preparing container done');
return container;
}

export function installTool(
tool: string,
version: string,
dryRun = false
): Promise<number | void> {
const container = prepareContainer();
return container.get(InstallToolService).execute(tool, version, dryRun);
}
13 changes: 13 additions & 0 deletions src/cli/install-tool/install-legacy-tool.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { execa } from 'execa';
import { injectable } from 'inversify';
import { logger } from '../utils';

@injectable()
export class InstallLegacyToolService {
async execute(tool: string, version: string): Promise<void> {
logger.info(`Preparing legacy tool ${tool} ...`);
await execa('/usr/local/containerbase/bin/install-tool', [tool, version], {
stdio: 'inherit',
});
}
}
Loading