@travetto/pack 3.0.0-rc.2 → 3.0.0-rc.20
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.
- package/README.md +1 -1
- package/__index__.ts +1 -0
- package/package.json +16 -11
- package/support/bin/config.ts +81 -0
- package/support/bin/docker-operation.ts +96 -0
- package/support/bin/operation.ts +273 -0
- package/support/bin/rollup-esm-dynamic-import.ts +55 -0
- package/support/bin/rollup.ts +36 -0
- package/support/bin/shell.ts +53 -0
- package/support/bin/types.ts +70 -0
- package/support/bin/util.ts +63 -0
- package/support/cli.pack.ts +14 -0
- package/support/cli.pack_docker.ts +48 -0
- package/support/cli.pack_zip.ts +24 -0
- package/support/pack.base.ts +150 -0
- package/support/pack.dockerfile.ts +9 -0
- package/bin/cli-pack.ts +0 -10
- package/bin/cli-pack_assemble.ts +0 -21
- package/bin/cli-pack_docker-export.ts +0 -54
- package/bin/cli-pack_docker.ts +0 -29
- package/bin/cli-pack_zip.ts +0 -19
- package/bin/lib/assemble.ts +0 -151
- package/bin/lib/dependencies.ts +0 -103
- package/bin/lib/types.ts +0 -19
- package/bin/lib/util.ts +0 -175
- package/bin/operation/assemble.ts +0 -75
- package/bin/operation/docker.ts +0 -96
- package/bin/operation/pack.ts +0 -69
- package/bin/operation/zip.ts +0 -51
- package/bin/pack-base.ts +0 -100
- package/index.d.ts +0 -5
- package/support/pack.config.ts +0 -66
package/bin/lib/dependencies.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
|
|
3
|
-
import { FsUtil, PathUtil } from '@travetto/boot';
|
|
4
|
-
|
|
5
|
-
export type ResolvedDep = { file: string, type: DepType, dep: string, version: string };
|
|
6
|
-
export type DepType = 'prod' | 'dev' | 'opt' | 'peer';
|
|
7
|
-
|
|
8
|
-
type DepResolveConfig = { root?: string, types?: DepType[] | (readonly DepType[]), maxDepth?: number };
|
|
9
|
-
|
|
10
|
-
const DEP_MAPPING = {
|
|
11
|
-
prod: 'dependencies',
|
|
12
|
-
dev: 'devDependencies',
|
|
13
|
-
opt: 'optionalDependencies',
|
|
14
|
-
peer: 'peerDependencies',
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
type PackageShape = {
|
|
18
|
-
name: string;
|
|
19
|
-
} & {
|
|
20
|
-
[key: string]: {
|
|
21
|
-
[key: string]: string;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Utilities for processing the package.json dependencies
|
|
27
|
-
*/
|
|
28
|
-
export class DependenciesUtil {
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Find the dependency's package.json file
|
|
32
|
-
* @param dep
|
|
33
|
-
* @param root
|
|
34
|
-
*/
|
|
35
|
-
static resolveDependencyPackageJson(dep: string, root: string): string {
|
|
36
|
-
const paths = [root, ...(require.resolve.paths(root) || [])];
|
|
37
|
-
let folder: string;
|
|
38
|
-
try {
|
|
39
|
-
folder = require.resolve(`${dep}/package.json`, { paths });
|
|
40
|
-
folder = path.dirname(PathUtil.resolveUnix(root, folder));
|
|
41
|
-
} catch {
|
|
42
|
-
folder = require.resolve(dep, { paths });
|
|
43
|
-
folder = path.dirname(PathUtil.resolveUnix(root, folder));
|
|
44
|
-
while (!FsUtil.existsSync(`${folder}/package.json`)) {
|
|
45
|
-
const next = path.dirname(folder);
|
|
46
|
-
if (folder === next) {
|
|
47
|
-
throw new Error(`Unable to resolve dependency: ${dep}`);
|
|
48
|
-
}
|
|
49
|
-
folder = next;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return folder;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get list of all production dependencies and their folders, for a given package
|
|
57
|
-
*/
|
|
58
|
-
static async resolveDependencies({
|
|
59
|
-
root = PathUtil.cwd,
|
|
60
|
-
types = ['prod'],
|
|
61
|
-
maxDepth = Number.MAX_SAFE_INTEGER
|
|
62
|
-
}: DepResolveConfig): Promise<ResolvedDep[]> {
|
|
63
|
-
const pending: [string, number][] = [[root, 0]];
|
|
64
|
-
const foundSet = new Set<string>();
|
|
65
|
-
const found: ResolvedDep[] = [];
|
|
66
|
-
while (pending.length) {
|
|
67
|
-
const [top, depth] = pending.shift()!;
|
|
68
|
-
if (depth > maxDepth) { // Ignore if greater than valid max depth
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
72
|
-
const p = await import(`${top}/package.json`) as PackageShape;
|
|
73
|
-
const deps: (readonly [name: string, type: DepType, version: string])[] = [];
|
|
74
|
-
for (const type of types) {
|
|
75
|
-
if (
|
|
76
|
-
type !== 'dev' ||
|
|
77
|
-
maxDepth === 0
|
|
78
|
-
) {
|
|
79
|
-
deps.push(...Object
|
|
80
|
-
.entries<Record<string, string>>(p[DEP_MAPPING[type]] ?? {})
|
|
81
|
-
.map(([name, version]) => [name, type, version] as const)
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
for (const [dep, type, version] of deps) {
|
|
86
|
-
try {
|
|
87
|
-
const resolved = this.resolveDependencyPackageJson(dep, top);
|
|
88
|
-
|
|
89
|
-
if (!foundSet.has(resolved)) {
|
|
90
|
-
foundSet.add(resolved);
|
|
91
|
-
found.push({ file: resolved, type, dep, version });
|
|
92
|
-
pending.push([resolved, depth + 1]);
|
|
93
|
-
}
|
|
94
|
-
} catch {
|
|
95
|
-
if (!dep.startsWith('@types') && type !== 'opt' && type !== 'peer') {
|
|
96
|
-
console.error('Unable to resolve', { type, dependency: dep });
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return found;
|
|
102
|
-
}
|
|
103
|
-
}
|
package/bin/lib/types.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export type CommonConfig = {
|
|
2
|
-
name?: string;
|
|
3
|
-
file?: string;
|
|
4
|
-
workspace: string;
|
|
5
|
-
active?: boolean;
|
|
6
|
-
postProcess?: { [key: string]: (<T extends CommonConfig>(cfg: T) => Promise<void>) }[];
|
|
7
|
-
preProcess?: { [key: string]: (<T extends CommonConfig>(cfg: T) => Promise<void>) }[];
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export type PackOperation<T extends CommonConfig, K extends string> = {
|
|
11
|
-
key: K;
|
|
12
|
-
title: string;
|
|
13
|
-
defaults?: Partial<T>;
|
|
14
|
-
overrides?: Partial<T>;
|
|
15
|
-
extend?(src: Partial<T>, dest: Partial<T>): Partial<T>;
|
|
16
|
-
context(cfg: T): Promise<string> | string;
|
|
17
|
-
exec(cfg: T): AsyncGenerator<string>;
|
|
18
|
-
buildConfig(configs: Partial<T>[]): T;
|
|
19
|
-
};
|
package/bin/lib/util.ts
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
// TODO: Get proper typings
|
|
5
|
-
const glob = require('picomatch');
|
|
6
|
-
|
|
7
|
-
import { FsUtil, PathUtil, ScanFs } from '@travetto/boot';
|
|
8
|
-
import { SourceIndex } from '@travetto/boot/src/internal/source';
|
|
9
|
-
import { color } from '@travetto/cli/src/color';
|
|
10
|
-
|
|
11
|
-
import { CommonConfig, PackOperation } from './types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Shared packing utils
|
|
15
|
-
*/
|
|
16
|
-
export class PackUtil {
|
|
17
|
-
|
|
18
|
-
static #modes: Partial<CommonConfig>[];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Build configuration object for an operation with a set of configs
|
|
22
|
-
*/
|
|
23
|
-
static buildConfig<T extends CommonConfig>(
|
|
24
|
-
op: { defaults?: Partial<T>, overrides?: Partial<T>, extend?(src: Partial<T>, dest: Partial<T>): Partial<T> },
|
|
25
|
-
configs: Partial<T>[]
|
|
26
|
-
): T {
|
|
27
|
-
const inputs = [
|
|
28
|
-
op.defaults! ?? {},
|
|
29
|
-
...configs,
|
|
30
|
-
op.overrides! ?? {}
|
|
31
|
-
].filter(x => Object.keys(x).length > 0);
|
|
32
|
-
|
|
33
|
-
const res = inputs.reduce((out: Partial<T>, config: Partial<T>): Partial<T> => {
|
|
34
|
-
const final = {
|
|
35
|
-
active: config.active ?? out.active,
|
|
36
|
-
workspace: config.workspace ?? out.workspace,
|
|
37
|
-
preProcess: [...(config.preProcess! ?? []), ...(out.preProcess ?? [])],
|
|
38
|
-
postProcess: [...(config.postProcess! ?? []), ...(out.postProcess ?? [])],
|
|
39
|
-
...op.extend?.(config, out)
|
|
40
|
-
};
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
42
|
-
return final as Partial<T>;
|
|
43
|
-
}, {});
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
45
|
-
return res as T;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Find pack modes with associated metadata
|
|
50
|
-
*/
|
|
51
|
-
static async modeList(): Promise<Partial<CommonConfig>[]> {
|
|
52
|
-
if (!this.#modes) {
|
|
53
|
-
this.#modes = await Promise.all(
|
|
54
|
-
SourceIndex.find({ folder: 'support', filter: f => /\/pack[.].*[.]ts/.test(f) })
|
|
55
|
-
.map(async (x) => {
|
|
56
|
-
const req: Partial<CommonConfig> = (await import(x.file)).config;
|
|
57
|
-
req.file = x.module.replace(/^node_modules\//, '');
|
|
58
|
-
return req;
|
|
59
|
-
})
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
return this.#modes;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Build file include/exclude lists/checker
|
|
68
|
-
*/
|
|
69
|
-
static excludeChecker(files: string[], base: string): (file: string) => boolean {
|
|
70
|
-
const all = files.map(x => {
|
|
71
|
-
const negate = x.startsWith('!') || x.startsWith('^');
|
|
72
|
-
x = negate ? x.substring(1) : x;
|
|
73
|
-
x = x.replace(/^[.][/]/g, `${base}/`);
|
|
74
|
-
const match: (f: string) => boolean = glob(x, { nocase: true, dot: true, basename: base, contains: true });
|
|
75
|
-
Object.defineProperty(match, 'source', { value: x });
|
|
76
|
-
return [match, negate] as const;
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return (f: string): boolean => {
|
|
80
|
-
let exclude = undefined;
|
|
81
|
-
f = PathUtil.resolveUnix(base, f);
|
|
82
|
-
for (const [match, n] of all) {
|
|
83
|
-
if ((n || exclude === undefined) && match(f)) {
|
|
84
|
-
if (n) { // Fast exit if negating
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
exclude = match;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return !!exclude;
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Update .env.js with new env data
|
|
96
|
-
*/
|
|
97
|
-
static async writeEnvJs(workspace: string, env: Record<string, string | undefined>): Promise<void> {
|
|
98
|
-
const out = `${workspace}/.env.js`;
|
|
99
|
-
let src = '';
|
|
100
|
-
if (!!(await FsUtil.exists(out))) {
|
|
101
|
-
src = await fs.readFile(out, 'utf8');
|
|
102
|
-
}
|
|
103
|
-
const lines = Object.entries(env).map(([k, v]) => v ? `process.env['${k}'] = \`${v.replace(/`/g, '\\`')}\`;` : '');
|
|
104
|
-
const content = `${src}\n${lines.join('\n')}`;
|
|
105
|
-
await fs.writeFile(PathUtil.resolveUnix(workspace, '.env.js'), content, { encoding: 'utf8' });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Delete all empty folders
|
|
110
|
-
*/
|
|
111
|
-
static async removeEmptyFolders(root: string): Promise<void> {
|
|
112
|
-
for (const el of await ScanFs.scanDir({ testDir: x => true, testFile: x => false, withHidden: true }, root)) {
|
|
113
|
-
let dir = el.file;
|
|
114
|
-
while ((await fs.readdir(dir)).length === 0) { // empty
|
|
115
|
-
await fs.rmdir(dir);
|
|
116
|
-
dir = path.dirname(dir);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Run operation with logging
|
|
123
|
-
*/
|
|
124
|
-
static async runOperation<T extends CommonConfig>(op: PackOperation<T, string>, cfg: T, indent = 0): Promise<void> {
|
|
125
|
-
const spacer = ' '.repeat(indent);
|
|
126
|
-
const ctx = await op.context(cfg);
|
|
127
|
-
const title = color`${{ title: op.title }} ${ctx}`;
|
|
128
|
-
const width = Math.max(title.replace(/\x1b\[\d+m/g, '').length, 50); // eslint-disable-line
|
|
129
|
-
|
|
130
|
-
let i = 0;
|
|
131
|
-
function stdout(msg?: string): void {
|
|
132
|
-
if (i++ > 0) {
|
|
133
|
-
process.stdout.write(color`${spacer}${{ param: 'done' }}\n`);
|
|
134
|
-
}
|
|
135
|
-
if (msg) {
|
|
136
|
-
process.stdout.write(color`${spacer}${{ output: '᳁' }} ${{ path: msg.padEnd(width - 15) }} ... `);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async function runPhase(phase: 'preProcess' | 'postProcess'): Promise<void> {
|
|
141
|
-
for (const el of cfg[phase] ?? []) {
|
|
142
|
-
const [name, fn] = Object.entries(el)[0];
|
|
143
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
144
|
-
await stdout(name as string);
|
|
145
|
-
await fn(cfg);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
let message: string | undefined;
|
|
150
|
-
|
|
151
|
-
process.stdout.write(`${spacer}${title}\n`);
|
|
152
|
-
process.stdout.write(`${spacer}${'-'.repeat(width)}\n`);
|
|
153
|
-
|
|
154
|
-
await runPhase('preProcess');
|
|
155
|
-
|
|
156
|
-
for await (const msg of op.exec(cfg)) {
|
|
157
|
-
if (msg.includes('Success')) { // We are done
|
|
158
|
-
message = msg;
|
|
159
|
-
break;
|
|
160
|
-
} else {
|
|
161
|
-
stdout(msg);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
await runPhase('postProcess');
|
|
166
|
-
|
|
167
|
-
// Wrap up
|
|
168
|
-
stdout();
|
|
169
|
-
|
|
170
|
-
if (message !== undefined) {
|
|
171
|
-
process.stdout.write(`${spacer}${'-'.repeat(width)}\n`);
|
|
172
|
-
process.stdout.write(`${spacer}${message}\n`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { FsUtil, PathUtil } from '@travetto/boot';
|
|
2
|
-
import { color } from '@travetto/cli/src/color';
|
|
3
|
-
import { CliUtil } from '@travetto/cli/src/util';
|
|
4
|
-
|
|
5
|
-
import { PackUtil } from '../lib/util';
|
|
6
|
-
import { CommonConfig, PackOperation } from '../lib/types';
|
|
7
|
-
import { AssembleUtil } from '../lib/assemble';
|
|
8
|
-
|
|
9
|
-
export interface AssembleConfig extends CommonConfig {
|
|
10
|
-
keepSource: boolean;
|
|
11
|
-
readonly: boolean;
|
|
12
|
-
cacheDir: string;
|
|
13
|
-
add: Record<string, string>[];
|
|
14
|
-
exclude: string[];
|
|
15
|
-
excludeCompile: string[];
|
|
16
|
-
env: Record<string, string | undefined>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Utils for packing source code and minimizing space usage
|
|
21
|
-
*/
|
|
22
|
-
export const Assemble: PackOperation<AssembleConfig, 'assemble'> = {
|
|
23
|
-
key: 'assemble',
|
|
24
|
-
title: 'Assembling',
|
|
25
|
-
context(cfg: AssembleConfig) {
|
|
26
|
-
return `[readonly=${cfg.readonly},cache=${cfg.cacheDir},source=${cfg.keepSource}]`;
|
|
27
|
-
},
|
|
28
|
-
overrides: {
|
|
29
|
-
keepSource: CliUtil.toBool(process.env.PACK_ASSEMBLE_KEEP_SOURCE),
|
|
30
|
-
readonly: CliUtil.toBool(process.env.PACK_ASSEMBLE_READONLY)
|
|
31
|
-
},
|
|
32
|
-
extend(src: Partial<AssembleConfig>, dest: Partial<AssembleConfig>): Partial<AssembleConfig> {
|
|
33
|
-
return {
|
|
34
|
-
keepSource: src.keepSource ?? dest.keepSource,
|
|
35
|
-
readonly: src.readonly ?? dest.readonly,
|
|
36
|
-
cacheDir: src.cacheDir ?? dest.cacheDir,
|
|
37
|
-
add: [...(src.add ?? []), ...(dest.add ?? [])],
|
|
38
|
-
exclude: [...(src.exclude ?? []), ...(dest.exclude ?? [])],
|
|
39
|
-
excludeCompile: [...(src.excludeCompile ?? []), ...(dest.excludeCompile ?? [])],
|
|
40
|
-
env: { ...(src.env ?? {}), ...(dest.env ?? {}) },
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
buildConfig(configs: Partial<AssembleConfig>[]): AssembleConfig {
|
|
44
|
-
return PackUtil.buildConfig(this, configs);
|
|
45
|
-
},
|
|
46
|
-
/**
|
|
47
|
-
* Assemble the project into a workspace directory, optimized for space and runtime
|
|
48
|
-
*/
|
|
49
|
-
async * exec({ workspace, cacheDir, add, exclude, excludeCompile, env, keepSource, readonly }: AssembleConfig) {
|
|
50
|
-
const fullCacheDir = PathUtil.resolveUnix(workspace!, cacheDir);
|
|
51
|
-
const ws = PathUtil.resolveUnix(workspace!);
|
|
52
|
-
|
|
53
|
-
yield 'Cleaning Workspace'; await FsUtil.unlinkRecursive(ws).then(() => { });
|
|
54
|
-
yield 'Copying Dependencies'; await AssembleUtil.copyDependencies(ws);
|
|
55
|
-
yield 'Copying App Content'; await AssembleUtil.copyModule(PathUtil.cwd, ws);
|
|
56
|
-
yield 'Excluding Pre-Compile Files'; await AssembleUtil.excludeFiles(ws, excludeCompile);
|
|
57
|
-
yield 'Building'; await AssembleUtil.buildWorkspace(ws, cacheDir);
|
|
58
|
-
yield 'Excluding Post-Compile Files'; await AssembleUtil.excludeFiles(ws, exclude);
|
|
59
|
-
yield 'Copying Added Content'; await AssembleUtil.copyAddedContent(ws, add);
|
|
60
|
-
yield 'Removing Empty Folders'; await PackUtil.removeEmptyFolders(ws);
|
|
61
|
-
yield 'Writing Env.js'; await PackUtil.writeEnvJs(ws, {
|
|
62
|
-
...env,
|
|
63
|
-
TRV_CACHE: `\${__dirname}/${cacheDir}`,
|
|
64
|
-
...(readonly ? { TRV_READONLY: '1' } : {})
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
if (!keepSource) {
|
|
68
|
-
yield 'Clean Boot'; await AssembleUtil.cleanBoot(ws);
|
|
69
|
-
yield 'Remove Source Maps'; await AssembleUtil.cleanCache(fullCacheDir);
|
|
70
|
-
yield 'Emptying .ts Files'; await AssembleUtil.purgeSource([`${ws}/node_modules/@travetto`, `${ws}/src`]);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
yield color`${{ success: 'Successfully' }} assembled project at ${{ path: workspace }}`;
|
|
74
|
-
}
|
|
75
|
-
};
|
package/bin/operation/docker.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
|
|
3
|
-
import { ExecUtil, Package, PathUtil } from '@travetto/boot';
|
|
4
|
-
import { color } from '@travetto/cli/src/color';
|
|
5
|
-
import { CliUtil } from '@travetto/cli/src/util';
|
|
6
|
-
|
|
7
|
-
import { CommonConfig, PackOperation } from '../lib/types';
|
|
8
|
-
import { PackUtil } from '../lib/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 ["node", "./node_modules/@travetto/cli/bin/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: Package.name.replace('@', ''),
|
|
39
|
-
builder: dockerFileBuilder,
|
|
40
|
-
port: [],
|
|
41
|
-
tag: ['latest']
|
|
42
|
-
},
|
|
43
|
-
overrides: {
|
|
44
|
-
image: process.env.PACK_DOCKER_IMAGE || undefined,
|
|
45
|
-
name: process.env.PACK_DOCKER_NAME || undefined,
|
|
46
|
-
app: process.env.PACK_DOCKER_APP || undefined,
|
|
47
|
-
port: process.env.PACK_DOCKER_PORT ? [process.env.PACK_DOCKER_PORT] : undefined,
|
|
48
|
-
registry: process.env.PACK_DOCKER_REGISTRY || undefined,
|
|
49
|
-
push: CliUtil.toBool(process.env.PACK_DOCKER_PUSH),
|
|
50
|
-
tag: process.env.PACK_DOCKER_TAG ? [process.env.PACK_DOCKER_TAG] : undefined
|
|
51
|
-
},
|
|
52
|
-
extend(src: Partial<DockerConfig>, dest: Partial<DockerConfig>): Partial<DockerConfig> {
|
|
53
|
-
return {
|
|
54
|
-
image: src.image ?? dest.image,
|
|
55
|
-
app: src.app ?? dest.app,
|
|
56
|
-
name: src.name ?? dest.name,
|
|
57
|
-
builder: src.builder ?? dest.builder,
|
|
58
|
-
tag: src.tag ?? dest.tag,
|
|
59
|
-
port: src.port ?? dest.port,
|
|
60
|
-
registry: src.registry ?? dest.registry,
|
|
61
|
-
env: { ...(src.env ?? {}), ...(dest.env ?? {}) },
|
|
62
|
-
push: src.push ?? dest.push
|
|
63
|
-
};
|
|
64
|
-
},
|
|
65
|
-
buildConfig(configs: Partial<DockerConfig>[]): DockerConfig {
|
|
66
|
-
return PackUtil.buildConfig(this, configs);
|
|
67
|
-
},
|
|
68
|
-
/**
|
|
69
|
-
* Dockerize workspace with flags
|
|
70
|
-
*/
|
|
71
|
-
async* exec(cfg: DockerConfig) {
|
|
72
|
-
const { builder, workspace, push, image, tag, name, registry } = cfg;
|
|
73
|
-
|
|
74
|
-
const ws = PathUtil.resolveUnix(workspace);
|
|
75
|
-
|
|
76
|
-
yield 'Building Dockerfile';
|
|
77
|
-
|
|
78
|
-
await fs.writeFile(PathUtil.resolveUnix(ws, 'Dockerfile'), builder!(cfg), { encoding: 'utf8' });
|
|
79
|
-
|
|
80
|
-
yield 'Pulling Base Image';
|
|
81
|
-
await ExecUtil.spawn('docker', ['pull', image]).result;
|
|
82
|
-
|
|
83
|
-
yield 'Building Docker Container';
|
|
84
|
-
const tags = tag.map(x => registry ? `${registry}/${name}:${x}` : `${name}:${x}`);
|
|
85
|
-
const args = ['build', ...tags.flatMap(x => ['-t', x]), '.'];
|
|
86
|
-
|
|
87
|
-
await ExecUtil.spawn('docker', args, { cwd: ws, stdio: [0, 'pipe', 2] }).result;
|
|
88
|
-
|
|
89
|
-
if (push) {
|
|
90
|
-
yield 'Pushing Tags';
|
|
91
|
-
await ExecUtil.spawn('docker', ['image', 'push', ...tags]).result;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
yield color`${{ success: 'Successfully' }} containerized project`;
|
|
95
|
-
}
|
|
96
|
-
};
|
package/bin/operation/pack.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { color } from '@travetto/cli/src/color';
|
|
2
|
-
|
|
3
|
-
import { CommonConfig, PackOperation } from '../lib/types';
|
|
4
|
-
import { PackUtil } from '../lib/util';
|
|
5
|
-
import { Assemble, AssembleConfig } from './assemble';
|
|
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 color`${{ success: 'Successfully' }} packed project`;
|
|
68
|
-
}
|
|
69
|
-
};
|
package/bin/operation/zip.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import * as fs from 'fs/promises';
|
|
3
|
-
|
|
4
|
-
import { ExecUtil, FsUtil, PathUtil } from '@travetto/boot';
|
|
5
|
-
import { color } from '@travetto/cli/src/color';
|
|
6
|
-
|
|
7
|
-
import { CommonConfig, PackOperation } from '../lib/types';
|
|
8
|
-
import { PackUtil } from '../lib/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 = PathUtil.resolveUnix(workspace);
|
|
34
|
-
const zipFile = PathUtil.resolveUnix(output);
|
|
35
|
-
|
|
36
|
-
yield 'Preparing Target';
|
|
37
|
-
await fs.mkdir(path.dirname(zipFile), { recursive: true });
|
|
38
|
-
if (await FsUtil.exists(zipFile)) {
|
|
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 color`${{ success: 'Successfully' }} archived project to ${{ path: zipFile.replace(PathUtil.cwd, '.') }}`;
|
|
50
|
-
}
|
|
51
|
-
};
|
package/bin/pack-base.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import * as os from 'os';
|
|
2
|
-
|
|
3
|
-
import { CliCommand, OptionConfig } from '@travetto/cli/src/command';
|
|
4
|
-
import { color } from '@travetto/cli/src/color';
|
|
5
|
-
import { PathUtil, Package, FsUtil } from '@travetto/boot';
|
|
6
|
-
|
|
7
|
-
import { PackUtil } from './lib/util';
|
|
8
|
-
import { CommonConfig, PackOperation } from './lib/types';
|
|
9
|
-
|
|
10
|
-
const packName = `pack_${Package.name}`
|
|
11
|
-
.toLowerCase()
|
|
12
|
-
.replace(/[^a-z]+/g, '_')
|
|
13
|
-
.replace(/_+/g, '_');
|
|
14
|
-
|
|
15
|
-
export type BaseOptions = {
|
|
16
|
-
workspace: OptionConfig<string>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
function getConfigFromOperationOrGlobal<C extends CommonConfig, K extends string>(key: K, config: Partial<C> | Record<K, Partial<C>> | undefined): Partial<C> | undefined {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
21
|
-
return !config ? config : (key && key in config ? (config as Record<K, C>)[key] : config) as C;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Supports packing a project into a directory, ready for archiving
|
|
26
|
-
*/
|
|
27
|
-
export abstract class BasePackCommand<V extends BaseOptions, C extends CommonConfig, K extends string> extends CliCommand<V> {
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Package stage name
|
|
31
|
-
*/
|
|
32
|
-
abstract get operation(): PackOperation<C, K>;
|
|
33
|
-
|
|
34
|
-
get cmdOptions(): Partial<C> {
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
36
|
-
return this.cmd as Partial<C>;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get name(): string {
|
|
40
|
-
return this.operation.key ? `pack:${this.operation.key}` : 'pack';
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
commonOptions(): BaseOptions {
|
|
44
|
-
return { workspace: this.option({ desc: 'Working directory' }) } as const;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async resolveConfigs(): Promise<C> {
|
|
48
|
-
const list = (await PackUtil.modeList());
|
|
49
|
-
if (!this.args[0]) {
|
|
50
|
-
this.showHelp('Missing config mode');
|
|
51
|
-
}
|
|
52
|
-
const cfg = list.find(c => c.name === this.args[0]);
|
|
53
|
-
if (!cfg) {
|
|
54
|
-
this.showHelp(`Unknown config mode: ${this.args[0]}`);
|
|
55
|
-
}
|
|
56
|
-
const def = list.find(c => c.name === 'default');
|
|
57
|
-
|
|
58
|
-
const configs = [
|
|
59
|
-
{ workspace: PathUtil.resolveUnix(os.tmpdir(), packName) },
|
|
60
|
-
def,
|
|
61
|
-
cfg,
|
|
62
|
-
this.cmdOptions,
|
|
63
|
-
{ active: true }
|
|
64
|
-
]
|
|
65
|
-
.map(x => getConfigFromOperationOrGlobal(this.operation.key, x))
|
|
66
|
-
.filter((x): x is C => x !== undefined);
|
|
67
|
-
|
|
68
|
-
return this.operation.buildConfig(configs);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
getArgs(): string {
|
|
72
|
-
return '[mode]';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async help(): Promise<string> {
|
|
76
|
-
const lines = await PackUtil.modeList();
|
|
77
|
-
|
|
78
|
-
const out: string[] = [];
|
|
79
|
-
if (lines.length) {
|
|
80
|
-
out.push('', color`${{ title: 'Available Pack Modes:' }}`);
|
|
81
|
-
for (const { name, file } of lines) {
|
|
82
|
-
out.push(color` * ${{ input: `${name}` }} [${{ path: file }}]`);
|
|
83
|
-
}
|
|
84
|
-
out.push('');
|
|
85
|
-
}
|
|
86
|
-
return out.join('\n');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
override async complete(): Promise<Record<string, string[]>> {
|
|
90
|
-
return { '': (await PackUtil.modeList()).map(x => x.name!) };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async action(): Promise<void> {
|
|
94
|
-
const resolved = await this.resolveConfigs();
|
|
95
|
-
if (await FsUtil.exists(PathUtil.resolveUnix(resolved.workspace, '.git'))) {
|
|
96
|
-
throw new Error('Refusing to use workspace with a .git directory');
|
|
97
|
-
}
|
|
98
|
-
return PackUtil.runOperation(this.operation, resolved);
|
|
99
|
-
}
|
|
100
|
-
}
|