@travetto/pack 3.0.0-rc.2 → 3.0.0-rc.5
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 +5 -0
- package/package.json +9 -9
- package/support/bin/assemble/operation.ts +59 -0
- package/support/bin/assemble/util.ts +139 -0
- package/{bin/operation → support/bin}/docker.ts +19 -18
- package/{bin/operation → support/bin}/pack.ts +5 -5
- package/{bin/lib → support/bin}/types.ts +0 -0
- package/{bin/lib → support/bin}/util.ts +35 -32
- package/{bin/operation → support/bin}/zip.ts +10 -10
- package/{bin/pack-base.ts → support/cli.pack-base.ts} +24 -27
- package/{bin/cli-pack.ts → support/cli.pack.ts} +3 -3
- package/{bin/cli-pack_assemble.ts → support/cli.pack_assemble.ts} +4 -4
- package/{bin/cli-pack_docker-export.ts → support/cli.pack_docker-export.ts} +7 -6
- package/{bin/cli-pack_docker.ts → support/cli.pack_docker.ts} +4 -4
- package/{bin/cli-pack_zip.ts → support/cli.pack_zip.ts} +4 -4
- package/support/pack.config.ts +2 -8
- package/bin/lib/assemble.ts +0 -151
- package/bin/lib/dependencies.ts +0 -103
- package/bin/operation/assemble.ts +0 -75
- package/index.d.ts +0 -5
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Assemble is the operation that stages the project's code for deployment. The as
|
|
|
40
40
|
|
|
41
41
|
1. Cleaning Workspace - Cleans workspace to start with an empty workspace
|
|
42
42
|
1. Copying Dependencies - Computes the prod dependencies and copies them into the new workspace
|
|
43
|
-
1. Copying App Content - Copies over application content (src
|
|
43
|
+
1. Copying App Content - Copies over application content (src/, resources/, support/, bin/)
|
|
44
44
|
1. Excluding Pre-Compile Files - Any files that should be excluded pre-compilation, are removed
|
|
45
45
|
1. Compiling - Compiles the code in the new workspace, isolating it from your local development
|
|
46
46
|
1. Excluding Post-Compile Files - Removes any files that should be excluded, post compilation
|
package/__index__.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { AllConfig, AllConfigPartial } from './support/bin/pack';
|
|
2
|
+
export type { CommonConfig } from './support/bin/types';
|
|
3
|
+
export type { AssembleConfig } from './support/bin/assemble/operation';
|
|
4
|
+
export type { ZipConfig } from './support/bin/zip';
|
|
5
|
+
export type { DockerConfig } from './support/bin/docker';
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/pack",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.2",
|
|
3
|
+
"version": "3.0.0-rc.5",
|
|
5
4
|
"description": "Code packing utilities",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"travetto",
|
|
@@ -16,8 +15,7 @@
|
|
|
16
15
|
"name": "Travetto Framework"
|
|
17
16
|
},
|
|
18
17
|
"files": [
|
|
19
|
-
"
|
|
20
|
-
"bin",
|
|
18
|
+
"__index__.ts",
|
|
21
19
|
"support"
|
|
22
20
|
],
|
|
23
21
|
"repository": {
|
|
@@ -25,21 +23,23 @@
|
|
|
25
23
|
"directory": "module/pack"
|
|
26
24
|
},
|
|
27
25
|
"dependencies": {
|
|
28
|
-
"@travetto/base": "^3.0.0-rc.
|
|
26
|
+
"@travetto/base": "^3.0.0-rc.5",
|
|
29
27
|
"@types/picomatch": "^2.3.0",
|
|
30
28
|
"picomatch": "^2.3.1"
|
|
31
29
|
},
|
|
32
30
|
"peerDependencies": {
|
|
33
|
-
"@travetto/cli": "^3.0.0-rc.
|
|
31
|
+
"@travetto/cli": "^3.0.0-rc.5"
|
|
34
32
|
},
|
|
35
33
|
"peerDependenciesMeta": {
|
|
36
34
|
"@travetto/cli": {
|
|
37
35
|
"optional": true
|
|
38
36
|
}
|
|
39
37
|
},
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
38
|
+
"travetto": {
|
|
39
|
+
"displayName": "Pack",
|
|
40
|
+
"profiles": [
|
|
41
|
+
"build"
|
|
42
|
+
]
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
|
|
3
|
+
import { path } from '@travetto/manifest';
|
|
4
|
+
import { cliTpl } from '@travetto/cli';
|
|
5
|
+
import { Env } from '@travetto/base';
|
|
6
|
+
|
|
7
|
+
import { PackUtil } from '../util';
|
|
8
|
+
import { CommonConfig, PackOperation } from '../types';
|
|
9
|
+
import { AssembleUtil } from './util';
|
|
10
|
+
export interface AssembleConfig extends CommonConfig {
|
|
11
|
+
keepSource: boolean;
|
|
12
|
+
readonly: boolean;
|
|
13
|
+
add: Record<string, string>[];
|
|
14
|
+
exclude: string[];
|
|
15
|
+
env: Record<string, string | undefined>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Utils for packing source code and minimizing space usage
|
|
20
|
+
*/
|
|
21
|
+
export const Assemble: PackOperation<AssembleConfig, 'assemble'> = {
|
|
22
|
+
key: 'assemble',
|
|
23
|
+
title: 'Assembling',
|
|
24
|
+
context(cfg: AssembleConfig) {
|
|
25
|
+
return `[readonly=${cfg.readonly},source=${cfg.keepSource}]`;
|
|
26
|
+
},
|
|
27
|
+
overrides: {
|
|
28
|
+
keepSource: Env.getBoolean('PACK_ASSEMBLE_KEEP_SOURCE'),
|
|
29
|
+
readonly: Env.getBoolean('PACK_ASSEMBLE_READONLY')
|
|
30
|
+
},
|
|
31
|
+
extend(src: Partial<AssembleConfig>, dest: Partial<AssembleConfig>): Partial<AssembleConfig> {
|
|
32
|
+
return {
|
|
33
|
+
keepSource: src.keepSource ?? dest.keepSource,
|
|
34
|
+
readonly: src.readonly ?? dest.readonly,
|
|
35
|
+
add: [...(src.add ?? []), ...(dest.add ?? [])],
|
|
36
|
+
exclude: [...(src.exclude ?? []), ...(dest.exclude ?? [])],
|
|
37
|
+
env: { ...(src.env ?? {}), ...(dest.env ?? {}) },
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
buildConfig(configs: Partial<AssembleConfig>[]): AssembleConfig {
|
|
41
|
+
return PackUtil.buildConfig(this, configs);
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* Assemble the project into a workspace directory, optimized for space and runtime
|
|
45
|
+
*/
|
|
46
|
+
async * exec({ workspace, add, exclude, env, keepSource }: AssembleConfig) {
|
|
47
|
+
const ws = path.resolve(workspace!);
|
|
48
|
+
yield 'Cleaning Workspace'; {
|
|
49
|
+
await fs.rm(ws, { recursive: true, force: true }).catch(() => { });
|
|
50
|
+
await fs.mkdir(ws);
|
|
51
|
+
}
|
|
52
|
+
yield 'Create Entrypoint'; await AssembleUtil.copyEntryPoint(ws);
|
|
53
|
+
yield 'Copying Prod Dependencies'; await AssembleUtil.copyProdDependencies(ws, keepSource);
|
|
54
|
+
yield 'Excluding Files'; await AssembleUtil.excludeFiles(ws, exclude);
|
|
55
|
+
yield 'Copying Added Content'; await AssembleUtil.copyAddedContent(ws, add);
|
|
56
|
+
yield 'Removing Empty Folders'; await AssembleUtil.removeEmptyFolders(ws);
|
|
57
|
+
yield cliTpl`${{ success: 'Successfully' }} assembled project at ${{ path: workspace }}`;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
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,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
4
|
+
import { Env, ExecUtil } from '@travetto/base';
|
|
5
|
+
import { cliTpl } from '@travetto/cli';
|
|
6
6
|
|
|
7
|
-
import { CommonConfig, PackOperation } from '
|
|
8
|
-
import { PackUtil } from '
|
|
7
|
+
import { CommonConfig, PackOperation } from './types';
|
|
8
|
+
import { PackUtil } from './util';
|
|
9
9
|
|
|
10
10
|
export interface DockerConfig extends CommonConfig {
|
|
11
11
|
image: string;
|
|
@@ -25,7 +25,7 @@ WORKDIR /app
|
|
|
25
25
|
COPY . .
|
|
26
26
|
${Object.entries(env).map(([k, v]) => `ENV ${k} "${v}"`).join('\n')}
|
|
27
27
|
${(port ?? []).map(x => `EXPOSE ${x}`).join('\n')}
|
|
28
|
-
CMD ["
|
|
28
|
+
CMD ["./trv", "run", "${app}"]
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
31
|
export const Docker: PackOperation<DockerConfig, 'docker'> = {
|
|
@@ -35,19 +35,20 @@ export const Docker: PackOperation<DockerConfig, 'docker'> = {
|
|
|
35
35
|
return `[image=${cfg.image}, port=${cfg.port}]`;
|
|
36
36
|
},
|
|
37
37
|
defaults: {
|
|
38
|
-
name:
|
|
38
|
+
name: RootIndex.mainPackage.name.replace('@', ''),
|
|
39
|
+
image: 'node:18-alpine3.16',
|
|
39
40
|
builder: dockerFileBuilder,
|
|
40
41
|
port: [],
|
|
41
42
|
tag: ['latest']
|
|
42
43
|
},
|
|
43
44
|
overrides: {
|
|
44
|
-
image:
|
|
45
|
-
name:
|
|
46
|
-
app:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
tag:
|
|
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')
|
|
51
52
|
},
|
|
52
53
|
extend(src: Partial<DockerConfig>, dest: Partial<DockerConfig>): Partial<DockerConfig> {
|
|
53
54
|
return {
|
|
@@ -71,11 +72,11 @@ export const Docker: PackOperation<DockerConfig, 'docker'> = {
|
|
|
71
72
|
async* exec(cfg: DockerConfig) {
|
|
72
73
|
const { builder, workspace, push, image, tag, name, registry } = cfg;
|
|
73
74
|
|
|
74
|
-
const ws =
|
|
75
|
+
const ws = path.resolve(workspace);
|
|
75
76
|
|
|
76
77
|
yield 'Building Dockerfile';
|
|
77
78
|
|
|
78
|
-
await fs.writeFile(
|
|
79
|
+
await fs.writeFile(path.resolve(ws, 'Dockerfile'), builder!(cfg), { encoding: 'utf8' });
|
|
79
80
|
|
|
80
81
|
yield 'Pulling Base Image';
|
|
81
82
|
await ExecUtil.spawn('docker', ['pull', image]).result;
|
|
@@ -91,6 +92,6 @@ export const Docker: PackOperation<DockerConfig, 'docker'> = {
|
|
|
91
92
|
await ExecUtil.spawn('docker', ['image', 'push', ...tags]).result;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
yield
|
|
95
|
+
yield cliTpl`${{ success: 'Successfully' }} containerized project`;
|
|
95
96
|
}
|
|
96
97
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cliTpl } from '@travetto/cli';
|
|
2
2
|
|
|
3
|
-
import { CommonConfig, PackOperation } from '
|
|
4
|
-
import { PackUtil } from '
|
|
5
|
-
import { Assemble, AssembleConfig } from './assemble';
|
|
3
|
+
import { CommonConfig, PackOperation } from './types';
|
|
4
|
+
import { PackUtil } from './util';
|
|
5
|
+
import { Assemble, AssembleConfig } from './assemble/operation';
|
|
6
6
|
import { Docker, DockerConfig } from './docker';
|
|
7
7
|
import { Zip, ZipConfig } from './zip';
|
|
8
8
|
|
|
@@ -64,6 +64,6 @@ export const Pack: PackOperation<AllConfig, ''> = {
|
|
|
64
64
|
await PackUtil.runOperation(op, cfg[step], 2);
|
|
65
65
|
}
|
|
66
66
|
process.stdout.write('\n');
|
|
67
|
-
yield
|
|
67
|
+
yield cliTpl`${{ success: 'Successfully' }} packed project`;
|
|
68
68
|
}
|
|
69
69
|
};
|
|
File without changes
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as path from 'path';
|
|
1
|
+
import fs from 'fs/promises';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const glob = require('picomatch');
|
|
3
|
+
import glob from 'picomatch';
|
|
6
4
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
6
|
+
import { cliTpl } from '@travetto/cli';
|
|
7
|
+
import { ExecUtil } from '@travetto/base';
|
|
8
|
+
import { stripAnsiCodes } from '@travetto/terminal';
|
|
10
9
|
|
|
11
10
|
import { CommonConfig, PackOperation } from './types';
|
|
12
11
|
|
|
@@ -51,10 +50,10 @@ export class PackUtil {
|
|
|
51
50
|
static async modeList(): Promise<Partial<CommonConfig>[]> {
|
|
52
51
|
if (!this.#modes) {
|
|
53
52
|
this.#modes = await Promise.all(
|
|
54
|
-
|
|
53
|
+
RootIndex.findSupport({ filter: f => /\/pack[.].*[.]/.test(f) })
|
|
55
54
|
.map(async (x) => {
|
|
56
|
-
const req: Partial<CommonConfig> = (await import(x.
|
|
57
|
-
req.file = x.
|
|
55
|
+
const req: Partial<CommonConfig> = (await import(x.output)).config;
|
|
56
|
+
req.file = x.import.replace(/^node_modules\//, '');
|
|
58
57
|
return req;
|
|
59
58
|
})
|
|
60
59
|
);
|
|
@@ -71,14 +70,14 @@ export class PackUtil {
|
|
|
71
70
|
const negate = x.startsWith('!') || x.startsWith('^');
|
|
72
71
|
x = negate ? x.substring(1) : x;
|
|
73
72
|
x = x.replace(/^[.][/]/g, `${base}/`);
|
|
74
|
-
const match: (f: string) => boolean = glob(x, { nocase: true, dot: true, basename:
|
|
73
|
+
const match: (f: string) => boolean = glob(x, { nocase: true, dot: true, basename: true, contains: true, cwd: base });
|
|
75
74
|
Object.defineProperty(match, 'source', { value: x });
|
|
76
75
|
return [match, negate] as const;
|
|
77
76
|
});
|
|
78
77
|
|
|
79
78
|
return (f: string): boolean => {
|
|
80
79
|
let exclude = undefined;
|
|
81
|
-
f =
|
|
80
|
+
f = path.resolve(base, f);
|
|
82
81
|
for (const [match, n] of all) {
|
|
83
82
|
if ((n || exclude === undefined) && match(f)) {
|
|
84
83
|
if (n) { // Fast exit if negating
|
|
@@ -95,27 +94,14 @@ export class PackUtil {
|
|
|
95
94
|
* Update .env.js with new env data
|
|
96
95
|
*/
|
|
97
96
|
static async writeEnvJs(workspace: string, env: Record<string, string | undefined>): Promise<void> {
|
|
98
|
-
const out =
|
|
97
|
+
const out = path.resolve(workspace, '.env.js');
|
|
99
98
|
let src = '';
|
|
100
|
-
if (!!(await
|
|
99
|
+
if (!!(await fs.stat(out).catch(() => { }))) {
|
|
101
100
|
src = await fs.readFile(out, 'utf8');
|
|
102
101
|
}
|
|
103
102
|
const lines = Object.entries(env).map(([k, v]) => v ? `process.env['${k}'] = \`${v.replace(/`/g, '\\`')}\`;` : '');
|
|
104
103
|
const content = `${src}\n${lines.join('\n')}`;
|
|
105
|
-
await fs.writeFile(
|
|
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
|
-
}
|
|
104
|
+
await fs.writeFile(out, content, { encoding: 'utf8' });
|
|
119
105
|
}
|
|
120
106
|
|
|
121
107
|
/**
|
|
@@ -124,16 +110,16 @@ export class PackUtil {
|
|
|
124
110
|
static async runOperation<T extends CommonConfig>(op: PackOperation<T, string>, cfg: T, indent = 0): Promise<void> {
|
|
125
111
|
const spacer = ' '.repeat(indent);
|
|
126
112
|
const ctx = await op.context(cfg);
|
|
127
|
-
const title =
|
|
128
|
-
const width = Math.max(title
|
|
113
|
+
const title = cliTpl`${{ title: op.title }} ${ctx}`;
|
|
114
|
+
const width = Math.max(stripAnsiCodes(title).length, 50); // eslint-disable-line
|
|
129
115
|
|
|
130
116
|
let i = 0;
|
|
131
117
|
function stdout(msg?: string): void {
|
|
132
118
|
if (i++ > 0) {
|
|
133
|
-
process.stdout.write(
|
|
119
|
+
process.stdout.write(cliTpl`${spacer}${{ param: 'done' }}\n`);
|
|
134
120
|
}
|
|
135
121
|
if (msg) {
|
|
136
|
-
process.stdout.write(
|
|
122
|
+
process.stdout.write(cliTpl`${spacer}${{ output: '᳁' }} ${{ path: msg.padEnd(width - 15) }} ... `);
|
|
137
123
|
}
|
|
138
124
|
}
|
|
139
125
|
|
|
@@ -172,4 +158,21 @@ export class PackUtil {
|
|
|
172
158
|
process.stdout.write(`${spacer}${message}\n`);
|
|
173
159
|
}
|
|
174
160
|
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Remove directory, determine if errors should be ignored
|
|
164
|
+
* @param src The folder to copy
|
|
165
|
+
* @param dest The folder to copy to
|
|
166
|
+
* @param ignore Should errors be ignored
|
|
167
|
+
*/
|
|
168
|
+
static async copyRecursive(src: string, dest: string, ignore = false): Promise<void> {
|
|
169
|
+
const [cmd, args] = process.platform === 'win32' ?
|
|
170
|
+
['xcopy', ['/y', '/h', '/s', path.toNative(src), path.toNative(dest)]] :
|
|
171
|
+
['cp', ['-r', '-p', src, dest]];
|
|
172
|
+
|
|
173
|
+
const res = await ExecUtil.spawn(cmd, args, { catchAsResult: true }).result;
|
|
174
|
+
if (res.code && !ignore) {
|
|
175
|
+
throw new Error(`Failed to copy ${src} to ${dest}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
175
178
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as fs from 'fs/promises';
|
|
1
|
+
import fs from 'fs/promises';
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { path } from '@travetto/manifest';
|
|
4
|
+
import { ExecUtil } from '@travetto/base';
|
|
5
|
+
import { cliTpl } from '@travetto/cli';
|
|
6
6
|
|
|
7
|
-
import { CommonConfig, PackOperation } from '
|
|
8
|
-
import { PackUtil } from '
|
|
7
|
+
import { CommonConfig, PackOperation } from './types';
|
|
8
|
+
import { PackUtil } from './util';
|
|
9
9
|
|
|
10
10
|
export interface ZipConfig extends CommonConfig {
|
|
11
11
|
output: string;
|
|
@@ -30,12 +30,12 @@ export const Zip: PackOperation<ZipConfig, 'zip'> = {
|
|
|
30
30
|
* Zip workspace with flags
|
|
31
31
|
*/
|
|
32
32
|
async * exec({ workspace, output }: ZipConfig) {
|
|
33
|
-
const ws =
|
|
34
|
-
const zipFile =
|
|
33
|
+
const ws = path.resolve(workspace);
|
|
34
|
+
const zipFile = path.resolve(output);
|
|
35
35
|
|
|
36
36
|
yield 'Preparing Target';
|
|
37
37
|
await fs.mkdir(path.dirname(zipFile), { recursive: true });
|
|
38
|
-
if (await
|
|
38
|
+
if (await fs.stat(zipFile).catch(() => { })) {
|
|
39
39
|
await fs.unlink(zipFile); // Unlink
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -46,6 +46,6 @@ export const Zip: PackOperation<ZipConfig, 'zip'> = {
|
|
|
46
46
|
await ExecUtil.spawn('zip', ['-r', zipFile, '.'], { cwd: ws }).result;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
yield
|
|
49
|
+
yield cliTpl`${{ success: 'Successfully' }} archived project to ${{ path: zipFile.replace(path.cwd(), '.') }}`;
|
|
50
50
|
}
|
|
51
51
|
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import os from 'os';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { PathUtil, Package, FsUtil } from '@travetto/boot';
|
|
3
|
+
import { path, RootIndex } from '@travetto/manifest';
|
|
4
|
+
import { CliCommand, CliScmUtil, cliTpl, OptionConfig } from '@travetto/cli';
|
|
6
5
|
|
|
7
|
-
import { PackUtil } from './
|
|
8
|
-
import { CommonConfig, PackOperation } from './
|
|
6
|
+
import { PackUtil } from './bin/util';
|
|
7
|
+
import { CommonConfig, PackOperation } from './bin/types';
|
|
9
8
|
|
|
10
|
-
const packName = `pack_${
|
|
9
|
+
const packName = `pack_${RootIndex.mainPackage.name}`
|
|
11
10
|
.toLowerCase()
|
|
12
11
|
.replace(/[^a-z]+/g, '_')
|
|
13
12
|
.replace(/_+/g, '_');
|
|
@@ -44,19 +43,9 @@ export abstract class BasePackCommand<V extends BaseOptions, C extends CommonCon
|
|
|
44
43
|
return { workspace: this.option({ desc: 'Working directory' }) } as const;
|
|
45
44
|
}
|
|
46
45
|
|
|
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
|
-
|
|
46
|
+
async resolveConfigs(cfg: Partial<CommonConfig>, def?: Partial<CommonConfig>): Promise<C> {
|
|
58
47
|
const configs = [
|
|
59
|
-
{ workspace:
|
|
48
|
+
{ workspace: path.resolve(os.tmpdir(), packName) },
|
|
60
49
|
def,
|
|
61
50
|
cfg,
|
|
62
51
|
this.cmdOptions,
|
|
@@ -77,22 +66,30 @@ export abstract class BasePackCommand<V extends BaseOptions, C extends CommonCon
|
|
|
77
66
|
|
|
78
67
|
const out: string[] = [];
|
|
79
68
|
if (lines.length) {
|
|
80
|
-
out.push('',
|
|
69
|
+
out.push('', cliTpl`${{ title: 'Available Pack Modes:' }}`);
|
|
81
70
|
for (const { name, file } of lines) {
|
|
82
|
-
out.push(
|
|
71
|
+
out.push(cliTpl` * ${{ input: `${name}` }} [${{ path: file }}]`);
|
|
83
72
|
}
|
|
84
73
|
out.push('');
|
|
85
74
|
}
|
|
86
75
|
return out.join('\n');
|
|
87
76
|
}
|
|
88
77
|
|
|
89
|
-
override async complete(): Promise<Record<string, string[]>> {
|
|
90
|
-
return { '': (await PackUtil.modeList()).map(x => x.name!) };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
78
|
async action(): Promise<void> {
|
|
94
|
-
|
|
95
|
-
|
|
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)) {
|
|
96
93
|
throw new Error('Refusing to use workspace with a .git directory');
|
|
97
94
|
}
|
|
98
95
|
return PackUtil.runOperation(this.operation, resolved);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BaseOptions, BasePackCommand } from './pack-base';
|
|
2
|
-
import { Pack, AllConfig } from './
|
|
1
|
+
import { BaseOptions, BasePackCommand } from './cli.pack-base';
|
|
2
|
+
import { Pack, AllConfig } from './bin/pack';
|
|
3
3
|
|
|
4
|
-
export class PackCommand extends BasePackCommand<BaseOptions, AllConfig> {
|
|
4
|
+
export class PackCommand extends BasePackCommand<BaseOptions, AllConfig, ''> {
|
|
5
5
|
operation = Pack;
|
|
6
6
|
|
|
7
7
|
getOptions(): BaseOptions {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { OptionConfig } from '@travetto/cli
|
|
1
|
+
import { OptionConfig } from '@travetto/cli';
|
|
2
2
|
|
|
3
|
-
import { BaseOptions, BasePackCommand } from './pack-base';
|
|
4
|
-
import { Assemble, AssembleConfig } from './
|
|
3
|
+
import { BaseOptions, BasePackCommand } from './cli.pack-base';
|
|
4
|
+
import { Assemble, AssembleConfig } from './bin/assemble/operation';
|
|
5
5
|
|
|
6
6
|
type Options = BaseOptions & {
|
|
7
7
|
keepSource: OptionConfig<boolean>;
|
|
8
8
|
readonly: OptionConfig<boolean>;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
export class PackAssembleCommand extends BasePackCommand<Options, AssembleConfig> {
|
|
11
|
+
export class PackAssembleCommand extends BasePackCommand<Options, AssembleConfig, 'assemble'> {
|
|
12
12
|
operation = Assemble;
|
|
13
13
|
|
|
14
14
|
getOptions(): Options {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
import { CliCommand, OptionConfig, ListOptionConfig } from '@travetto/cli
|
|
4
|
+
import { path } from '@travetto/manifest';
|
|
5
|
+
import { CliCommand, OptionConfig, ListOptionConfig } from '@travetto/cli';
|
|
5
6
|
|
|
6
7
|
type Options = {
|
|
7
8
|
app: OptionConfig<string>;
|
|
@@ -26,8 +27,8 @@ export class PackDockerExportCommand extends CliCommand<Options> {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
async action(...args: unknown[]): Promise<void> {
|
|
29
|
-
const files = ['src', 'bin', 'support', '
|
|
30
|
-
.filter(x =>
|
|
30
|
+
const files = ['src', 'bin', 'support', 'resource', 'package.json', 'package-lock.json', ...this.cmd.add]
|
|
31
|
+
.filter(x => existsSync(path.resolve(x)));
|
|
31
32
|
|
|
32
33
|
const content = `
|
|
33
34
|
FROM ${this.cmd.image} as build
|
|
@@ -42,7 +43,7 @@ COPY --from=build /app /app
|
|
|
42
43
|
EXPOSE ${this.cmd.port}
|
|
43
44
|
WORKDIR /app
|
|
44
45
|
ENV NODE_OPTIONS "--no-deprecation"
|
|
45
|
-
CMD ["
|
|
46
|
+
CMD ["./trv", "run", "${this.cmd.app}"]
|
|
46
47
|
`;
|
|
47
48
|
|
|
48
49
|
if (this.cmd.output === '-' || this.cmd.output === '/dev/stdout' || !this.cmd.output) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { OptionConfig, ListOptionConfig } from '@travetto/cli
|
|
1
|
+
import { OptionConfig, ListOptionConfig } from '@travetto/cli';
|
|
2
2
|
|
|
3
|
-
import { BaseOptions, BasePackCommand } from './pack-base';
|
|
4
|
-
import { Docker, DockerConfig } from './
|
|
3
|
+
import { BaseOptions, BasePackCommand } from './cli.pack-base';
|
|
4
|
+
import { Docker, DockerConfig } from './bin/docker';
|
|
5
5
|
|
|
6
6
|
type Options = BaseOptions & {
|
|
7
7
|
image: OptionConfig<string>;
|
|
@@ -12,7 +12,7 @@ type Options = BaseOptions & {
|
|
|
12
12
|
registry: OptionConfig<string>;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export class PackDockerCommand extends BasePackCommand<Options, DockerConfig> {
|
|
15
|
+
export class PackDockerCommand extends BasePackCommand<Options, DockerConfig, 'docker'> {
|
|
16
16
|
operation = Docker;
|
|
17
17
|
|
|
18
18
|
getOptions(): Options {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { OptionConfig } from '@travetto/cli
|
|
1
|
+
import { OptionConfig } from '@travetto/cli';
|
|
2
2
|
|
|
3
|
-
import { BaseOptions, BasePackCommand } from './pack-base';
|
|
4
|
-
import { Zip, ZipConfig } from './
|
|
3
|
+
import { BaseOptions, BasePackCommand } from './cli.pack-base';
|
|
4
|
+
import { Zip, ZipConfig } from './bin/zip';
|
|
5
5
|
|
|
6
6
|
type Options = BaseOptions & {
|
|
7
7
|
output: OptionConfig<string>;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export class PackZipCommand extends BasePackCommand<Options, ZipConfig> {
|
|
10
|
+
export class PackZipCommand extends BasePackCommand<Options, ZipConfig, 'zip'> {
|
|
11
11
|
operation = Zip;
|
|
12
12
|
|
|
13
13
|
getOptions(): Options {
|
package/support/pack.config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AllConfigPartial } from '
|
|
1
|
+
import { AllConfigPartial } from './bin/pack';
|
|
2
2
|
|
|
3
3
|
const mod = (f: string): string => `node_modules/${f}`;
|
|
4
4
|
|
|
@@ -6,7 +6,6 @@ export const config: AllConfigPartial = {
|
|
|
6
6
|
name: 'default',
|
|
7
7
|
assemble: {
|
|
8
8
|
active: true,
|
|
9
|
-
cacheDir: 'cache',
|
|
10
9
|
keepSource: true,
|
|
11
10
|
readonly: true,
|
|
12
11
|
env: {
|
|
@@ -16,11 +15,6 @@ export const config: AllConfigPartial = {
|
|
|
16
15
|
{ [mod('@travetto/cli/bin/trv.js')]: mod('.bin/trv') },
|
|
17
16
|
{ [mod('lodash/lodash.min.js')]: mod('lodash/lodash.js') },
|
|
18
17
|
],
|
|
19
|
-
excludeCompile: [
|
|
20
|
-
mod('@travetto/*/doc/'),
|
|
21
|
-
mod('@travetto/*/e2e/'),
|
|
22
|
-
mod('@travetto/*/test/'),
|
|
23
|
-
],
|
|
24
18
|
exclude: [
|
|
25
19
|
'bower.json',
|
|
26
20
|
'LICENSE',
|
|
@@ -50,7 +44,7 @@ export const config: AllConfigPartial = {
|
|
|
50
44
|
mod('typescript/'),
|
|
51
45
|
mod('@types/'),
|
|
52
46
|
`^./${mod('@travetto/**/*.ts')}`,
|
|
53
|
-
`^./${mod('@travetto/
|
|
47
|
+
`^./${mod('@travetto/compiler/tsconfig.trv.json')}`,
|
|
54
48
|
'^./resources/',
|
|
55
49
|
'^./src/',
|
|
56
50
|
]
|
package/bin/lib/assemble.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
|
|
4
|
-
import { ExecUtil, PathUtil, ScanFs, FsUtil } from '@travetto/boot';
|
|
5
|
-
|
|
6
|
-
import { DependenciesUtil, DepType } from './dependencies';
|
|
7
|
-
import { PackUtil } from './util';
|
|
8
|
-
|
|
9
|
-
const MODULE_DIRS = ['src', 'bin', 'support', 'resources', 'index.ts', 'package.json', 'tsconfig.trv.json'];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Utils for assembling
|
|
13
|
-
*/
|
|
14
|
-
export class AssembleUtil {
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Minimize cached source files, by removing source mapping info
|
|
18
|
-
*/
|
|
19
|
-
static async cleanCache(cache: string): Promise<void> {
|
|
20
|
-
for (const el of await fs.readdir(cache)) {
|
|
21
|
-
if (el.endsWith('.ts') || el.endsWith('.js')) {
|
|
22
|
-
const content = (await fs.readFile(`${cache}/${el}`, 'utf8')).replace(/\/\/# sourceMap.*/g, '');
|
|
23
|
-
await fs.writeFile(`${cache}/${el}`, content);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Minimize cached source files, by removing source mapping info
|
|
30
|
-
*/
|
|
31
|
-
static async cleanBoot(ws: string): Promise<void> {
|
|
32
|
-
for (const el of await ScanFs.scanDir({
|
|
33
|
-
testFile: f => f.endsWith('.js') || f.endsWith('.d.ts'),
|
|
34
|
-
testDir: x => true
|
|
35
|
-
}, `${ws}/node_modules/@travetto/boot`)) {
|
|
36
|
-
if (el.file.endsWith('.d.ts')) {
|
|
37
|
-
await fs.writeFile(el.file, '');
|
|
38
|
-
} else if (el.file.endsWith('.js')) {
|
|
39
|
-
const content = (await fs.readFile(el.file, 'utf8')).replace(/\/\/# sourceMap.*/g, '');
|
|
40
|
-
await fs.writeFile(el.file, content);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Truncate all app source files, and framework source files
|
|
47
|
-
*/
|
|
48
|
-
static async purgeSource(folders: string[]): Promise<void> {
|
|
49
|
-
for (const sub of folders) {
|
|
50
|
-
for (const f of await ScanFs.scanDir({ testFile: x => x.endsWith('.ts'), testDir: x => true }, sub)) {
|
|
51
|
-
if (f.stats?.isFile() && !f.module.startsWith('cli/')) {
|
|
52
|
-
await fs.writeFile(f.file, '');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Copy a module
|
|
60
|
-
*/
|
|
61
|
-
static async copyModule(root: string, target: string): Promise<void> {
|
|
62
|
-
for (const f of MODULE_DIRS) {
|
|
63
|
-
const sourceFile = PathUtil.resolveUnix(root, f);
|
|
64
|
-
const targetFile = PathUtil.resolveUnix(target, f);
|
|
65
|
-
const found = await FsUtil.exists(sourceFile);
|
|
66
|
-
if (found) {
|
|
67
|
-
if (found.isFile()) {
|
|
68
|
-
await fs.copyFile(sourceFile, targetFile);
|
|
69
|
-
} else {
|
|
70
|
-
await fs.mkdir(targetFile, { recursive: true });
|
|
71
|
-
await FsUtil.copyRecursive(`${sourceFile}/*`, targetFile);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Purge workspace using file rules
|
|
79
|
-
*/
|
|
80
|
-
static async excludeFiles(root: string, files: string[]): Promise<void> {
|
|
81
|
-
const checker = PackUtil.excludeChecker(files, root);
|
|
82
|
-
for (const el of await ScanFs.scanDir({ testDir: x => true, testFile: checker, withHidden: true }, root)) {
|
|
83
|
-
if (!el.stats || !el.stats.isFile()) { continue; }
|
|
84
|
-
try {
|
|
85
|
-
await fs.unlink(el.file);
|
|
86
|
-
} catch { }
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Copy over all prod dependencies
|
|
92
|
-
*/
|
|
93
|
-
static async copyDependencies(workspace: string, types: DepType[] = ['prod', 'opt', 'peer']): Promise<void> {
|
|
94
|
-
|
|
95
|
-
for (const el of await DependenciesUtil.resolveDependencies({ types })) {
|
|
96
|
-
const sub = PathUtil.normalizeFrameworkPath(el.file, 'node_modules/')
|
|
97
|
-
.replace(/.*?node_modules/, 'node_modules');
|
|
98
|
-
|
|
99
|
-
const tgt = PathUtil.resolveUnix(workspace, sub);
|
|
100
|
-
await fs.mkdir(path.dirname(tgt), { recursive: true });
|
|
101
|
-
|
|
102
|
-
if (el.dep.startsWith('@travetto')) {
|
|
103
|
-
await this.copyModule(el.file, tgt);
|
|
104
|
-
} else {
|
|
105
|
-
if (!(await FsUtil.exists(tgt))) {
|
|
106
|
-
await FsUtil.copyRecursive(el.file, tgt);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
await FsUtil.copyRecursive(
|
|
111
|
-
PathUtil.resolveUnix(path.dirname(require.resolve('@travetto/boot/bin/main.js'))),
|
|
112
|
-
PathUtil.resolveUnix(workspace, 'node_modules/@travetto/boot/bin')
|
|
113
|
-
);
|
|
114
|
-
await FsUtil.copyRecursive(
|
|
115
|
-
PathUtil.resolveUnix(path.dirname(require.resolve('@travetto/base/bin/main.js'))),
|
|
116
|
-
PathUtil.resolveUnix(workspace, 'node_modules/@travetto/base/bin')
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Compile workspace
|
|
122
|
-
*/
|
|
123
|
-
static async buildWorkspace(root: string, cacheDir: string): Promise<void> {
|
|
124
|
-
await ExecUtil.spawn('node', ['./node_modules/@travetto/cli/bin/trv.js', 'build'],
|
|
125
|
-
{
|
|
126
|
-
cwd: root, isolatedEnv: true,
|
|
127
|
-
env: { TRV_ENV: 'prod', TRV_READONLY: '0', TRV_CACHE: cacheDir, TRV_NODE_VERSION: process.env.TRV_NODE_VERSION },
|
|
128
|
-
stdio: ['pipe', 'pipe', 2]
|
|
129
|
-
}).result;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Copy over added content
|
|
134
|
-
*/
|
|
135
|
-
static async copyAddedContent(workspace: string, files: Record<string, string>[]): Promise<void> {
|
|
136
|
-
for (const a of files) {
|
|
137
|
-
let [src, dest] = Object.entries(a)[0];
|
|
138
|
-
[src, dest] = [PathUtil.resolveUnix(src), PathUtil.resolveUnix(workspace, dest)];
|
|
139
|
-
const stat = await FsUtil.exists(src);
|
|
140
|
-
if (stat) {
|
|
141
|
-
if (stat.isFile()) {
|
|
142
|
-
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
143
|
-
await fs.copyFile(src, dest);
|
|
144
|
-
} else {
|
|
145
|
-
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
146
|
-
await FsUtil.copyRecursive(src, dest);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
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
|
-
}
|
|
@@ -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/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { AllConfig, AllConfigPartial } from './bin/operation/pack';
|
|
2
|
-
export { CommonConfig } from './bin/lib/types';
|
|
3
|
-
export { AssembleConfig } from './bin/operation/assemble';
|
|
4
|
-
export { ZipConfig } from './bin/operation/zip';
|
|
5
|
-
export { DockerConfig } from './bin/operation/docker';
|