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
@@ -1,765 +0,0 @@
1
- // @flow
2
- import fs from 'fs-extra';
3
- import yaml from 'js-yaml';
4
- import path from 'path';
5
- import getPort from 'get-port';
6
- import { keys, entries, mapValuesAsync, type MapObj } from './maps';
7
-
8
- import { buildLog } from './run';
9
- import { dockerPull } from './docker';
10
- import {
11
- dockerContainerFind,
12
- dockerContainerRunDaemon,
13
- type DockerContainer,
14
- } from './docker.container';
15
- import {
16
- dockerNetworkDelete,
17
- dockerNetworkCreate,
18
- type DockerNetworkCreateOptions,
19
- type DockerNetwork,
20
- } from './docker.network';
21
- import {
22
- dockerVolumeCreate,
23
- dockerVolumeRm,
24
- type DockerVolume,
25
- } from './docker.volume';
26
-
27
- export type DockerComposeResourceTracker = {
28
- services: Map<string, DockerComposeService>,
29
- networks: Map<string, DockerNetwork>,
30
- containers: Map<string, DockerContainer>,
31
- volumes: Map<string, DockerVolume>,
32
- cleaning: ?Promise<void>,
33
- };
34
-
35
- export const dockerComposeCreateResourceTracker = (): DockerComposeResourceTracker => ({
36
- networks: new Map(),
37
- services: new Map(),
38
- containers: new Map(),
39
- volumes: new Map(),
40
- cleaning: null,
41
- });
42
-
43
- const defaultTracker = dockerComposeCreateResourceTracker();
44
-
45
- type DockerComposeEnvDef = string[] | { [string]: string };
46
-
47
- type DockerComposeULimitDef = number | { soft: number, hard: number };
48
-
49
- type DockerComposeULimitsDef = {
50
- [string]: DockerComposeULimitDef,
51
- };
52
-
53
- type DockerComposeServiceDef = {
54
- container_name?: string,
55
- image?: string,
56
- ports?: string[],
57
- volumes?: string[],
58
- command?: string[],
59
- networks?: string[],
60
- environment?: DockerComposeEnvDef,
61
- links?: string[],
62
- ulimits?: DockerComposeULimitsDef,
63
- };
64
-
65
- type DockerComposeVolumeDef = {
66
- name?: string,
67
- };
68
-
69
- type DockerComposeNetworkDef = {
70
- ...DockerNetworkCreateOptions,
71
- name?: string,
72
- };
73
-
74
- type DockerCompose = {
75
- version: string,
76
- services?: {
77
- [string]: DockerComposeServiceDef,
78
- },
79
- volumes?: {
80
- [string]: DockerComposeVolumeDef,
81
- },
82
- networks?: {
83
- [string]: DockerComposeNetworkDef,
84
- },
85
- };
86
-
87
- /**
88
- * Parse a docker-compose.yml file into a pojo representation
89
- * @param {string} filePath Path to the docker-compose.yml file
90
- */
91
- export const dockerComposeParse = async (
92
- filePath?: string = './docker-compose.yml',
93
- ): Promise<DockerCompose> => (yaml.load(await fs.readFile(filePath)): any);
94
-
95
- let dc: ?DockerCompose = null;
96
-
97
- /**
98
- * Get the main docker-compose.yml from the root of the repo
99
- * @param {boolean} force Force reload from file
100
- */
101
- export const dockerComposeGetMain = async (
102
- force?: boolean = false,
103
- ): Promise<DockerCompose> => {
104
- if (force || !dc) {
105
- dc = await dockerComposeParse();
106
- }
107
- return dc;
108
- };
109
-
110
- // Function that handles passed dockerCompose as either a file path or `DockerCompose` object.
111
- // If not passed, defaults to the main docker-compose.yml from the root of the repo
112
- const dockerComposeResolve = async (
113
- dockerCompose?: ?(string | DockerCompose),
114
- force?: boolean,
115
- ): Promise<DockerCompose> =>
116
- typeof dockerCompose === 'string'
117
- ? dockerComposeParse(dockerCompose)
118
- : dockerCompose || dockerComposeGetMain(force);
119
-
120
- // Determines an unnamed resource's name from the dirname combined with the key
121
- const prefixName = (name: string) => `${path.basename(__dirname)}_${name}`;
122
-
123
- const getServiceDef = async (
124
- name: string,
125
- force?: boolean,
126
- dockerCompose?: ?(string | DockerCompose),
127
- ): Promise<?DockerComposeServiceDef> =>
128
- (await dockerComposeResolve(dockerCompose, force)).services?.[name] || null;
129
-
130
- type PortMap = {
131
- local: ?number,
132
- localDefault: number,
133
- docker: number,
134
- };
135
-
136
- type UrlMap = {
137
- local: ?string,
138
- docker: ?string,
139
- };
140
-
141
- type ParsedPortInfo = {
142
- runArgs: string[],
143
- ports: PortMap[],
144
- };
145
-
146
- const parsePorts = async (
147
- portsCfg?: string[] = [],
148
- avoidConflicts?: boolean = true,
149
- mapLocal?: boolean = true,
150
- host?: string = '0.0.0.0',
151
- ): Promise<ParsedPortInfo> => {
152
- const ports: PortMap[] = [];
153
- const runArgs = await portsCfg.reduce(async (args, portStr) => {
154
- const [lp, dp] = portStr.split(':');
155
- const localDefault = parseInt(lp, 10);
156
- const docker = parseInt(dp, 10);
157
- const local = mapLocal
158
- ? avoidConflicts
159
- ? await getPort({ port: localDefault, host })
160
- : localDefault
161
- : null;
162
- ports.push({ local, localDefault, docker });
163
- return local ? [...(await args), '-p', `${local}:${docker}`] : args;
164
- }, []);
165
- return { runArgs, ports };
166
- };
167
-
168
- const parseEnv = (env?: DockerComposeEnvDef = []): string[] =>
169
- Array.isArray(env)
170
- ? env.flatMap((e) => ['-e', e])
171
- : entries(env).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
172
-
173
- const parseULimits = (ul?: DockerComposeULimitsDef = {}): string[] =>
174
- entries(ul).flatMap(([k, v]) => [
175
- '--ulimit',
176
- `${k}=${
177
- typeof v === 'number' ? v : `${v.soft}${v.hard ? `:${v.hard}` : ''}`
178
- }`,
179
- ]);
180
-
181
- type ParsedVolumeInfo = {
182
- runArgs: string[],
183
- volumes: string[],
184
- };
185
-
186
- const parseVolumes = async (
187
- volCfg?: string[] = [],
188
- nameSuffix?: string = '',
189
- dockerCompose?: ?(string | DockerCompose),
190
- ): Promise<ParsedVolumeInfo> => {
191
- const { volumes: volMap } = await dockerComposeResolve(dockerCompose);
192
- const volumes = [];
193
- const runArgs: string[] = volCfg
194
- .map((v) => {
195
- const [src, ...rest] = v.split(':');
196
- const name = volMap?.[src]
197
- ? `${volMap[src].name || prefixName(src)}${nameSuffix}`
198
- : null;
199
- if (name) {
200
- volumes.push(name);
201
- }
202
- const realSrc = name || path.resolve(src);
203
- return [realSrc, ...rest].join(':');
204
- })
205
- .flatMap((v) => ['-v', v]);
206
- return { runArgs, volumes };
207
- };
208
-
209
- type ParsedNetworkInfo = {
210
- runArgs: string[],
211
- networks: string[],
212
- };
213
-
214
- const parseNetworks = async (
215
- netCfg?: string[] = [],
216
- dockerCompose?: ?(string | DockerCompose),
217
- ): Promise<ParsedNetworkInfo> => {
218
- const { networks: netMap } = await dockerComposeResolve(dockerCompose);
219
- const networks = netCfg.map((n) => netMap?.[n].name || prefixName(n));
220
- return {
221
- networks,
222
- runArgs: (networks.flatMap((n) => ['--network', n]): string[]),
223
- };
224
- };
225
-
226
- export const dockerComposeCreateNetworks = async (
227
- names?: ?(string[]),
228
- dockerCompose?: ?(string | DockerCompose),
229
- tracker?: DockerComposeResourceTracker = defaultTracker,
230
- ) => {
231
- const { networks = {} } = await dockerComposeResolve(dockerCompose);
232
- await Promise.all(
233
- entries(networks).map(async ([key, val]) => {
234
- const name = val?.name || prefixName(key);
235
- if (!names || names.includes(name)) {
236
- const network = await dockerNetworkCreate(name, (val || {}: any));
237
- if (network) {
238
- tracker.networks.set(name, network);
239
- }
240
- }
241
- }),
242
- );
243
- };
244
-
245
- export const dockerComposeCreateVolumes = async (
246
- names?: string[],
247
- dockerCompose?: ?(string | DockerCompose),
248
- tracker?: DockerComposeResourceTracker = defaultTracker,
249
- ) => {
250
- const { volumes = {} } = await dockerComposeResolve(dockerCompose);
251
- await Promise.all(
252
- entries(volumes).map(async ([key, val]) => {
253
- const name = val?.name || prefixName(key);
254
- if (!names || names.includes(name)) {
255
- const volume = await dockerVolumeCreate(name, (val || {}: any));
256
- if (volume) {
257
- tracker.volumes.set(name, volume);
258
- }
259
- }
260
- }),
261
- );
262
- };
263
-
264
- type HealthCheckFn = (UpResult) => Promise<void>;
265
-
266
- type UpOptions = {
267
- healthCheck?: HealthCheckFn,
268
- avoidConflicts?: boolean,
269
- mapVolumes?: boolean,
270
- mapPorts?: boolean,
271
- cmd?: string[],
272
- tracker?: DockerComposeResourceTracker,
273
- };
274
-
275
- type ServiceNameInfo = {
276
- name: string,
277
- aliases: string[],
278
- suffix: string,
279
- };
280
-
281
- type UpResult = {|
282
- service: DockerComposeService,
283
- container: DockerContainer,
284
- containerName: string,
285
- aliases: string[],
286
- ports: PortMap[],
287
- urls: UrlMap[],
288
- volumes: string[],
289
- |};
290
-
291
- export class DockerComposeService {
292
- #name: string;
293
- #svcDef: DockerComposeServiceDef;
294
- #dockerCompose: ?(DockerCompose | string);
295
- #tracker: DockerComposeResourceTracker = dockerComposeCreateResourceTracker();
296
-
297
- // lazily computed
298
- #parsedPorts: ?ParsedPortInfo = null;
299
- #parsedNetworks: ?ParsedNetworkInfo = null;
300
- #parsedVolumes: ?ParsedVolumeInfo = null;
301
- #baseRunArgs: ?(string[]) = null;
302
-
303
- constructor(
304
- name: string,
305
- serviceDef: DockerComposeServiceDef,
306
- dockerCompose?: ?(DockerCompose | string),
307
- ) {
308
- this.#name = name;
309
- this.#svcDef = serviceDef;
310
- this.#dockerCompose = dockerCompose || null;
311
- }
312
-
313
- get name(): string {
314
- return this.#name;
315
- }
316
-
317
- get serviceDef(): DockerComposeServiceDef {
318
- return this.#svcDef;
319
- }
320
-
321
- get image(): ?string {
322
- return this.#svcDef.image || null;
323
- }
324
-
325
- get defaultContainerName(): string {
326
- return this.#svcDef.container_name || this.#name;
327
- }
328
-
329
- get cmd(): string[] {
330
- return this.#svcDef.command || [];
331
- }
332
-
333
- get envArgs(): string[] {
334
- return parseEnv(this.#svcDef.environment);
335
- }
336
-
337
- /**
338
- * Find (available) container name and alias(es)
339
- * @param {boolean} avoidConflicts if `true`, find a container name that is unused
340
- * @param {number} max maximum number of names to try
341
- */
342
- async getNames(
343
- avoidConflicts?: boolean = false,
344
- max?: number = 100,
345
- ): Promise<ServiceNameInfo> {
346
- /* eslint-disable no-await-in-loop */
347
- for (let i = 0; i < max; i += 1) {
348
- const suffix = i ? `-${i}` : '';
349
- const testName = `${this.defaultContainerName}${suffix}`;
350
- const container = await dockerContainerFind(testName, { all: true });
351
- if (!avoidConflicts || !container) {
352
- return {
353
- name: testName,
354
- aliases: [`${this.name}${suffix}`],
355
- suffix,
356
- };
357
- }
358
- }
359
- /* eslint-enable no-await-in-loop */
360
- throw new Error(
361
- `Failed to find available container name for ${this.defaultContainerName}`,
362
- );
363
- }
364
-
365
- // Get (available) port mappings
366
- async getPorts(
367
- avoidConflicts?: boolean = false,
368
- mapLocal?: boolean = true,
369
- ): Promise<ParsedPortInfo> {
370
- return parsePorts(this.#svcDef.ports, avoidConflicts, mapLocal);
371
- }
372
-
373
- async getDefaultPortInfo(): Promise<ParsedPortInfo> {
374
- if (!this.#parsedPorts) {
375
- this.#parsedPorts = await this.getPorts();
376
- }
377
- return this.#parsedPorts;
378
- }
379
-
380
- async getDefaultPorts(): Promise<PortMap[]> {
381
- const { ports } = await this.getDefaultPortInfo();
382
- return ports;
383
- }
384
-
385
- async getDefaultPortArgs(): Promise<string[]> {
386
- const { runArgs } = await this.getDefaultPortInfo();
387
- return runArgs;
388
- }
389
-
390
- async getDefaultUrls(): Promise<UrlMap[]> {
391
- return this.constructor.getUrls(
392
- await this.getDefaultPorts(),
393
- this.defaultContainerName,
394
- );
395
- }
396
-
397
- async getDefaultNetworkInfo(): Promise<ParsedNetworkInfo> {
398
- if (!this.#parsedNetworks) {
399
- this.#parsedNetworks = await parseNetworks(this.#svcDef.networks);
400
- }
401
- return this.#parsedNetworks;
402
- }
403
-
404
- async getDefaultNetworks(): Promise<string[]> {
405
- const { networks } = await this.getDefaultNetworkInfo();
406
- return networks;
407
- }
408
-
409
- async getDefaultNetworkArgs(): Promise<string[]> {
410
- const { runArgs } = await this.getDefaultNetworkInfo();
411
- return runArgs;
412
- }
413
-
414
- async getDefaultVolumeInfo(): Promise<ParsedVolumeInfo> {
415
- if (!this.#parsedVolumes) {
416
- this.#parsedVolumes = await parseVolumes(this.#svcDef.networks);
417
- }
418
- return this.#parsedVolumes;
419
- }
420
-
421
- async getDefaultVolumes(): Promise<string[]> {
422
- const { volumes } = await this.getDefaultVolumeInfo();
423
- return volumes;
424
- }
425
-
426
- async getDefaultVolumeArgs(): Promise<string[]> {
427
- const { runArgs } = await this.getDefaultVolumeInfo();
428
- return runArgs;
429
- }
430
-
431
- async pull() {
432
- if (!this.image) {
433
- throw new Error(`Cannot pull '${this.name}', no image configured.`);
434
- }
435
- await dockerPull({ image: this.image });
436
- }
437
-
438
- async getBaseRunArgs(): Promise<string[]> {
439
- if (!this.#baseRunArgs) {
440
- const envArgs = parseEnv(this.#svcDef.environment);
441
- const ulArgs = parseULimits(this.#svcDef.ulimits);
442
- const netArgs = await this.getDefaultNetworkArgs();
443
-
444
- this.#baseRunArgs = ['--rm', ...envArgs, ...netArgs, ...ulArgs];
445
- }
446
- return this.#baseRunArgs;
447
- }
448
-
449
- async assembleRunArgs(
450
- containerName?: string = this.defaultContainerName,
451
- aliases?: string[] = [this.name],
452
- additionalArgs?: string[],
453
- ): Promise<string[]> {
454
- const additional = additionalArgs || [
455
- ...(await this.getDefaultPortArgs()),
456
- ...(await this.getDefaultVolumeArgs()),
457
- ];
458
- return [
459
- ...(await this.getBaseRunArgs()),
460
- ...(containerName ? ['--name', containerName] : []),
461
- ...aliases.flatMap((a) => (a ? ['--network-alias', a] : [])),
462
- ...additional,
463
- ];
464
- }
465
-
466
- async getRunArgs(
467
- avoidConflicts?: boolean = false,
468
- mapLocalPorts?: boolean = true,
469
- ): Promise<string[]> {
470
- const { name: cName, aliases, suffix } = await this.getNames(
471
- avoidConflicts,
472
- );
473
- const { runArgs: pArgs } = await this.getPorts(
474
- avoidConflicts,
475
- mapLocalPorts,
476
- );
477
- const { runArgs: vArgs } = await parseVolumes(this.#svcDef.volumes, suffix);
478
- return this.assembleRunArgs(cName, aliases, [...pArgs, ...vArgs]);
479
- }
480
-
481
- async up({
482
- healthCheck,
483
- avoidConflicts = false,
484
- mapVolumes = true,
485
- mapPorts = true,
486
- cmd = this.cmd,
487
- tracker = defaultTracker,
488
- }: UpOptions = {}): Promise<UpResult> {
489
- const { image } = this;
490
- if (!image) {
491
- throw new Error(
492
- `Cannot bring up service '${this.name}', no image defined.`,
493
- );
494
- }
495
- if (this.#tracker.containers.size) {
496
- buildLog(
497
- `Warning: up called on service '${this.name}' with already running container`,
498
- );
499
- }
500
- const { name: containerName, aliases, suffix } = await this.getNames(
501
- avoidConflicts,
502
- );
503
- const { runArgs: pArgs, ports } = await this.getPorts(
504
- avoidConflicts,
505
- mapPorts,
506
- );
507
- const { runArgs: vArgs, volumes } = mapVolumes
508
- ? await parseVolumes(this.#svcDef.volumes, suffix)
509
- : { runArgs: [], volumes: [] };
510
-
511
- let container = await dockerContainerFind(containerName, { all: true });
512
- if (container && !(await container.isRunning())) {
513
- await container.start();
514
- }
515
- if (!container) {
516
- await this.pull();
517
- await dockerComposeCreateNetworks(
518
- await this.getDefaultNetworks(),
519
- this.#dockerCompose,
520
- this.#tracker,
521
- );
522
- await dockerComposeCreateVolumes(
523
- volumes,
524
- this.#dockerCompose,
525
- this.#tracker,
526
- );
527
- const runArgs = await this.assembleRunArgs(containerName, aliases, [
528
- ...pArgs,
529
- ...vArgs,
530
- ]);
531
- container = await dockerContainerRunDaemon({
532
- image,
533
- runArgs,
534
- cmd,
535
- });
536
- } else {
537
- buildLog(`Reusing existing container for '${this.name}' service.`);
538
- }
539
- // This service tracks the things it created
540
- this.#tracker.containers.set(containerName, container);
541
- // The passed tracker needs to track this service
542
- tracker.services.set(this.name, this);
543
-
544
- const idAlias = container.id.slice(0, 12);
545
- aliases.push(idAlias);
546
- const urls = this.constructor.getUrls(ports, idAlias);
547
-
548
- const info: UpResult = {
549
- service: this,
550
- container,
551
- containerName,
552
- aliases,
553
- ports,
554
- volumes,
555
- urls,
556
- };
557
- await healthCheck?.(info);
558
- return info;
559
- }
560
-
561
- async down({
562
- includeDefaults = false,
563
- includeVolumes = false,
564
- includeNetworks = false,
565
- }: {
566
- includeDefaults?: boolean,
567
- includeVolumes?: boolean,
568
- includeNetworks?: boolean,
569
- } = {}) {
570
- buildLog(`Bringing down <${this.name}> service...`);
571
- await dockerComposeTeardown({
572
- tracker: this.#tracker,
573
- includeVolumes,
574
- includeNetworks,
575
- });
576
- if (includeDefaults) {
577
- const container = await dockerContainerFind(this.defaultContainerName);
578
- if (container) {
579
- await container.teardown(true);
580
- }
581
- }
582
- }
583
-
584
- static async parse(
585
- name: string,
586
- force?: boolean = true,
587
- dockerCompose?: ?(DockerCompose | string),
588
- ): Promise<?DockerComposeService> {
589
- const svcDef = await getServiceDef(name, force, dockerCompose);
590
- return svcDef ? new this(name, svcDef, dockerCompose) : null;
591
- }
592
-
593
- static getUrls(ports: PortMap[], alias: string): UrlMap[] {
594
- return ports.map(({ local, docker }) => ({
595
- local: local ? `http://localhost:${local}` : null,
596
- docker: docker ? `http://${alias}:${docker}` : null,
597
- }));
598
- }
599
- }
600
-
601
- export async function dockerComposeGetAllServices(
602
- dockerCompose?: ?(string | DockerCompose),
603
- ): Promise<MapObj<string, DockerComposeService>> {
604
- const { services } = await dockerComposeResolve(dockerCompose);
605
- return mapValuesAsync(services, (s, name) =>
606
- DockerComposeService.parse(name),
607
- );
608
- }
609
-
610
- export async function dockerComposeTeardown({
611
- includeDefaults = false,
612
- includeVolumes = false,
613
- includeNetworks = false,
614
- dockerCompose,
615
- tracker = defaultTracker,
616
- }: {
617
- includeDefaults?: boolean,
618
- includeVolumes?: boolean,
619
- includeNetworks?: boolean,
620
- dockerCompose?: ?(string | DockerCompose),
621
- tracker?: DockerComposeResourceTracker,
622
- } = {}): Promise<void> {
623
- if (!tracker.cleaning) {
624
- // eslint-disable-next-line no-param-reassign
625
- tracker.cleaning = (async () => {
626
- if (tracker.services.size) {
627
- buildLog('Bringing down started docker services...');
628
- const promises = Promise.all(
629
- Array.from(tracker.services.values()).map(async (s) =>
630
- s.down({ includeVolumes, includeNetworks }),
631
- ),
632
- );
633
- tracker.services.clear();
634
- await promises;
635
- }
636
- if (includeDefaults) {
637
- const { services } = await dockerComposeResolve(dockerCompose);
638
- const svcNames = keys(services);
639
- if (svcNames.length) {
640
- buildLog('Bringing down default docker services...');
641
- await Promise.all(
642
- svcNames.map(async (s) =>
643
- (await DockerComposeService.parse(s))?.down({
644
- includeDefaults,
645
- includeVolumes,
646
- includeNetworks,
647
- }),
648
- ),
649
- );
650
- }
651
- }
652
-
653
- if (tracker.containers.size) {
654
- buildLog('Stopping created docker containers...');
655
- const promises = Promise.all(
656
- Array.from(tracker.containers.values()).map(async (c) =>
657
- c.teardown(true),
658
- ),
659
- );
660
- tracker.containers.clear();
661
- await promises;
662
- }
663
-
664
- if (includeVolumes) {
665
- if (tracker.volumes.size) {
666
- buildLog('Removing created docker volumes...');
667
- const promises = Promise.all(
668
- Array.from(tracker.volumes.values()).map(async (v) => v.rm()),
669
- );
670
- tracker.volumes.clear();
671
- await promises;
672
- }
673
- if (includeDefaults) {
674
- buildLog('Removing default docker volumes...');
675
- const { volumes } = await dockerComposeResolve(dockerCompose);
676
- await Promise.all(
677
- entries(volumes).map(async ([key, val]) => {
678
- const name = val?.name || prefixName(key);
679
- await dockerVolumeRm(name, true);
680
- }),
681
- );
682
- }
683
- }
684
-
685
- if (includeNetworks) {
686
- if (tracker.networks.size) {
687
- buildLog('Removing created docker networks...');
688
- const promises = Promise.all(
689
- Array.from(tracker.networks.values()).map(async (n) => n.rm()),
690
- );
691
- tracker.networks.clear();
692
- await promises;
693
- }
694
- if (includeDefaults) {
695
- buildLog('Removing default docker networks...');
696
- const { networks } = await dockerComposeResolve(dockerCompose);
697
- await Promise.all(
698
- entries(networks).map(async ([key, val]) => {
699
- const name = val?.name || prefixName(key);
700
- try {
701
- await dockerNetworkDelete(name);
702
- } catch (err) {
703
- buildLog(`Error deleting network '${name}': ${err.message}`);
704
- }
705
- }),
706
- );
707
- }
708
- }
709
- // eslint-disable-next-line no-param-reassign
710
- tracker.cleaning = null;
711
- })();
712
- }
713
- return tracker.cleaning;
714
- }
715
-
716
- export type DockerContainerInfo = {|
717
- ...UpResult,
718
- id: string,
719
- image: string,
720
- name?: ?string,
721
-
722
- // for convenience, the first port mapping info
723
- port?: ?number,
724
- dockerPort?: ?number,
725
- url?: ?string,
726
- dockerUrl?: ?string,
727
- |};
728
-
729
- export async function dockerComposeRunService(
730
- key: string,
731
- upOptions?: UpOptions = {},
732
- dockerCompose?: ?(string | DockerCompose),
733
- ): Promise<DockerContainerInfo> {
734
- const service: ?DockerComposeService = await DockerComposeService.parse(
735
- key,
736
- false,
737
- dockerCompose,
738
- );
739
- if (!service) {
740
- throw new Error(`Failed to find service '${key}'`);
741
- }
742
- buildLog(`Starting <${service.name}> service...`);
743
- const upResult: UpResult = await service.up(upOptions);
744
- const {
745
- container,
746
- urls,
747
- urls: [{ local: url, docker: dockerUrl }],
748
- ports: [{ local: port, docker: dockerPort }],
749
- } = upResult;
750
- const { id, name, image } = container;
751
- urls.forEach(
752
- ({ local }) =>
753
- local && buildLog(`<${service.name}> accessible at ${local}`),
754
- );
755
- return {
756
- ...upResult,
757
- id,
758
- image,
759
- name,
760
- port,
761
- dockerPort,
762
- url,
763
- dockerUrl,
764
- };
765
- }