diff --git a/src/cli/command/cleanup-path.spec.ts b/src/cli/command/cleanup-path.spec.ts new file mode 100644 index 0000000000..ee3a0afdb7 --- /dev/null +++ b/src/cli/command/cleanup-path.spec.ts @@ -0,0 +1,26 @@ +import { Cli } from 'clipanion'; +import { describe, expect, test, vi } from 'vitest'; +import { prepareCommands } from '.'; + +const mocks = vi.hoisted(() => ({ + deleteAsync: vi.fn(), +})); + +vi.mock('del', () => mocks); + +describe('cli/command/cleanup-path', () => { + test('download-file', async () => { + const cli = new Cli({ binaryName: 'containerbase-cli' }); + prepareCommands(cli, null); + + expect( + await cli.run(['cleanup', 'path', '/tmp/**:/var/tmp', '/some/path/**']), + ).toBe(0); + + expect(mocks.deleteAsync).toHaveBeenCalledOnce(); + expect(mocks.deleteAsync).toHaveBeenCalledWith( + ['/tmp/**', '/var/tmp', '/some/path/**'], + { dot: true }, + ); + }); +}); diff --git a/src/cli/command/cleanup-path.ts b/src/cli/command/cleanup-path.ts new file mode 100644 index 0000000000..59d544f31e --- /dev/null +++ b/src/cli/command/cleanup-path.ts @@ -0,0 +1,49 @@ +import { Command, Option } from 'clipanion'; +import { deleteAsync } from 'del'; +import prettyMilliseconds from 'pretty-ms'; +import { logger } from '../utils'; + +export class CleanupPathCommand extends Command { + static override paths = [['cleanup', 'path']]; + + static override usage = Command.Usage({ + description: 'Cleanup passed paths.', + examples: [ + [ + 'Cleanup multiple paths', + '$0 cleanup path "/tmp/**:/var/tmp" "/some/paths/**"', + ], + ], + }); + + cleanupPaths = Option.Rest({ required: 1 }); + + async execute(): Promise { + const start = Date.now(); + let error = false; + const paths = this.cleanupPaths.flatMap((p) => p.split(':')); + logger.info({ paths }, `Cleanup paths ...`); + try { + const deleted = await deleteAsync(paths, { dot: true }); + logger.debug({ deleted }, 'Deleted paths'); + return 0; + } catch (err) { + error = true; + logger.debug(err); + if (err instanceof Error) { + logger.error(err.message); + } + return 1; + } finally { + if (error) { + logger.fatal( + `Cleanup failed in ${prettyMilliseconds(Date.now() - start)}.`, + ); + } else { + logger.info( + `Cleanup succeded in ${prettyMilliseconds(Date.now() - start)}.`, + ); + } + } + } +} diff --git a/src/cli/command/index.ts b/src/cli/command/index.ts index 1b391159c6..b9f1ea2adb 100644 --- a/src/cli/command/index.ts +++ b/src/cli/command/index.ts @@ -1,6 +1,7 @@ import type { Cli } from 'clipanion'; import type { CliMode } from '../utils'; import { logger } from '../utils/logger'; +import { CleanupPathCommand } from './cleanup-path'; import { DownloadFileCommand } from './download-file'; import { InitToolCommand } from './init-tool'; import { InstallGemCommand, InstallGemShortCommand } from './install-gem'; @@ -42,4 +43,5 @@ export function prepareCommands(cli: Cli, mode: CliMode | null): void { cli.register(InstallToolCommand); cli.register(PrepareToolCommand); cli.register(InitToolCommand); + cli.register(CleanupPathCommand); } diff --git a/src/usr/local/containerbase/bin/docker-entrypoint.sh b/src/usr/local/containerbase/bin/docker-entrypoint.sh index b91c0cfec5..498e49848c 100755 --- a/src/usr/local/containerbase/bin/docker-entrypoint.sh +++ b/src/usr/local/containerbase/bin/docker-entrypoint.sh @@ -5,6 +5,11 @@ if [[ -f "/usr/local/etc/env" && -z "${CONTAINERBASE_ENV+x}" ]]; then . /usr/local/etc/env fi +if [[ -n "${CONTAINERBASE_CLEANUP_PATH}" ]]; then + # cleanup path via https://www.npmjs.com/package/del + containerbase-cli cleanup path "${CONTAINERBASE_CLEANUP_PATH}" +fi + if [[ ! -d "/tmp/containerbase" ]]; then # initialize all prepared tools containerbase-cli init tool all