@travetto/pack 3.0.0-rc.7 → 3.0.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,139 +0,0 @@
1
- import fs from 'fs/promises';
2
-
3
- import { IndexedModule, Package, PackageUtil, path, RootIndex } from '@travetto/manifest';
4
- import { FileQueryProvider, TypedObject } from '@travetto/base';
5
-
6
- import { PackUtil } from '../util';
7
-
8
- /**
9
- * Utils for assembling
10
- */
11
- export class AssembleUtil {
12
-
13
- /**
14
- * Purge workspace using file rules
15
- */
16
- static async excludeFiles(root: string, files: string[]): Promise<void> {
17
- const filter = PackUtil.excludeChecker(files, root);
18
- for await (const el of FileQueryProvider.query({ paths: [root], filter, hidden: true })) {
19
- try {
20
- await fs.unlink(el);
21
- } catch { }
22
- }
23
- }
24
-
25
- /**
26
- * Copy over added content
27
- */
28
- static async copyAddedContent(workspace: string, files: Record<string, string>[]): Promise<void> {
29
- for (const a of files) {
30
- let [src, dest] = Object.entries(a)[0];
31
- [src, dest] = [path.resolve(src), path.resolve(workspace, dest)];
32
- const stat = await fs.stat(src).catch(() => { });
33
- if (stat) {
34
- if (stat.isFile()) {
35
- await fs.mkdir(path.dirname(dest), { recursive: true });
36
- await fs.copyFile(src, dest);
37
- } else {
38
- await fs.mkdir(path.dirname(dest), { recursive: true });
39
- await PackUtil.copyRecursive(src, dest);
40
- }
41
- }
42
- }
43
- }
44
-
45
- static async copyModule(workspace: string, module: IndexedModule, keepSource?: boolean): Promise<void> {
46
- const toCopy: Promise<void>[] = [];
47
- for (const [key, files] of TypedObject.entries(module.files)) {
48
- switch (key) {
49
- case '$index':
50
- case '$root':
51
- case '$package':
52
- case 'src':
53
- case 'support':
54
- case 'resources':
55
- case 'bin': {
56
- for (const file of files) {
57
- const targetPartial = file.output.split(RootIndex.manifest.outputFolder)[1];
58
- const target = path.join(workspace, targetPartial);
59
- const src = await fs.stat(file.output).then(() => file.output, () => file.source);
60
- toCopy.push((async (): Promise<void> => {
61
- await fs.mkdir(path.dirname(target), { recursive: true });
62
- await fs.copyFile(src, target);
63
-
64
- if (file.type === 'ts' || file.type === 'js') {
65
- if (keepSource) {
66
- await fs.copyFile(`${src}.map`, `${target}.map`).catch(() => { });
67
- } else {
68
- await fs.writeFile(target, (await fs.readFile(target, 'utf8')).replace(/\/\/# sourceMap.*/g, ''));
69
- }
70
- }
71
- })());
72
- }
73
- break;
74
- }
75
- }
76
- }
77
- await Promise.all(toCopy);
78
- }
79
-
80
- /**
81
- * Copy over all prod dependencies
82
- */
83
- static async copyProdDependencies(workspace: string, keepSource?: boolean): Promise<void> {
84
- const pkgs = await PackageUtil.visitPackages<{ pkg: Package, src: string }>(RootIndex.mainModule.source, {
85
- valid: req =>
86
- (req.rel === 'prod' || req.rel === 'opt' || req.rel === 'root') &&
87
- !req.pkg.name.startsWith('@types/'),
88
- create: req => ({ pkg: req.pkg, src: req.sourcePath }),
89
- });
90
- await fs.mkdir(path.resolve(workspace, 'node_modules'), { recursive: true });
91
- for (const { pkg, src } of pkgs) {
92
- if (RootIndex.hasModule(pkg.name)) {
93
- await this.copyModule(workspace, RootIndex.getModule(pkg.name)!, keepSource);
94
- } else {
95
- const folder = path.dirname(path.resolve(workspace, 'node_modules', src.replace(/^.*?node_modules\//, '')));
96
- await PackUtil.copyRecursive(src, folder);
97
- }
98
- }
99
- }
100
-
101
- /**
102
- * Copy over entry point
103
- */
104
- static async copyEntryPoint(workspace: string): Promise<void> {
105
- // Faux-package.json
106
- await fs.writeFile(path.resolve(workspace, 'package.json'), JSON.stringify({
107
- name: '@entry/main',
108
- version: RootIndex.mainPackage.version,
109
- dependencies: { [RootIndex.mainPackage.name]: '*', }
110
- }, null, 2), 'utf8');
111
-
112
- const manifest = structuredClone(RootIndex.manifest);
113
- for (const [name, mod] of TypedObject.entries(manifest.modules)) {
114
- if (!mod.profiles.includes('std')) {
115
- delete manifest.modules[name];
116
- }
117
- }
118
-
119
- manifest.manifestFile = 'manifest.json';
120
- manifest.mainPath = RootIndex.manifest.modules[RootIndex.mainPackage.name].output;
121
-
122
- await fs.writeFile(path.resolve(workspace, 'manifest.json'), JSON.stringify(manifest), 'utf8');
123
-
124
- const output = path.resolve(RootIndex.manifest.workspacePath, RootIndex.manifest.outputFolder);
125
- for (const file of [
126
- path.resolve(output, 'trv'), // Entry points
127
- path.resolve(output, 'trv.cmd')
128
- ]) {
129
- await fs.copyFile(file, path.resolve(workspace, path.basename(file)));
130
- }
131
- }
132
-
133
- /**
134
- * Delete all empty folders
135
- */
136
- static async removeEmptyFolders(root: string): Promise<void> {
137
- // Remove
138
- }
139
- }
@@ -1,97 +0,0 @@
1
- import fs from 'fs/promises';
2
-
3
- import { path, RootIndex } from '@travetto/manifest';
4
- import { Env, ExecUtil } from '@travetto/base';
5
- import { cliTpl } from '@travetto/cli';
6
-
7
- import { CommonConfig, PackOperation } from './types';
8
- import { PackUtil } from './util';
9
-
10
- export interface DockerConfig extends CommonConfig {
11
- image: string;
12
- tag: string[];
13
- name?: string;
14
- app?: string;
15
- port?: (string | number)[];
16
- env: Record<string, string | number | boolean>;
17
- builder?: (cfg: DockerConfig) => string;
18
- registry?: string;
19
- push?: boolean;
20
- }
21
-
22
- const dockerFileBuilder = ({ image, port, app = 'rest', env }: DockerConfig): string => `
23
- FROM ${image}
24
- WORKDIR /app
25
- COPY . .
26
- ${Object.entries(env).map(([k, v]) => `ENV ${k} "${v}"`).join('\n')}
27
- ${(port ?? []).map(x => `EXPOSE ${x}`).join('\n')}
28
- CMD ["./trv", "run", "${app}"]
29
- `;
30
-
31
- export const Docker: PackOperation<DockerConfig, 'docker'> = {
32
- key: 'docker',
33
- title: 'Docker-izing',
34
- context(cfg: DockerConfig) {
35
- return `[image=${cfg.image}, port=${cfg.port}]`;
36
- },
37
- defaults: {
38
- name: RootIndex.mainPackage.name.replace('@', ''),
39
- image: 'node:18-alpine3.16',
40
- builder: dockerFileBuilder,
41
- port: [],
42
- tag: ['latest']
43
- },
44
- overrides: {
45
- image: Env.get('PACK_DOCKER_IMAGE') || undefined,
46
- name: Env.get('PACK_DOCKER_NAME') || undefined,
47
- app: Env.get('PACK_DOCKER_APP') || undefined,
48
- registry: Env.get('PACK_DOCKER_REGISTRY') || undefined,
49
- push: Env.getBoolean('PACK_DOCKER_PUSH'),
50
- port: Env.getList('PACK_DOCKER_PORT'),
51
- tag: Env.getList('PACK_DOCKER_TAG')
52
- },
53
- extend(src: Partial<DockerConfig>, dest: Partial<DockerConfig>): Partial<DockerConfig> {
54
- return {
55
- image: src.image ?? dest.image,
56
- app: src.app ?? dest.app,
57
- name: src.name ?? dest.name,
58
- builder: src.builder ?? dest.builder,
59
- tag: src.tag ?? dest.tag,
60
- port: src.port ?? dest.port,
61
- registry: src.registry ?? dest.registry,
62
- env: { ...(src.env ?? {}), ...(dest.env ?? {}) },
63
- push: src.push ?? dest.push
64
- };
65
- },
66
- buildConfig(configs: Partial<DockerConfig>[]): DockerConfig {
67
- return PackUtil.buildConfig(this, configs);
68
- },
69
- /**
70
- * Dockerize workspace with flags
71
- */
72
- async* exec(cfg: DockerConfig) {
73
- const { builder, workspace, push, image, tag, name, registry } = cfg;
74
-
75
- const ws = path.resolve(workspace);
76
-
77
- yield 'Building Dockerfile';
78
-
79
- await fs.writeFile(path.resolve(ws, 'Dockerfile'), builder!(cfg), { encoding: 'utf8' });
80
-
81
- yield 'Pulling Base Image';
82
- await ExecUtil.spawn('docker', ['pull', image]).result;
83
-
84
- yield 'Building Docker Container';
85
- const tags = tag.map(x => registry ? `${registry}/${name}:${x}` : `${name}:${x}`);
86
- const args = ['build', ...tags.flatMap(x => ['-t', x]), '.'];
87
-
88
- await ExecUtil.spawn('docker', args, { cwd: ws, stdio: [0, 'pipe', 2] }).result;
89
-
90
- if (push) {
91
- yield 'Pushing Tags';
92
- await ExecUtil.spawn('docker', ['image', 'push', ...tags]).result;
93
- }
94
-
95
- yield cliTpl`${{ success: 'Successfully' }} containerized project`;
96
- }
97
- };
@@ -1,69 +0,0 @@
1
- import { cliTpl } from '@travetto/cli';
2
-
3
- import { CommonConfig, PackOperation } from './types';
4
- import { PackUtil } from './util';
5
- import { Assemble, AssembleConfig } from './assemble/operation';
6
- import { Docker, DockerConfig } from './docker';
7
- import { Zip, ZipConfig } from './zip';
8
-
9
- type DeepPartial<T> = {
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- [P in keyof T]?: (T[P] extends (number | string | boolean | undefined | RegExp | ((...args: any[]) => any)) ?
12
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
- (T[P] | undefined) : (T[P] extends any[] ? DeepPartial<T[P][number]>[] : DeepPartial<T[P]>));
14
- };
15
-
16
- const ops = {
17
- [Assemble.key]: Assemble,
18
- [Zip.key]: Zip,
19
- [Docker.key]: Docker
20
- } as const;
21
-
22
- export type AllConfig = CommonConfig &
23
- { assemble: AssembleConfig } &
24
- { zip: ZipConfig } &
25
- { docker: DockerConfig };
26
-
27
- export type AllConfigPartial = DeepPartial<AllConfig>;
28
-
29
- type DefaultOpType = ['assemble', typeof Assemble];
30
-
31
- export const Pack: PackOperation<AllConfig, ''> = {
32
- key: '',
33
- title: 'Packing',
34
- buildConfig(configs: Partial<AllConfig>[]): AllConfig {
35
- const ret: Partial<AllConfig> = {
36
- workspace: configs[0].workspace,
37
- };
38
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
- for (const [k, op] of (Object.entries(ops) as DefaultOpType[])) {
40
- ret[k] = op.buildConfig(configs.map(config => config[k] ?? {}));
41
- }
42
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
43
- return ret as AllConfig;
44
- },
45
- async context(cfg: AllConfig) {
46
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
47
- return `[ ${(Object.entries(ops) as DefaultOpType[])
48
- .filter(x => cfg[x[0]].active)
49
- .map(x => x[0])
50
- .join(', ')} ]`;
51
- },
52
- async * exec(cfg: AllConfig) {
53
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
54
- const steps = (Object.entries(ops) as DefaultOpType[])
55
- .filter(x => cfg[x[0]].active);
56
-
57
- if (!steps.length) {
58
- throw new Error('Pack operation has zero active steps');
59
- }
60
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
61
- for (const [step, op] of steps as DefaultOpType[]) {
62
- process.stdout.write('\n');
63
- cfg[step].workspace = cfg.workspace;
64
- await PackUtil.runOperation(op, cfg[step], 2);
65
- }
66
- process.stdout.write('\n');
67
- yield cliTpl`${{ success: 'Successfully' }} packed project`;
68
- }
69
- };
@@ -1,51 +0,0 @@
1
- import fs from 'fs/promises';
2
-
3
- import { path } from '@travetto/manifest';
4
- import { ExecUtil } from '@travetto/base';
5
- import { cliTpl } from '@travetto/cli';
6
-
7
- import { CommonConfig, PackOperation } from './types';
8
- import { PackUtil } from './util';
9
-
10
- export interface ZipConfig extends CommonConfig {
11
- output: string;
12
- }
13
-
14
- export const Zip: PackOperation<ZipConfig, 'zip'> = {
15
- key: 'zip',
16
- title: 'Zipping',
17
- context(cfg: ZipConfig) {
18
- return `[output=${cfg.output}]`;
19
- },
20
- overrides: {
21
- output: process.env.PACK_ZIP_OUTPUT || undefined
22
- },
23
- extend(src: Partial<ZipConfig>, dest: Partial<ZipConfig>): Partial<ZipConfig> {
24
- return { output: src.output ?? dest.output };
25
- },
26
- buildConfig(configs: Partial<ZipConfig>[]): ZipConfig {
27
- return PackUtil.buildConfig(this, configs);
28
- },
29
- /**
30
- * Zip workspace with flags
31
- */
32
- async * exec({ workspace, output }: ZipConfig) {
33
- const ws = path.resolve(workspace);
34
- const zipFile = path.resolve(output);
35
-
36
- yield 'Preparing Target';
37
- await fs.mkdir(path.dirname(zipFile), { recursive: true });
38
- if (await fs.stat(zipFile).catch(() => { })) {
39
- await fs.unlink(zipFile); // Unlink
40
- }
41
-
42
- yield 'Compressing';
43
- if (/win/i.test(process.platform)) {
44
- await ExecUtil.spawn('powershell', ['Compress-Archive', '-Path', '.', '-DestinationPath', zipFile], { cwd: ws }).result;
45
- } else {
46
- await ExecUtil.spawn('zip', ['-r', zipFile, '.'], { cwd: ws }).result;
47
- }
48
-
49
- yield cliTpl`${{ success: 'Successfully' }} archived project to ${{ path: zipFile.replace(path.cwd(), '.') }}`;
50
- }
51
- };
@@ -1,97 +0,0 @@
1
- import os from 'os';
2
-
3
- import { path, RootIndex } from '@travetto/manifest';
4
- import { CliCommand, CliScmUtil, cliTpl, OptionConfig } from '@travetto/cli';
5
-
6
- import { PackUtil } from './bin/util';
7
- import { CommonConfig, PackOperation } from './bin/types';
8
-
9
- const packName = `pack_${RootIndex.mainPackage.name}`
10
- .toLowerCase()
11
- .replace(/[^a-z]+/g, '_')
12
- .replace(/_+/g, '_');
13
-
14
- export type BaseOptions = {
15
- workspace: OptionConfig<string>;
16
- };
17
-
18
- function getConfigFromOperationOrGlobal<C extends CommonConfig, K extends string>(key: K, config: Partial<C> | Record<K, Partial<C>> | undefined): Partial<C> | undefined {
19
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
20
- return !config ? config : (key && key in config ? (config as Record<K, C>)[key] : config) as C;
21
- }
22
-
23
- /**
24
- * Supports packing a project into a directory, ready for archiving
25
- */
26
- export abstract class BasePackCommand<V extends BaseOptions, C extends CommonConfig, K extends string> extends CliCommand<V> {
27
-
28
- /**
29
- * Package stage name
30
- */
31
- abstract get operation(): PackOperation<C, K>;
32
-
33
- get cmdOptions(): Partial<C> {
34
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
35
- return this.cmd as Partial<C>;
36
- }
37
-
38
- get name(): string {
39
- return this.operation.key ? `pack:${this.operation.key}` : 'pack';
40
- }
41
-
42
- commonOptions(): BaseOptions {
43
- return { workspace: this.option({ desc: 'Working directory' }) } as const;
44
- }
45
-
46
- async resolveConfigs(cfg: Partial<CommonConfig>, def?: Partial<CommonConfig>): Promise<C> {
47
- const configs = [
48
- { workspace: path.resolve(os.tmpdir(), packName) },
49
- def,
50
- cfg,
51
- this.cmdOptions,
52
- { active: true }
53
- ]
54
- .map(x => getConfigFromOperationOrGlobal(this.operation.key, x))
55
- .filter((x): x is C => x !== undefined);
56
-
57
- return this.operation.buildConfig(configs);
58
- }
59
-
60
- getArgs(): string {
61
- return '[mode]';
62
- }
63
-
64
- async help(): Promise<string> {
65
- const lines = await PackUtil.modeList();
66
-
67
- const out: string[] = [];
68
- if (lines.length) {
69
- out.push('', cliTpl`${{ title: 'Available Pack Modes:' }}`);
70
- for (const { name, file } of lines) {
71
- out.push(cliTpl` * ${{ input: `${name}` }} [${{ path: file }}]`);
72
- }
73
- out.push('');
74
- }
75
- return out.join('\n');
76
- }
77
-
78
- async action(): Promise<void> {
79
- if (!this.args[0]) {
80
- return this.showHelp('Missing config mode');
81
- }
82
-
83
- const list = (await PackUtil.modeList());
84
- const cfg = list.find(c => c.name === this.args[0]);
85
- if (!cfg) {
86
- return this.showHelp(`Unknown config mode: ${this.args[0]}`);
87
- }
88
-
89
- const def = list.find(c => c.name === 'default');
90
-
91
- const resolved = await this.resolveConfigs(cfg, def);
92
- if (await CliScmUtil.isRepoRoot(resolved.workspace)) {
93
- throw new Error('Refusing to use workspace with a .git directory');
94
- }
95
- return PackUtil.runOperation(this.operation, resolved);
96
- }
97
- }
@@ -1,21 +0,0 @@
1
- import { OptionConfig } from '@travetto/cli';
2
-
3
- import { BaseOptions, BasePackCommand } from './cli.pack-base';
4
- import { Assemble, AssembleConfig } from './bin/assemble/operation';
5
-
6
- type Options = BaseOptions & {
7
- keepSource: OptionConfig<boolean>;
8
- readonly: OptionConfig<boolean>;
9
- };
10
-
11
- export class PackAssembleCommand extends BasePackCommand<Options, AssembleConfig, 'assemble'> {
12
- operation = Assemble;
13
-
14
- getOptions(): Options {
15
- return {
16
- ...this.commonOptions(),
17
- keepSource: this.boolOption({ desc: 'Should source be preserved' }),
18
- readonly: this.boolOption({ desc: 'Build a readonly deployable' })
19
- };
20
- }
21
- }
@@ -1,55 +0,0 @@
1
- import fs from 'fs/promises';
2
- import { existsSync } from 'fs';
3
-
4
- import { path } from '@travetto/manifest';
5
- import { CliCommand, OptionConfig, ListOptionConfig } from '@travetto/cli';
6
-
7
- type Options = {
8
- app: OptionConfig<string>;
9
- image: OptionConfig<string>;
10
- port: OptionConfig<number>;
11
- add: ListOptionConfig<string>;
12
- output: OptionConfig<string>;
13
- };
14
-
15
- export class PackDockerExportCommand extends CliCommand<Options> {
16
-
17
- name = 'pack:docker-export';
18
-
19
- getOptions(): Options {
20
- return {
21
- app: this.option({ desc: 'The application target to run', def: 'rest' }),
22
- image: this.option({ desc: 'Docker image to extend', def: 'node:16-alpine' }),
23
- port: this.intOption({ desc: 'Expose port', def: 3000 }),
24
- add: this.listOption({ desc: 'Files to include' }),
25
- output: this.option({ desc: 'Docker file name', def: 'Dockerfile' })
26
- };
27
- }
28
-
29
- async action(...args: unknown[]): Promise<void> {
30
- const files = ['src', 'bin', 'support', 'resource', 'package.json', 'package-lock.json', ...this.cmd.add]
31
- .filter(x => existsSync(path.resolve(x)));
32
-
33
- const content = `
34
- FROM ${this.cmd.image} as build
35
- WORKDIR /build
36
- ${files.map(x => `COPY ${x} ${x}`).join('\n')}
37
- ENV NODE_OPTIONS "--no-deprecation"
38
- RUN npm ci
39
- RUN npx trv pack:assemble -w /app
40
-
41
- FROM ${this.cmd.image} as scratch
42
- COPY --from=build /app /app
43
- EXPOSE ${this.cmd.port}
44
- WORKDIR /app
45
- ENV NODE_OPTIONS "--no-deprecation"
46
- CMD ["./trv", "run", "${this.cmd.app}"]
47
- `;
48
-
49
- if (this.cmd.output === '-' || this.cmd.output === '/dev/stdout' || !this.cmd.output) {
50
- console.log(content);
51
- } else {
52
- await fs.writeFile(this.cmd.output, content, { encoding: 'utf8' });
53
- }
54
- }
55
- }
@@ -1,60 +0,0 @@
1
- import { AllConfigPartial } from './bin/pack';
2
-
3
- const mod = (f: string): string => `node_modules/${f}`;
4
-
5
- export const config: AllConfigPartial = {
6
- name: 'default',
7
- assemble: {
8
- active: true,
9
- keepSource: true,
10
- readonly: true,
11
- env: {
12
- TRV_DYNAMIC: '0'
13
- },
14
- add: [
15
- { [mod('@travetto/cli/bin/trv.js')]: mod('.bin/trv') },
16
- { [mod('lodash/lodash.min.js')]: mod('lodash/lodash.js') },
17
- ],
18
- exclude: [
19
- 'bower.json',
20
- 'LICENSE',
21
- 'LICENCE',
22
- '*.map',
23
- '*.md',
24
- '*.lock',
25
- '*.html',
26
- '*.mjs',
27
- mod('**/*.ts'),
28
- '*.d.ts',
29
- '*.tsbuildinfo',
30
- '*.java',
31
- '*.markdown',
32
- '.eslintrc',
33
- '.npmignore',
34
- '.*.yml',
35
- 'cache/compiler.*.log',
36
- mod('faker'),
37
- mod('lodash/lodash.min.js'),
38
- mod('source-map-support/node_modules/source-map'),
39
- mod('source-map-support/browser-source-map-support.js'),
40
- mod('bson/browser_build/'),
41
- mod('**/tsconfig.json'),
42
- mod('**/tsconfig.*.json'),
43
- mod('@travetto/*/doc.ts'),
44
- mod('typescript/'),
45
- mod('@types/'),
46
- `^./${mod('@travetto/**/*.ts')}`,
47
- `^./${mod('@travetto/compiler/tsconfig.trv.json')}`,
48
- '^./resources/',
49
- '^./src/',
50
- ]
51
- },
52
- zip: {
53
- active: false,
54
- output: 'output.zip'
55
- },
56
- docker: {
57
- active: false,
58
- image: 'node:16-alpine'
59
- }
60
- };