build-strap 4.0.0-dev.46 → 4.0.0

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.
Files changed (129) hide show
  1. package/README.md +3 -34
  2. package/dist/src/ant.d.ts +19 -0
  3. package/dist/src/ant.js +18 -0
  4. package/dist/src/cert.d.ts +12 -0
  5. package/dist/src/cert.js +91 -0
  6. package/dist/src/clean.d.ts +4 -0
  7. package/dist/src/clean.js +11 -0
  8. package/dist/src/copy.d.ts +7 -0
  9. package/dist/src/copy.js +53 -0
  10. package/dist/src/cp.d.ts +17 -0
  11. package/dist/src/cp.js +88 -0
  12. package/dist/src/docker.container.d.ts +73 -0
  13. package/dist/src/docker.container.js +247 -0
  14. package/dist/src/docker.d.ts +68 -0
  15. package/dist/src/docker.js +188 -0
  16. package/dist/src/docker.network.d.ts +42 -0
  17. package/dist/src/docker.network.js +85 -0
  18. package/dist/src/docker.volume.d.ts +26 -0
  19. package/dist/src/docker.volume.js +62 -0
  20. package/dist/src/dockerCleanup.d.ts +38 -0
  21. package/dist/src/dockerCleanup.js +77 -0
  22. package/dist/src/dockerCompose.d.ts +154 -0
  23. package/dist/src/dockerCompose.js +439 -0
  24. package/dist/src/fs.d.ts +5 -0
  25. package/dist/src/fs.js +38 -0
  26. package/dist/src/git.d.ts +9 -0
  27. package/dist/src/git.js +24 -0
  28. package/dist/src/index.d.ts +20 -0
  29. package/dist/src/index.js +20 -0
  30. package/dist/src/maps.d.ts +33 -0
  31. package/dist/src/maps.js +41 -0
  32. package/dist/src/npm.d.ts +35 -0
  33. package/dist/src/npm.js +104 -0
  34. package/dist/src/pkg.d.ts +33 -0
  35. package/dist/src/pkg.js +33 -0
  36. package/dist/src/publish.d.ts +27 -0
  37. package/dist/src/publish.js +57 -0
  38. package/dist/src/run.d.ts +13 -0
  39. package/dist/src/run.js +44 -0
  40. package/dist/src/tgz.d.ts +13 -0
  41. package/dist/src/tgz.js +67 -0
  42. package/dist/src/version.d.ts +34 -0
  43. package/dist/src/version.js +101 -0
  44. package/dist/src/yarn.d.ts +26 -0
  45. package/dist/src/yarn.js +75 -0
  46. package/package.json +74 -20
  47. package/ant.js +0 -43
  48. package/ant.js.flow +0 -42
  49. package/artifactory.js +0 -617
  50. package/artifactory.js.flow +0 -616
  51. package/cert.conf +0 -20
  52. package/cert.js +0 -153
  53. package/cert.js.flow +0 -152
  54. package/clean.js +0 -20
  55. package/clean.js.flow +0 -19
  56. package/copy.js +0 -80
  57. package/copy.js.flow +0 -79
  58. package/cp.js +0 -173
  59. package/cp.js.flow +0 -172
  60. package/docker.container.js +0 -390
  61. package/docker.container.js.flow +0 -389
  62. package/docker.js +0 -365
  63. package/docker.js.flow +0 -364
  64. package/docker.network.js +0 -160
  65. package/docker.network.js.flow +0 -159
  66. package/docker.volume.js +0 -136
  67. package/docker.volume.js.flow +0 -136
  68. package/dockerCleanup.js +0 -152
  69. package/dockerCleanup.js.flow +0 -151
  70. package/dockerCompose.js +0 -766
  71. package/dockerCompose.js.flow +0 -765
  72. package/flow.js +0 -21
  73. package/flow.js.flow +0 -20
  74. package/fs.js +0 -95
  75. package/fs.js.flow +0 -96
  76. package/git.js +0 -35
  77. package/git.js.flow +0 -34
  78. package/hg.js +0 -35
  79. package/hg.js.flow +0 -34
  80. package/index.js +0 -27
  81. package/index.js.flow +0 -26
  82. package/inline-resources.js +0 -158
  83. package/inline-resources.js.flow +0 -157
  84. package/maps.js +0 -112
  85. package/maps.js.flow +0 -111
  86. package/npm.js +0 -145
  87. package/npm.js.flow +0 -144
  88. package/pkg.js +0 -81
  89. package/pkg.js.flow +0 -80
  90. package/publish.js +0 -145
  91. package/publish.js.flow +0 -144
  92. package/run.js +0 -90
  93. package/run.js.flow +0 -89
  94. package/src/ant.js +0 -42
  95. package/src/artifactory.js +0 -616
  96. package/src/cert.conf +0 -20
  97. package/src/cert.js +0 -152
  98. package/src/clean.js +0 -19
  99. package/src/copy.js +0 -79
  100. package/src/cp.js +0 -172
  101. package/src/docker.container.js +0 -389
  102. package/src/docker.js +0 -364
  103. package/src/docker.network.js +0 -159
  104. package/src/docker.volume.js +0 -136
  105. package/src/dockerCleanup.js +0 -151
  106. package/src/dockerCompose.js +0 -765
  107. package/src/flow.js +0 -20
  108. package/src/fs.js +0 -96
  109. package/src/git.js +0 -34
  110. package/src/hg.js +0 -34
  111. package/src/index.js +0 -26
  112. package/src/inline-resources.js +0 -157
  113. package/src/maps.js +0 -111
  114. package/src/npm.js +0 -144
  115. package/src/pkg.js +0 -80
  116. package/src/publish.js +0 -144
  117. package/src/run.js +0 -89
  118. package/src/test.js +0 -55
  119. package/src/tgz.js +0 -101
  120. package/src/version.js +0 -142
  121. package/src/yarn.js +0 -123
  122. package/test.js +0 -56
  123. package/test.js.flow +0 -55
  124. package/tgz.js +0 -102
  125. package/tgz.js.flow +0 -101
  126. package/version.js +0 -143
  127. package/version.js.flow +0 -142
  128. package/yarn.js +0 -124
  129. package/yarn.js.flow +0 -123
@@ -0,0 +1,247 @@
1
+ import bytes from 'bytes';
2
+ import { throttle } from 'lodash-es';
3
+ import { spawn } from './cp.js';
4
+ import { parseDockerDate } from './docker.js';
5
+ import { buildLog } from './run.js';
6
+ // calling this function in rapid succession can lead to errors.
7
+ // prefer throttled version
8
+ export async function unthrottledDockerContainerLs({ all, filter, } = {}) {
9
+ return (await spawn('docker', [
10
+ 'container',
11
+ 'ls',
12
+ ...(all ? ['--all'] : []),
13
+ '--no-trunc',
14
+ '--format',
15
+ '{{json .}}',
16
+ ], { captureOutput: true })).output
17
+ .split('\n')
18
+ .filter((line) => !!line.trim())
19
+ .map((line) => {
20
+ const { Command: command, CreatedAt, ID: id, Image: image, Labels, Mounts, Names, Networks, Ports, RunningFor: runningFor, Size, Status: status, } = JSON.parse(line.trim());
21
+ const names = Names.split(',').map((n) => n.trim());
22
+ const [name] = names;
23
+ return {
24
+ command,
25
+ created: parseDockerDate(CreatedAt),
26
+ async exists() {
27
+ try {
28
+ return !!(await this.inspect());
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ },
34
+ exited: /^Exited/.test(status),
35
+ id,
36
+ image,
37
+ inspect: async () => (await dockerContainerInspect(id))?.[0],
38
+ async isRunning() {
39
+ try {
40
+ return (await this.inspect())?.State?.Running || false;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ },
46
+ kill: async (ignoreError = true) => dockerContainerKill(id, ignoreError),
47
+ labels: Labels.split(',').map((l) => l.trim()),
48
+ mounts: Mounts.split(',').map((m) => m.trim()),
49
+ name,
50
+ names,
51
+ networks: Networks.split(',').map((n) => n.trim()),
52
+ ports: Ports.split(',').map((p) => {
53
+ const [, iface, src, dest] = p.match(/^([^:]+):(\d+)-\\u003e(\d+)/i) || [];
54
+ return {
55
+ dest: parseInt(dest, 10),
56
+ iface,
57
+ src: parseInt(src, 10),
58
+ };
59
+ }),
60
+ restart: async () => dockerContainerRestart(id),
61
+ rm: async (ignoreError = true) => dockerContainerRm(id, ignoreError),
62
+ runningFor,
63
+ size: bytes.parse(Size),
64
+ start: async () => dockerContainerStart(id),
65
+ status,
66
+ stop: async (ignoreError = true) => dockerContainerStop(id, ignoreError),
67
+ async teardown(verbose = true) {
68
+ const log = (msg) => verbose && buildLog(msg);
69
+ if (await this.isRunning()) {
70
+ try {
71
+ log(`Stopping container: <${this.name}>...`);
72
+ await this.stop(false);
73
+ log(`<${this.name}> container stopped.`);
74
+ }
75
+ catch (e1) {
76
+ log(`Failed to stop <${this.name}> container: ${e1.message}`);
77
+ try {
78
+ log(`Killing container: <${this.name}>...`);
79
+ await this.kill(false);
80
+ log(`<${this.name}> container killed.`);
81
+ }
82
+ catch (e2) {
83
+ log(`Failed to kill <${this.name}> container: ${e2.message}`);
84
+ }
85
+ }
86
+ }
87
+ else {
88
+ log(`<${this.name}> container not running, skipping stop.`);
89
+ }
90
+ if (await this.exists()) {
91
+ await this.rm(true);
92
+ }
93
+ else {
94
+ log(`<${this.name}> container does not exist, skipping rm.`);
95
+ }
96
+ },
97
+ };
98
+ })
99
+ .filter((c) => c.id && (typeof filter === 'function' ? filter(c) : true));
100
+ }
101
+ export const dockerContainerLs = throttle(unthrottledDockerContainerLs, 500, {
102
+ trailing: false,
103
+ });
104
+ export async function dockerContainerFind(search, options) {
105
+ return ((await dockerContainerLs(options))?.find((c) => c.name === search ||
106
+ c.id.startsWith(search) ||
107
+ c.names.includes(search)) || null);
108
+ }
109
+ export async function dockerContainerStop(id, ignoreErrors = true) {
110
+ const ids = Array.isArray(id) ? id : [id];
111
+ try {
112
+ await spawn('docker', ['container', 'stop', ...ids]);
113
+ }
114
+ catch (e) {
115
+ if (!ignoreErrors) {
116
+ throw new Error(`Failed to stop container(s): ${e.message}`);
117
+ }
118
+ }
119
+ }
120
+ export async function dockerContainerKill(id, ignoreErrors = true) {
121
+ const ids = Array.isArray(id) ? id : [id];
122
+ try {
123
+ await spawn('docker', ['container', 'kill', ...ids]);
124
+ }
125
+ catch (e) {
126
+ if (!ignoreErrors) {
127
+ throw new Error(`Failed to kill container(s): ${e.message}`);
128
+ }
129
+ }
130
+ }
131
+ export async function dockerTryStopContainer(id, name = '') {
132
+ if (id) {
133
+ try {
134
+ await dockerContainerStop(id, false);
135
+ }
136
+ catch (e) {
137
+ buildLog(`Failed to stop ${name} container: ${e.message}`);
138
+ }
139
+ }
140
+ }
141
+ export async function dockerContainerRm(id, ignoreErrors = true) {
142
+ const ids = Array.isArray(id) ? id : [id];
143
+ try {
144
+ await spawn('docker', ['container', 'rm', ...ids]);
145
+ }
146
+ catch (e) {
147
+ if (ignoreErrors) {
148
+ buildLog(`Warning (ignored Error): Failed to remove container(s): ${e.message}`);
149
+ }
150
+ else {
151
+ throw new Error(`Failed to remove container(s): ${e.message}`);
152
+ }
153
+ }
154
+ }
155
+ export async function dockerContainerRestart(id) {
156
+ const ids = Array.isArray(id) ? id : [id];
157
+ await spawn('docker', ['container', 'restart', ...ids]);
158
+ }
159
+ export async function dockerContainerStart(id) {
160
+ const ids = Array.isArray(id) ? id : [id];
161
+ await spawn('docker', ['container', 'start', ...ids]);
162
+ }
163
+ export async function unthrottledDockerContainerInspect(id) {
164
+ const ids = Array.isArray(id) ? id : [id];
165
+ return ((await spawn('docker', ['container', 'inspect', '--format', '{{json .}}', ...ids], { captureOutput: true })).output
166
+ .split('\n')
167
+ .filter((line) => !!line.trim())
168
+ .map((line) => JSON.parse(line.trim())) || []);
169
+ }
170
+ export const dockerContainerInspect = throttle(unthrottledDockerContainerInspect, 500, {
171
+ trailing: false,
172
+ });
173
+ export async function dockerContainerRun({ image, runArgs = [], cmd = [], spawnOptions, }) {
174
+ return (await spawn('docker', ['container', 'run', ...runArgs, image, ...cmd], {
175
+ pipeOutput: true,
176
+ stdio: 'inherit',
177
+ ...spawnOptions,
178
+ })).output;
179
+ }
180
+ export async function dockerContainerRunDaemon({ image, runArgs = [], cmd = [], waitAttempts = 10, waitDuration = 501, }) {
181
+ const id = (await dockerContainerRun({
182
+ cmd,
183
+ image,
184
+ runArgs: ['-d', ...runArgs],
185
+ spawnOptions: {
186
+ captureOutput: true,
187
+ pipeOutput: false,
188
+ stdio: 'pipe',
189
+ },
190
+ })).trim();
191
+ let container = await dockerContainerFind(id);
192
+ let attempts = 0;
193
+ // containers don't always show up in the list right away
194
+ /* eslint-disable no-await-in-loop */
195
+ while (!container && attempts < waitAttempts) {
196
+ await new Promise((resolve) => {
197
+ setTimeout(resolve, waitDuration);
198
+ });
199
+ container = await dockerContainerFind(id);
200
+ attempts += 1;
201
+ }
202
+ /* eslint-enable no-await-in-loop */
203
+ if (!container) {
204
+ throw new Error(`Failed to find newly created container: ${id}`);
205
+ }
206
+ return container;
207
+ }
208
+ const indicators = ['.', ':', '*', '+', '-', '=', '%', '$', '@', '^', '&'];
209
+ let curIndicator = 0;
210
+ /**
211
+ * Waits for the given container to be fully started. Checks that the container is
212
+ * running, and test with the provided testFn every second until it returns true.
213
+ * @param {DockerContainer} container The container to test
214
+ * @param {Function} testFn A function that validates that the container is ready (e.g. by calling an API on the container)
215
+ * @param {number} timeoutMs The amount of time to wait between attempts.
216
+ * @param {number} maxAttempts The maximum number of attempts before giving up (rejects promise)
217
+ */
218
+ export const dockerContainerWaitForStart = async (container, testFn, timeoutMs = 1000, maxAttempts = 1200) => {
219
+ // claim an indicator
220
+ const indicator = indicators[curIndicator] || '.';
221
+ curIndicator = (curIndicator + 1) % indicators.length;
222
+ const { name } = container;
223
+ buildLog(`Waiting for ${name} to fully start... ${indicator}`);
224
+ await new Promise((resolve, reject) => {
225
+ const check = (tries = 0) => {
226
+ process.stdout.write(indicator);
227
+ setTimeout(async () => {
228
+ try {
229
+ if (!(await container.isRunning())) {
230
+ return reject(new Error(`The '${name}' container is no longer running.`));
231
+ }
232
+ if (await testFn(container)) {
233
+ return resolve();
234
+ }
235
+ }
236
+ catch (err) {
237
+ // ignore
238
+ }
239
+ return tries < maxAttempts
240
+ ? check(tries + 1)
241
+ : reject(new Error(`Timeout waiting for '${name}' container to start.`));
242
+ }, timeoutMs);
243
+ };
244
+ check();
245
+ });
246
+ process.stdout.write('\n');
247
+ };
@@ -0,0 +1,68 @@
1
+ export interface DockerConfig {
2
+ name?: string;
3
+ registry?: string;
4
+ repository?: string;
5
+ }
6
+ export declare function getDockerConfig(): DockerConfig;
7
+ export declare const parseDockerDate: (date: string) => Date;
8
+ export declare function dockerBuild(tags?: string[], buildArgs?: string[], target?: string | null, extraArgs?: string[], repo?: string, dockerFile?: string, workDir?: string): Promise<string>;
9
+ export declare function dockerTag(imageId: string, tags?: string[], repo?: string): Promise<void>;
10
+ /**
11
+ * Apply the standard convention for tagging the docker image for the project,
12
+ * based on the source control branch being built.
13
+ * For releases, applies `latest`, `M.m.p`, `M.m`, `M`
14
+ * For release candidates, applies `latest-rc`
15
+ * For feature branches, applies `latest-feature`
16
+ * For development branch, applies `latest-dev`
17
+ * All other branches, no tag is applies
18
+ * @param {string} imageId id of the docker image to which to apply the tags
19
+ * @param {string} repo optional override of the docker repo url to use (derived from package.json by default)
20
+ */
21
+ export declare function dockerTagVersion(imageId: string, repo?: string): Promise<void>;
22
+ export interface DockerImage {
23
+ created: Date;
24
+ digest: string;
25
+ id: string;
26
+ repository: string;
27
+ size: number;
28
+ tag: string;
29
+ }
30
+ export declare type DockerImageFilter = (i: DockerImage) => boolean;
31
+ export declare function dockerImages(repo?: null | string, filter?: null | DockerImageFilter): Promise<DockerImage[]>;
32
+ export declare function getDockerId(tag?: string, repo?: null | string): Promise<string>;
33
+ export declare function getUntaggedDockerIds(repo?: string, filter?: null | DockerImageFilter): Promise<string[]>;
34
+ export declare function getDockerTags(id?: null | string, repo?: null | string, fullName?: boolean, filter?: null | DockerImageFilter): Promise<string[]>;
35
+ export declare function getDockerDigest(imageId: string, repo?: string): Promise<string>;
36
+ interface DockerLoginOptions {
37
+ password?: string;
38
+ registry?: string;
39
+ user?: string;
40
+ }
41
+ export declare function dockerLogin({ password, registry, user, }?: DockerLoginOptions): Promise<void>;
42
+ export declare function dockerPush(tags?: string[], repo?: string): Promise<void>;
43
+ export interface DockerPullOptions {
44
+ image: string;
45
+ offline?: boolean;
46
+ testUrl?: string | null;
47
+ }
48
+ export declare function dockerPull({ image, offline, testUrl, }: DockerPullOptions): Promise<void>;
49
+ export declare function dockerRmi(images?: string[], ignoreErrors?: boolean): Promise<void>;
50
+ export declare function getDockerRepo(): string;
51
+ export interface PullAndRunContainerOptions extends DockerPullOptions {
52
+ alias?: string | null;
53
+ cmd?: string[];
54
+ network?: string | null;
55
+ runArgs?: string[];
56
+ }
57
+ export declare function dockerPullAndRunContainer(options: PullAndRunContainerOptions): Promise<string>;
58
+ export interface CopyFilePathConfig {
59
+ from: string;
60
+ to: string;
61
+ }
62
+ export interface CopyFilesFromDockerImageConfig {
63
+ filePaths: CopyFilePathConfig[];
64
+ ignoreErrors?: boolean;
65
+ imageId: string;
66
+ }
67
+ export declare function copyFilesFromDockerImage({ filePaths, ignoreErrors, imageId, }: CopyFilesFromDockerImageConfig): Promise<any>;
68
+ export {};
@@ -0,0 +1,188 @@
1
+ import bytes from 'bytes';
2
+ import isReachable from 'is-reachable';
3
+ import moment from 'moment';
4
+ import path from 'path';
5
+ import { spawn } from './cp.js';
6
+ import { dockerContainerKill, dockerContainerRunDaemon, } from './docker.container.js';
7
+ import { dockerNetworkConnect } from './docker.network.js';
8
+ import { getCfg, getPkgName, getPkgScope } from './pkg.js';
9
+ import { buildLog } from './run.js';
10
+ import { getDevBranch, getVersion } from './version.js';
11
+ export function getDockerConfig() {
12
+ return getCfg().docker || {};
13
+ }
14
+ export const parseDockerDate = (date) => moment(date, 'YYYY-MM-DD HH:mm:ss ZZ').toDate();
15
+ export async function dockerBuild(tags = ['latest'], buildArgs = [], target = null, extraArgs = [], repo = getDockerRepo(), dockerFile = './Dockerfile', workDir = '.') {
16
+ const args = [
17
+ 'build',
18
+ ...['-f', path.resolve(dockerFile)],
19
+ ...(target ? ['--target', target] : []),
20
+ ...tags.reduce((ar, t) => [...ar, '-t', `${repo}:${t}`], []),
21
+ ...buildArgs.reduce((ar, a) => [...ar, '--build-arg', a], []),
22
+ ...(extraArgs || []),
23
+ path.resolve(workDir),
24
+ ];
25
+ return (await spawn('docker', args, { stdio: 'inherit' })).output;
26
+ }
27
+ export async function dockerTag(imageId, tags = ['latest'], repo = getDockerRepo()) {
28
+ await Promise.all(tags.map(async (t) => {
29
+ await spawn('docker', ['tag', imageId, `${repo}:${t}`]);
30
+ buildLog(`Tagged image ${imageId} as ${repo}:${t}`);
31
+ }));
32
+ }
33
+ /**
34
+ * Apply the standard convention for tagging the docker image for the project,
35
+ * based on the source control branch being built.
36
+ * For releases, applies `latest`, `M.m.p`, `M.m`, `M`
37
+ * For release candidates, applies `latest-rc`
38
+ * For feature branches, applies `latest-feature`
39
+ * For development branch, applies `latest-dev`
40
+ * All other branches, no tag is applies
41
+ * @param {string} imageId id of the docker image to which to apply the tags
42
+ * @param {string} repo optional override of the docker repo url to use (derived from package.json by default)
43
+ */
44
+ export async function dockerTagVersion(imageId, repo = getDockerRepo()) {
45
+ const { branch, isRelease, major, minor, patch } = await getVersion();
46
+ // determine what tags to apply
47
+ if (isRelease) {
48
+ await dockerTag(imageId, ['latest', `${major}`, `${major}.${minor}`, `${major}.${minor}.${patch}`], repo);
49
+ }
50
+ else if (branch === (await getDevBranch())) {
51
+ await dockerTag(imageId, ['latest-dev'], repo);
52
+ }
53
+ else if (branch.match(/^(release|patch)-/)) {
54
+ await dockerTag(imageId, ['latest-rc'], repo);
55
+ }
56
+ else if (branch.match(/^feature-/)) {
57
+ await dockerTag(imageId, ['latest-feature'], repo);
58
+ }
59
+ }
60
+ export async function dockerImages(repo = getDockerRepo(), filter = null) {
61
+ return (await spawn('docker', ['images', '--format', `{{json .}}`, ...(repo ? [repo] : [])], { captureOutput: true })).output
62
+ .split('\n')
63
+ .filter((line) => !!line.trim())
64
+ .map((l) => {
65
+ const { CreatedAt, Digest: digest, ID: id, Repository: repository, Size, Tag: tag, } = JSON.parse(l.trim());
66
+ return {
67
+ created: parseDockerDate(CreatedAt),
68
+ digest,
69
+ id,
70
+ repository,
71
+ size: bytes.parse(Size),
72
+ tag,
73
+ };
74
+ })
75
+ .filter((m) => (m && m.id) != null &&
76
+ (typeof filter === 'function' ? filter(m) : true));
77
+ }
78
+ export async function getDockerId(tag = 'latest', repo = null) {
79
+ return (await dockerImages(repo, (m) => m.tag === tag)).map((m) => m.id)[0];
80
+ }
81
+ export async function getUntaggedDockerIds(repo, filter = null) {
82
+ return (await dockerImages(repo, (m) => m.tag === '<none>' && (typeof filter === 'function' ? filter(m) : true))).map((m) => m.id);
83
+ }
84
+ export async function getDockerTags(id, repo, fullName = false, filter = null) {
85
+ return (await dockerImages(repo, (m) => (!id || m.id === id) &&
86
+ (typeof filter === 'function' ? filter(m) : true))).map((m) => (fullName ? `${m.repository}:${m.tag}` : m.tag));
87
+ }
88
+ export async function getDockerDigest(imageId, repo) {
89
+ return (await dockerImages(repo, (m) => m.id === imageId)).map((m) => m.digest)[0];
90
+ }
91
+ export async function dockerLogin({ password = process.env.DOCKER_PASSWORD, registry = process.env.DOCKER_REGISTRY, user = process.env.DOCKER_PASSWORD, } = {}) {
92
+ const reg = registry || getDockerConfig().registry;
93
+ await spawn('docker', ['login', '-u', user || '', '-p', password || '', ...(reg ? [reg] : [])], { stdio: 'inherit' });
94
+ }
95
+ export async function dockerPush(tags = ['latest'], repo = getDockerRepo()) {
96
+ // do this sequentially, so you don't push the same image simultaneously
97
+ await tags.reduce(async (prev, tag) => {
98
+ await prev;
99
+ await spawn('docker', ['push', `${repo}:${tag}`], { stdio: 'inherit' });
100
+ }, Promise.resolve());
101
+ }
102
+ export async function dockerPull({ image, offline = process.argv.includes('--offline'), testUrl, }) {
103
+ if (offline || !(await isReachable(testUrl || 'https://hub.docker.com'))) {
104
+ if (offline === false) {
105
+ throw new Error('Offline, cannot docker pull');
106
+ }
107
+ buildLog('It looks like you are offline, skipping docker pull');
108
+ }
109
+ else {
110
+ // throws on failure
111
+ await spawn('docker', ['pull', image], { stdio: 'inherit' });
112
+ }
113
+ }
114
+ export async function dockerRmi(images = [], ignoreErrors = true) {
115
+ // must do these sequentially, or they will interfere with each other
116
+ await images.reduce(async (prev, image) => {
117
+ await prev;
118
+ await spawn('docker', ['rmi', image], { stdio: 'inherit' }).catch((err) => {
119
+ if (ignoreErrors) {
120
+ buildLog(`Warning (ignored Error): Failed to rm image(s): ${err.message}`);
121
+ }
122
+ else {
123
+ throw err;
124
+ }
125
+ });
126
+ }, Promise.resolve());
127
+ }
128
+ export function getDockerRepo() {
129
+ const { name: dkrName, registry, repository: dkrRepo } = getDockerConfig();
130
+ const repository = dkrRepo || getPkgScope();
131
+ const name = dkrName || getPkgName(false);
132
+ if (!repository || !name) {
133
+ throw new Error('Docker configuration is missing or incomplete in package.json');
134
+ }
135
+ return `${registry ? `${registry}/` : ''}${repository}/${name}`;
136
+ }
137
+ export async function dockerPullAndRunContainer(options) {
138
+ const { image, runArgs = [], cmd = [], network, alias, offline = process.argv.includes('--offline'), testUrl, } = options;
139
+ try {
140
+ await dockerPull({ image, offline, testUrl });
141
+ }
142
+ catch (err) {
143
+ buildLog(`docker pull failed (${err.message}), attempting to continue...`);
144
+ }
145
+ const { id } = await dockerContainerRunDaemon({ cmd, image, runArgs });
146
+ if (network) {
147
+ await dockerNetworkConnect(network, id, alias);
148
+ }
149
+ return id;
150
+ }
151
+ export async function copyFilesFromDockerImage({ filePaths, ignoreErrors, imageId, }) {
152
+ const container = await dockerContainerRunDaemon({
153
+ cmd: ['read', '-p', 'pause'],
154
+ image: imageId,
155
+ runArgs: ['-it', '--rm', '--entrypoint=/bin/bash'],
156
+ });
157
+ buildLog(`Copying Files from Docker Image - imageId (${imageId})`);
158
+ const spawnOptions = {
159
+ captureOutput: false,
160
+ pipeOutput: true,
161
+ stdio: 'inherit',
162
+ };
163
+ const copyErrors = [];
164
+ try {
165
+ filePaths.forEach(async (fp) => {
166
+ // Try to copy from the Debug Folder
167
+ try {
168
+ await spawn('docker', ['cp', `${container.id}:${fp.from}`, fp.to], spawnOptions);
169
+ buildLog(`Copied ${fp.from} => ${fp.to}`);
170
+ }
171
+ catch (error) {
172
+ copyErrors.push(error);
173
+ buildLog(`Error copying file ${fp.from}`);
174
+ }
175
+ });
176
+ }
177
+ finally {
178
+ try {
179
+ await dockerContainerKill(container.id);
180
+ }
181
+ catch (error) {
182
+ copyErrors.push(error);
183
+ }
184
+ }
185
+ if (copyErrors.length > 0 && ignoreErrors !== true) {
186
+ throw new Error('Some files failed to copy');
187
+ }
188
+ }
@@ -0,0 +1,42 @@
1
+ export interface DockerNetwork {
2
+ IPv6: boolean;
3
+ created: Date;
4
+ driver: string;
5
+ exists: () => Promise<boolean>;
6
+ id: string;
7
+ labels: string[];
8
+ name: string;
9
+ rm: () => Promise<void>;
10
+ scope: string;
11
+ }
12
+ interface DockerNetworkLsOptions {
13
+ filter?: (network: DockerNetwork) => boolean;
14
+ }
15
+ export declare function unthrottledDockerNetworkLs({ filter, }?: DockerNetworkLsOptions): Promise<DockerNetwork[]>;
16
+ export declare const dockerNetworkLs: (options?: DockerNetworkLsOptions) => Promise<DockerNetwork[]> | undefined;
17
+ export declare function dockerNetworkFind(networkName: string, options?: DockerNetworkLsOptions): Promise<DockerNetwork | null>;
18
+ export interface DockerNetworkCreateOptions {
19
+ auxAddresses?: string[];
20
+ driver?: string;
21
+ driverOpts?: Record<string, string>;
22
+ gateways?: string[];
23
+ ingress?: boolean;
24
+ internal?: boolean;
25
+ ipRange?: string;
26
+ ipv6?: boolean;
27
+ labels?: string[];
28
+ subnets?: string[];
29
+ }
30
+ export declare function dockerNetworkCreate(networkName: string, { driver, driverOpts, ipRange, gateways, subnets, auxAddresses, ingress, internal, ipv6, labels, }?: DockerNetworkCreateOptions): Promise<DockerNetwork | null>;
31
+ /**
32
+ * Removes a network by id
33
+ * @param {string} id The id of the network
34
+ */
35
+ export declare function dockerNetworkRm(id: string): Promise<void>;
36
+ /**
37
+ * Removes all networks with the given name
38
+ * @param {string} networkName The name of the network
39
+ */
40
+ export declare function dockerNetworkDelete(networkName: string): Promise<void>;
41
+ export declare function dockerNetworkConnect(networkName: string, containerId: string, alias?: string | null): Promise<void>;
42
+ export {};
@@ -0,0 +1,85 @@
1
+ import { throttle } from 'lodash-es';
2
+ import { spawn } from './cp.js';
3
+ import { parseDockerDate } from './docker.js';
4
+ // calling this function in rapid succession can lead to errors.
5
+ // prefer throttled version
6
+ export async function unthrottledDockerNetworkLs({ filter, } = {}) {
7
+ return (await spawn('docker', ['network', 'ls', '--format', '{{json .}}'], {
8
+ captureOutput: true,
9
+ })).output
10
+ .split('\n')
11
+ .filter((line) => !!line.trim())
12
+ .map((line) => {
13
+ const { CreatedAt, Driver: driver, ID: id, IPv6, Labels, Name: name, Scope: scope, } = JSON.parse(line.trim());
14
+ return {
15
+ IPv6: IPv6 === 'true',
16
+ created: parseDockerDate(CreatedAt),
17
+ driver,
18
+ exists: async () => !!(await dockerNetworkFind(id)),
19
+ id,
20
+ labels: Labels.split(',').map((l) => l.trim()),
21
+ name,
22
+ rm: async () => dockerNetworkRm(id),
23
+ scope,
24
+ };
25
+ })
26
+ .filter((n) => n.id && (typeof filter === 'function' ? filter(n) : true));
27
+ }
28
+ export const dockerNetworkLs = throttle(unthrottledDockerNetworkLs, 500, {
29
+ trailing: false,
30
+ });
31
+ export async function dockerNetworkFind(networkName, options) {
32
+ return ((await dockerNetworkLs(options))?.find((n) => n.name === networkName || n.id === networkName) || null);
33
+ }
34
+ export async function dockerNetworkCreate(networkName, { driver, driverOpts = {}, ipRange, gateways = [], subnets = [], auxAddresses = [], ingress, internal, ipv6, labels = [], } = {}) {
35
+ const existing = await dockerNetworkFind(networkName);
36
+ if (existing)
37
+ return existing;
38
+ await spawn('docker', [
39
+ 'network',
40
+ 'create',
41
+ ...labels.flatMap((l) => ['--label', l]),
42
+ ...gateways.flatMap((g) => ['--gateway', g]),
43
+ ...subnets.flatMap((s) => ['--subnet', s]),
44
+ ...auxAddresses.flatMap((a) => ['--aux-address', a]),
45
+ ...(ipRange ? ['--ip-range', ipRange] : []),
46
+ ...(ingress ? ['--ingress'] : []),
47
+ ...(internal ? ['--internal'] : []),
48
+ ...(ipv6 ? ['--ipv6'] : []),
49
+ ...(driver ? ['-d', driver] : []),
50
+ ...Object.entries(driverOpts).flatMap(([k, v]) => ['-o', `${k}=${v}`]),
51
+ networkName,
52
+ ]);
53
+ return dockerNetworkFind(networkName);
54
+ }
55
+ /**
56
+ * Removes a network by id
57
+ * @param {string} id The id of the network
58
+ */
59
+ export async function dockerNetworkRm(id) {
60
+ await spawn('docker', ['network', 'rm', id]);
61
+ }
62
+ /**
63
+ * Removes all networks with the given name
64
+ * @param {string} networkName The name of the network
65
+ */
66
+ export async function dockerNetworkDelete(networkName) {
67
+ let existing;
68
+ // eslint-disable-next-line no-cond-assign, no-await-in-loop
69
+ while ((existing = await dockerNetworkFind(networkName))) {
70
+ // eslint-disable-next-line no-await-in-loop
71
+ await existing.rm();
72
+ }
73
+ }
74
+ export async function dockerNetworkConnect(networkName, containerId, alias) {
75
+ const net = await dockerNetworkCreate(networkName);
76
+ if (!net)
77
+ throw new Error('Failed to create docker network');
78
+ await spawn('docker', [
79
+ 'network',
80
+ 'connect',
81
+ ...(alias ? ['--alias', alias] : []),
82
+ net.id,
83
+ containerId,
84
+ ]);
85
+ }
@@ -0,0 +1,26 @@
1
+ declare type DockerVolumeInspectOutput = Record<string, any>;
2
+ export interface DockerVolume {
3
+ driver: string;
4
+ inspect: () => Promise<null | DockerVolumeInspectOutput>;
5
+ labels: string[];
6
+ mountPoint: string;
7
+ name: string;
8
+ rm: () => Promise<void>;
9
+ scope: string;
10
+ }
11
+ interface DockerVolumeLsOptions {
12
+ filter?: (vol: DockerVolume) => boolean;
13
+ }
14
+ export declare function unthrottledDockerVolumeLs({ filter, }?: DockerVolumeLsOptions): Promise<DockerVolume[]>;
15
+ export declare const dockerVolumeLs: (options?: DockerVolumeLsOptions) => undefined | Promise<DockerVolume[]>;
16
+ export declare function dockerVolumeFind(search: string, options?: DockerVolumeLsOptions): Promise<null | DockerVolume>;
17
+ export interface DockerVolumeCreateOptions {
18
+ driver?: string;
19
+ driverOpts?: Record<string, string>;
20
+ labels?: string[];
21
+ }
22
+ export declare function dockerVolumeCreate(name: string, { labels, driver, driverOpts }?: DockerVolumeCreateOptions): Promise<null | DockerVolume>;
23
+ export declare function dockerVolumeRm(id: string | string[], ignoreErrors?: boolean): Promise<void>;
24
+ export declare function unthrottledDockerVolumeInspect(id: string | string[]): Promise<DockerVolumeInspectOutput[]>;
25
+ export declare const dockerVolumeInspect: (id: string | string[]) => undefined | Promise<DockerVolumeInspectOutput[]>;
26
+ export {};