@automattic/vip 3.25.2-dev.0 → 3.25.3-dev.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.
@@ -15,9 +15,14 @@ exports.landoShell = landoShell;
15
15
  exports.landoStart = landoStart;
16
16
  exports.landoStop = landoStop;
17
17
  exports.removeProxyCache = removeProxyCache;
18
+ exports.tryResolveDomains = tryResolveDomains;
18
19
  exports.validateDockerInstalled = validateDockerInstalled;
19
20
  var _chalk = _interopRequireDefault(require("chalk"));
20
21
  var _debug = _interopRequireDefault(require("debug"));
22
+ var _bootstrap = require("lando/lib/bootstrap");
23
+ var _lando = _interopRequireDefault(require("lando/lib/lando"));
24
+ var _utils = _interopRequireDefault(require("lando/plugins/lando-core/lib/utils"));
25
+ var _build = _interopRequireDefault(require("lando/plugins/lando-tooling/lib/build"));
21
26
  var _nodeChild_process = require("node:child_process");
22
27
  var _promises = require("node:dns/promises");
23
28
  var _promises2 = require("node:fs/promises");
@@ -27,12 +32,11 @@ var _nodeUtil = require("node:util");
27
32
  var _semver = require("semver");
28
33
  var _devEnvironmentCore = require("./dev-environment-core");
29
34
  var _dockerUtils = require("./docker-utils");
30
- var _landoLoader = require("./lando-loader");
31
- var _runtimeMode = require("../cli/runtime-mode");
32
35
  var _devEnvironment = require("../constants/dev-environment");
33
36
  var _env = _interopRequireDefault(require("../env"));
34
37
  var _userError = _interopRequireDefault(require("../user-error"));
35
38
  var _xdgData = require("../xdg-data");
39
+ var _hostsUpdater = require("./hosts-updater");
36
40
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
37
41
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
38
42
  /**
@@ -41,44 +45,6 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
41
45
  const DEBUG_KEY = '@automattic/vip:bin:dev-environment';
42
46
  const debug = (0, _debug.default)(DEBUG_KEY);
43
47
  const execFileAsync = (0, _nodeUtil.promisify)(_nodeChild_process.execFile);
44
- const unwrapLandoModuleDefault = loaded => {
45
- if (loaded && typeof loaded === 'object' && 'default' in loaded) {
46
- return loaded.default;
47
- }
48
- return loaded;
49
- };
50
- let landoConstructor = null;
51
- let landoBuildTaskFn = null;
52
- let landoUtilsModule = null;
53
- let buildConfigFn = null;
54
- const getLandoConstructor = () => {
55
- if (!landoConstructor) {
56
- landoConstructor = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/lib/lando'));
57
- }
58
- return landoConstructor;
59
- };
60
- const getLandoBuildTask = () => {
61
- if (!landoBuildTaskFn) {
62
- landoBuildTaskFn = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/plugins/lando-tooling/lib/build'));
63
- }
64
- return landoBuildTaskFn;
65
- };
66
- const getLandoUtils = () => {
67
- if (!landoUtilsModule) {
68
- landoUtilsModule = unwrapLandoModuleDefault((0, _landoLoader.loadLandoModule)('lando/plugins/lando-core/lib/utils'));
69
- }
70
- return landoUtilsModule;
71
- };
72
- const getLandoBuildConfig = () => {
73
- if (!buildConfigFn) {
74
- const loaded = (0, _landoLoader.loadLandoModule)('lando/lib/bootstrap');
75
- buildConfigFn = loaded.buildConfig ?? loaded.default?.buildConfig ?? null;
76
- if (!buildConfigFn) {
77
- throw new Error('Unable to load Lando bootstrap buildConfig.');
78
- }
79
- }
80
- return buildConfigFn;
81
- };
82
48
  const bannerLabelWidth = 18;
83
49
  let logPathRegistered = false;
84
50
  let resolvedLogPath = null;
@@ -182,7 +148,7 @@ const writeLogBanner = async config => {
182
148
  });
183
149
  const dockerVersions = await getDockerVersions(config);
184
150
  const command = process.argv.slice(1).join(' ');
185
- const bannerLines = ['=== VIP Dev Env Log ===', formatBannerLine('COMMAND', command), formatBannerLine('OS', `${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`), formatBannerLine('NODE', _env.default.node.version), formatBannerLine('VIP-CLI', _env.default.app.version), formatBannerLine('RUNTIME', (0, _runtimeMode.getRuntimeModeLabel)()), formatBannerLine('DOCKER ENGINE', dockerVersions.engine), formatBannerLine('DOCKER COMPOSE', dockerVersions.compose), formatBannerLine('COMPOSE PLUGIN', dockerVersions.composePlugin), formatBannerLine('DOCKER BIN', config.dockerBin ?? 'unknown'), formatBannerLine('COMPOSE BIN', config.composeBin ?? 'unknown'), formatBannerLine('RAM', formatBytes((0, _nodeOs.totalmem)())), formatBannerLine('CPU', String((0, _nodeOs.cpus)().length)), '===', '', ''];
151
+ const bannerLines = ['=== VIP Dev Env Log ===', formatBannerLine('COMMAND', command), formatBannerLine('OS', `${_env.default.os.name} ${_env.default.os.version} ${_env.default.os.arch}`), formatBannerLine('NODE', _env.default.node.version), formatBannerLine('VIP-CLI', _env.default.app.version), formatBannerLine('DOCKER ENGINE', dockerVersions.engine), formatBannerLine('DOCKER COMPOSE', dockerVersions.compose), formatBannerLine('COMPOSE PLUGIN', dockerVersions.composePlugin), formatBannerLine('DOCKER BIN', config.dockerBin ?? 'unknown'), formatBannerLine('COMPOSE BIN', config.composeBin ?? 'unknown'), formatBannerLine('RAM', formatBytes((0, _nodeOs.totalmem)())), formatBannerLine('CPU', String((0, _nodeOs.cpus)().length)), '===', '', ''];
186
152
  await (0, _promises2.writeFile)(logFilePath, bannerLines.join('\n'), {
187
153
  flag: 'a'
188
154
  });
@@ -193,7 +159,7 @@ const writeLogBanner = async config => {
193
159
  */
194
160
  async function getLandoConfig(options = {}) {
195
161
  // The path will be smth like `yarn/global/node_modules/lando/lib/lando.js`; we need the path up to `lando` (inclusive)
196
- const landoPath = (0, _nodePath.dirname)((0, _nodePath.dirname)((0, _landoLoader.resolveLandoModule)('lando')));
162
+ const landoPath = (0, _nodePath.dirname)((0, _nodePath.dirname)(require.resolve('lando')));
197
163
  debug(`Getting Lando config, using paths '${landoPath}' for plugins`);
198
164
  const isLandoDebugSelected = _debug.default.enabled(DEBUG_KEY);
199
165
  const isAllDebugSelected = _debug.default.enabled('"*"');
@@ -237,7 +203,7 @@ async function getLandoConfig(options = {}) {
237
203
  LANDO_HOST_GROUP_ID: process.platform === 'win32' ? '1000' : `${(0, _nodeOs.userInfo)().gid}`
238
204
  }
239
205
  };
240
- return getLandoBuildConfig()(config);
206
+ return (0, _bootstrap.buildConfig)(config);
241
207
  }
242
208
  const appMap = new Map();
243
209
  async function initLandoApplication(lando, instancePath) {
@@ -326,8 +292,7 @@ async function bootstrapLando(options = {}) {
326
292
  }
327
293
  registerLogPathOutput(config, Boolean(options.quiet));
328
294
  await writeLogBanner(config);
329
- const LandoClass = getLandoConstructor();
330
- const lando = new LandoClass(config);
295
+ const lando = new _lando.default(config);
331
296
  _debug.default.log = (message, ...args) => {
332
297
  lando.log.debug(message, ...args);
333
298
  };
@@ -360,11 +325,32 @@ async function bootstrapLando(options = {}) {
360
325
  debug('bootstrapLando() took %d ms', duration);
361
326
  }
362
327
  }
363
- async function landoStart(lando, instancePath) {
328
+ const autofixedApps = new WeakSet();
329
+ function installDnsAutofixer(app) {
330
+ if (autofixedApps.has(app)) {
331
+ return;
332
+ }
333
+ autofixedApps.add(app);
334
+ app.events.on('post-start', 9, async () => {
335
+ const urlsToScan = [];
336
+ app.info.filter(service => service.urls.length).forEach(service => {
337
+ service.urls.forEach(url => {
338
+ if (!/^https?:\/\/(localhost|127\.0\.0\.1):/.exec(url) && !url.includes('*')) {
339
+ urlsToScan.push(url);
340
+ }
341
+ });
342
+ });
343
+ await tryResolveDomains(urlsToScan, true);
344
+ });
345
+ }
346
+ async function landoStart(lando, instancePath, autoFixDomainResolution = false) {
364
347
  const started = new Date();
365
348
  try {
366
349
  debug('Will start lando app on path:', instancePath);
367
350
  const app = await getLandoApplication(lando, instancePath);
351
+ if (autoFixDomainResolution) {
352
+ installDnsAutofixer(app);
353
+ }
368
354
  await app.start();
369
355
  } finally {
370
356
  const duration = new Date().getTime() - started.getTime();
@@ -388,11 +374,14 @@ async function landoLogs(lando, instancePath, options) {
388
374
  debug('landoLogs() took %d ms', duration);
389
375
  }
390
376
  }
391
- async function landoRebuild(lando, instancePath) {
377
+ async function landoRebuild(lando, instancePath, autoFixDomainResolution = false) {
392
378
  const started = new Date();
393
379
  try {
394
380
  debug('Will rebuild lando app on path:', instancePath);
395
381
  const app = await getLandoApplication(lando, instancePath);
382
+ if (autoFixDomainResolution) {
383
+ installDnsAutofixer(app);
384
+ }
396
385
  await ensureNoOrphantProxyContainer(lando);
397
386
  await app.rebuild();
398
387
  } finally {
@@ -462,7 +451,7 @@ async function landoInfo(lando, instancePath, options = {}) {
462
451
  const started = new Date();
463
452
  try {
464
453
  const app = await getLandoApplication(lando, instancePath);
465
- const info = getLandoUtils().startTable(app);
454
+ const info = _utils.default.startTable(app);
466
455
  const reachableServices = app.info.filter(service => service.urls.length);
467
456
  reachableServices.forEach(service => info[`${service.service} urls`] = service.urls);
468
457
  const health = await checkEnvHealth(lando, app);
@@ -566,7 +555,7 @@ async function getExtraServicesConnections(lando, app) {
566
555
  }
567
556
  return extraServices;
568
557
  }
569
- async function tryResolveDomains(urls) {
558
+ async function tryResolveDomains(urls, autofix) {
570
559
  const domains = [...new Set(urls.filter(url => url.toLowerCase().startsWith('http')).map(url => {
571
560
  try {
572
561
  return new URL(url).hostname;
@@ -575,6 +564,7 @@ async function tryResolveDomains(urls) {
575
564
  }
576
565
  }).filter(domain => domain !== undefined))];
577
566
  const domainsToFix = [];
567
+ const pendingWarnings = [];
578
568
  for (const domain of domains) {
579
569
  try {
580
570
  // eslint-disable-next-line no-await-in-loop
@@ -582,20 +572,72 @@ async function tryResolveDomains(urls) {
582
572
  debug('%s resolves to %s', domain, address.address);
583
573
  if (address.address !== '127.0.0.1') {
584
574
  domainsToFix.push(domain);
585
- console.warn(_chalk.default.yellow.bold('WARNING:'), `${domain} resolves to ${address.address} instead of 127.0.0.1. Things may not work as expected.`);
575
+ pendingWarnings.push(`${domain} resolves to ${address.address} instead of 127.0.0.1. Things may not work as expected.`);
586
576
  }
587
577
  } catch (err) {
588
578
  const msg = err instanceof Error ? err.message : 'Unknown error';
589
579
  domainsToFix.push(domain);
590
- console.warn(_chalk.default.yellow.bold('WARNING:'), `Failed to resolve ${domain}: ${msg}`);
580
+ pendingWarnings.push(`Failed to resolve ${domain}: ${msg}`);
591
581
  }
592
582
  }
593
583
  if (domainsToFix.length) {
584
+ if (autofix) {
585
+ console.log(_chalk.default.green('Attempting to fix domain resolution issues...'));
586
+ const result = await autofixDomains(domainsToFix);
587
+ if (result instanceof Error) {
588
+ // Autofix failed — surface the original DNS warnings so the user knows what went wrong
589
+ pendingWarnings.forEach(msg => console.warn(_chalk.default.yellow.bold('WARNING:'), msg));
590
+ console.error(_chalk.default.red(result.message));
591
+ if (result.cause) {
592
+ console.error(_chalk.default.red('Cause: '), result.cause.message);
593
+ }
594
+ } else {
595
+ // Autofix succeeded — suppress the warnings so a clean start looks clean
596
+ console.log(_chalk.default.green('Domain resolution issues fixed successfully.'));
597
+ return;
598
+ }
599
+ } else {
600
+ pendingWarnings.forEach(msg => console.warn(_chalk.default.yellow.bold('WARNING:'), msg));
601
+ }
594
602
  console.warn(_chalk.default.yellow('Please add the following lines to the hosts file on your system:\n'));
595
603
  console.warn(domainsToFix.map(domain => `127.0.0.1 ${domain}`).join('\n'));
596
604
  console.warn(_chalk.default.yellow('\nLearn more: https://docs.wpvip.com/vip-local-development-environment/troubleshooting-dev-env/#h-resolve-networking-configuration-issues\n'));
597
605
  }
598
606
  }
607
+ function ensureError(error) {
608
+ if (error instanceof Error) {
609
+ return error;
610
+ }
611
+ return new Error(String(error));
612
+ }
613
+ const AUTOFIX_DOWNLOAD_TIMEOUT_MS = 30_000;
614
+ async function autofixDomains(domains) {
615
+ const dir = await (0, _hostsUpdater.getInstallDir)();
616
+ const filename = (0, _hostsUpdater.getExeName)();
617
+ let binary = _nodePath.default.join(dir, filename);
618
+ try {
619
+ await (0, _promises2.access)(binary, _promises2.constants.X_OK);
620
+ } catch {
621
+ try {
622
+ binary = await (0, _hostsUpdater.installBinary)('latest', dir, AUTOFIX_DOWNLOAD_TIMEOUT_MS);
623
+ } catch (err) {
624
+ return new Error('Failed to install hosts updater binary, cannot autofix domain resolution issues.', {
625
+ cause: ensureError(err)
626
+ });
627
+ }
628
+ }
629
+ const fixableDomains = domains.filter(domain => !domain.includes('*'));
630
+ if (fixableDomains.length) {
631
+ try {
632
+ await (0, _hostsUpdater.updateDomains)(binary, fixableDomains);
633
+ } catch (err) {
634
+ return new Error('Failed to update hosts file, cannot autofix domain resolution issues.', {
635
+ cause: ensureError(err)
636
+ });
637
+ }
638
+ }
639
+ return true;
640
+ }
599
641
  async function getRunningServicesForProject(docker, project) {
600
642
  const containers = await docker.listContainers({
601
643
  filters: {
@@ -616,7 +658,7 @@ async function checkEnvHealth(lando, app) {
616
658
  });
617
659
  });
618
660
  const urlsToScan = Object.keys(urls).filter(url => !url.includes('*'));
619
- await tryResolveDomains(urlsToScan);
661
+ await tryResolveDomains(urlsToScan, false);
620
662
  app.urls.forEach(entry => {
621
663
  // We use different status codes to see if the service is up.
622
664
  // We may consider the service is up when Lando considers it is down.
@@ -675,7 +717,7 @@ async function landoExec(lando, instancePath, toolName, args, options) {
675
717
  if (options.stdio) {
676
718
  tool.stdio = options.stdio;
677
719
  }
678
- const task = getLandoBuildTask()(tool, lando);
720
+ const task = (0, _build.default)(tool, lando);
679
721
  const argv = {
680
722
  // eslint-disable-next-line id-length
681
723
  _: args
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.InvalidChecksumError = exports.DownloadError = void 0;
5
+ exports.download = download;
6
+ exports.getExeName = getExeName;
7
+ exports.getInstallDir = getInstallDir;
8
+ exports.getReleaseUrl = getReleaseUrl;
9
+ exports.installBinary = installBinary;
10
+ exports.updateDomains = updateDomains;
11
+ var _nodeFetch = _interopRequireDefault(require("node-fetch"));
12
+ var _nodeChild_process = require("node:child_process");
13
+ var _nodeCrypto = require("node:crypto");
14
+ var _nodeFs = require("node:fs");
15
+ var _promises = require("node:fs/promises");
16
+ var _nodeOs = require("node:os");
17
+ var _nodePath = require("node:path");
18
+ var _nodeStream = require("node:stream");
19
+ var _promises2 = require("node:stream/promises");
20
+ var _nodeUtil = require("node:util");
21
+ var _nodeZlib = require("node:zlib");
22
+ var _proxyAgent = require("../http/proxy-agent");
23
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
24
+ class DownloadError extends Error {
25
+ constructor(url, code, options) {
26
+ super((0, _nodeUtil.format)('Failed to download file: %s (status code: %d)', url, code), options);
27
+ this.name = 'DownloadError';
28
+ }
29
+ }
30
+ exports.DownloadError = DownloadError;
31
+ class InvalidChecksumError extends Error {
32
+ constructor(message, options) {
33
+ super(message, options);
34
+ this.name = 'InvalidChecksumError';
35
+ }
36
+ }
37
+ exports.InvalidChecksumError = InvalidChecksumError;
38
+ const archMap = {
39
+ ia32: '386',
40
+ x64: 'amd64',
41
+ arm64: 'arm64'
42
+ };
43
+ const platformMap = {
44
+ win32: 'windows',
45
+ darwin: 'darwin',
46
+ linux: 'linux'
47
+ };
48
+ function getReleaseUrl(version = 'latest', arch = process.arch, platform = process.platform) {
49
+ const resolvedArch = archMap[arch];
50
+ const resolvedPlatform = platformMap[platform];
51
+ if (!resolvedArch || !resolvedPlatform) {
52
+ throw new Error('Unsupported platform or architecture');
53
+ }
54
+ const suffix = 'windows' === resolvedPlatform ? '.exe' : '';
55
+ if (version !== 'latest') {
56
+ const binary = `https://github.com/Automattic/dev-env-update-hosts/releases/download/${version}/dev-env-update-hosts-${resolvedPlatform}-${resolvedArch}${suffix}.gz`;
57
+ const checksum = `${binary}.sum`;
58
+ return [binary, checksum];
59
+ }
60
+ const binary = `https://github.com/Automattic/dev-env-update-hosts/releases/latest/download/dev-env-update-hosts-${resolvedPlatform}-${resolvedArch}${suffix}.gz`;
61
+ const checksum = `${binary}.sum`;
62
+ return [binary, checksum];
63
+ }
64
+ async function download(url, asText, timeout = 0) {
65
+ const controller = new AbortController();
66
+ const timeoutId = timeout > 0 ? setTimeout(() => controller.abort(), timeout) : null;
67
+ const clearTimer = () => {
68
+ if (timeoutId) {
69
+ clearTimeout(timeoutId);
70
+ }
71
+ };
72
+ const proxyAgent = (0, _proxyAgent.createProxyAgent)(url.toString());
73
+ let response;
74
+ try {
75
+ response = await (0, _nodeFetch.default)(url, {
76
+ signal: controller.signal,
77
+ redirect: 'follow',
78
+ agent: proxyAgent ?? undefined
79
+ });
80
+ } catch (err) {
81
+ clearTimer();
82
+ throw err;
83
+ }
84
+ if (!response.ok) {
85
+ clearTimer();
86
+ throw new DownloadError(url, response.status);
87
+ }
88
+ if (asText) {
89
+ try {
90
+ return await response.text();
91
+ } finally {
92
+ clearTimer();
93
+ }
94
+ }
95
+
96
+ // For streams: unref the timer so it will not prevent process exit once the
97
+ // body has been fully consumed, but it will still abort a stalled read while
98
+ // the event loop is kept alive by the active stream pipeline.
99
+ timeoutId?.unref();
100
+ return response.body;
101
+ }
102
+ function getExeName(platform = process.platform, arch = process.arch) {
103
+ const exeSuffix = platform === 'win32' ? '.exe' : '';
104
+ return `dev-env-update-host-${platform}-${arch}${exeSuffix}`;
105
+ }
106
+ async function installBinary(version, dest, timeout = 0, arch = process.arch, platform = process.platform) {
107
+ const [binaryUrl, checksumUrl] = getReleaseUrl(version, arch, platform);
108
+ const checksum = (await download(new URL(checksumUrl), true, timeout)).trim();
109
+ const compressedStream = await download(new URL(binaryUrl), false, timeout);
110
+ if (!compressedStream) {
111
+ throw new Error('Failed to download binary');
112
+ }
113
+ const hash = (0, _nodeCrypto.createHash)('sha256');
114
+ const hashTap = new _nodeStream.Transform({
115
+ transform(chunk, _encoding, callback) {
116
+ hash.update(chunk);
117
+ callback(null, chunk);
118
+ }
119
+ });
120
+ const destFilename = (0, _nodePath.join)(dest, getExeName(platform, arch));
121
+ // Use a unique temp name to avoid collisions when multiple processes install concurrently.
122
+ const tempFilename = `${destFilename}.${(0, _nodeCrypto.randomBytes)(8).toString('hex')}.tmp`;
123
+ const outStream = (0, _nodeFs.createWriteStream)(tempFilename, {
124
+ mode: 0o755
125
+ });
126
+ let removeTmp = true;
127
+ try {
128
+ await (0, _promises2.pipeline)(compressedStream, hashTap, (0, _nodeZlib.createGunzip)(), outStream);
129
+ const calculatedChecksum = hash.digest('hex');
130
+ if (!(0, _nodeCrypto.timingSafeEqual)(Buffer.from(calculatedChecksum, 'hex'), Buffer.from(checksum, 'hex'))) {
131
+ throw new InvalidChecksumError((0, _nodeUtil.format)('Downloaded file checksum does not match expected value (expected: %s, got: %s)', checksum, calculatedChecksum));
132
+ }
133
+ await (0, _promises.rename)(tempFilename, destFilename);
134
+ removeTmp = false;
135
+ } finally {
136
+ if (removeTmp) {
137
+ await (0, _promises.rm)(tempFilename, {
138
+ force: true
139
+ }).catch(err => {
140
+ console.warn('Error removing temporary file %s: %s', tempFilename, err);
141
+ });
142
+ }
143
+ }
144
+ return destFilename;
145
+ }
146
+ async function getInstallDir() {
147
+ const binDir = (0, _nodePath.join)((0, _nodePath.dirname)(__dirname), 'bin');
148
+ try {
149
+ await (0, _promises.mkdir)(binDir, {
150
+ recursive: true
151
+ });
152
+ await (0, _promises.access)(binDir, _promises.constants.W_OK);
153
+ return binDir;
154
+ } catch {
155
+ // Swallow errors and fall back to a temporary directory
156
+ }
157
+ const tmpDir = await (0, _promises.mkdtemp)((0, _nodePath.join)((0, _nodeOs.tmpdir)(), 'dev-env-update-hosts-'));
158
+ process.once('exit', () => {
159
+ try {
160
+ (0, _nodeFs.rmSync)(tmpDir, {
161
+ recursive: true,
162
+ force: true
163
+ });
164
+ } catch (err) {
165
+ console.warn('Error removing temporary dir: %s', err);
166
+ }
167
+ });
168
+ return tmpDir;
169
+ }
170
+ function updateDomains(binary, domains) {
171
+ return new Promise((resolve, reject) => {
172
+ const child = (0, _nodeChild_process.spawn)(binary, domains, {
173
+ stdio: 'inherit'
174
+ });
175
+ child.on('error', err => reject(err));
176
+ child.on('exit', code => {
177
+ if (code === 0) {
178
+ resolve();
179
+ } else {
180
+ reject(new Error(`Binary exited with code ${code}`));
181
+ }
182
+ });
183
+ });
184
+ }