mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Update dependencies (multibuild, dockerode, docker-toolbelt, docker-progress)
Update resin-multibuild from 4.7.2 to 4.11.0 Change-type: patch
This commit is contained in:
parent
d9821939d9
commit
2c922ee6d2
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 Balena Ltd.
|
||||
* Copyright 2016-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -220,7 +220,7 @@ ${dockerignoreHelp}
|
||||
* @param opts
|
||||
*/
|
||||
protected async buildProject(
|
||||
docker: import('docker-toolbelt'),
|
||||
docker: import('dockerode'),
|
||||
logger: import('../utils/logger'),
|
||||
composeOpts: ComposeOpts,
|
||||
opts: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 Balena Ltd.
|
||||
* Copyright 2016-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -229,7 +229,7 @@ ${dockerignoreHelp}
|
||||
}
|
||||
|
||||
async deployProject(
|
||||
docker: import('docker-toolbelt'),
|
||||
docker: import('dockerode'),
|
||||
logger: import('../utils/logger'),
|
||||
composeOpts: ComposeOpts,
|
||||
opts: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Balena Ltd.
|
||||
* Copyright 2017-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -92,13 +92,13 @@ export default class ScanCmd extends Command {
|
||||
);
|
||||
const engineReachableDevices: boolean[] = await Promise.all(
|
||||
localDevices.map(async ({ address }: { address: string }) => {
|
||||
const docker = dockerUtils.createClient({
|
||||
const docker = await dockerUtils.createClient({
|
||||
host: address,
|
||||
port: dockerPort,
|
||||
timeout: dockerTimeout,
|
||||
}) as any;
|
||||
});
|
||||
try {
|
||||
await docker.pingAsync();
|
||||
await docker.ping();
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
@ -132,14 +132,14 @@ export default class ScanCmd extends Command {
|
||||
// Query devices for info
|
||||
const devicesInfo = await Promise.all(
|
||||
developmentDevices.map(async ({ host, address }) => {
|
||||
const docker = dockerUtils.createClient({
|
||||
const docker = await dockerUtils.createClient({
|
||||
host: address,
|
||||
port: dockerPort,
|
||||
timeout: dockerTimeout,
|
||||
}) as any;
|
||||
});
|
||||
const [dockerInfo, dockerVersion] = await Promise.all([
|
||||
docker.infoAsync().catchReturn('Could not get Docker info'),
|
||||
docker.versionAsync().catchReturn('Could not get Docker version'),
|
||||
docker.info(),
|
||||
docker.version(),
|
||||
]);
|
||||
return {
|
||||
host,
|
||||
@ -165,7 +165,13 @@ export default class ScanCmd extends Command {
|
||||
});
|
||||
}
|
||||
|
||||
const cmdOutput = productionDevicesInfo.concat(devicesInfo);
|
||||
const cmdOutput: Array<{
|
||||
host: string;
|
||||
address: string;
|
||||
osVariant: string;
|
||||
dockerInfo: any;
|
||||
dockerVersion: import('dockerode').DockerVersion | undefined;
|
||||
}> = [...productionDevicesInfo, ...devicesInfo];
|
||||
|
||||
// Output results
|
||||
if (!options.json && cmdOutput.length === 0) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2017-2020 Balena Ltd.
|
||||
* Copyright 2017-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -221,7 +221,7 @@ export const createRelease = async function (
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('docker-toolbelt')} docker
|
||||
* @param {import('dockerode')} docker
|
||||
* @param {Array<import('./compose-types').BuiltImage>} images
|
||||
* @param {Partial<import('balena-release/build/models').ImageModel>} serviceImages
|
||||
* @returns {Promise<Array<import('./compose-types').TaggedImage>>}
|
||||
@ -255,12 +255,11 @@ export const tagServiceImages = (docker, images, serviceImages) =>
|
||||
|
||||
/**
|
||||
* @param {*} sdk
|
||||
* @param {import('docker-toolbelt')} docker
|
||||
* @param {import('./logger')} logger
|
||||
* @param {number} appID
|
||||
* @returns {Promise<string[]>}
|
||||
*/
|
||||
export const getPreviousRepos = (sdk, docker, logger, appID) =>
|
||||
export const getPreviousRepos = (sdk, logger, appID) =>
|
||||
sdk.pine
|
||||
.get({
|
||||
resource: 'release',
|
||||
@ -283,17 +282,15 @@ export const getPreviousRepos = (sdk, docker, logger, appID) =>
|
||||
// grab all images from the latest release, return all image locations in the registry
|
||||
if (release.length > 0) {
|
||||
const images = release[0].contains__image;
|
||||
const { getRegistryAndName } = require('resin-multibuild');
|
||||
return Promise.all(
|
||||
images.map(function (d) {
|
||||
const imageName = d.image[0].is_stored_at__image_location;
|
||||
return docker
|
||||
.getRegistryAndName(imageName)
|
||||
.then(function (registry) {
|
||||
logger.logDebug(
|
||||
`Requesting access to previously pushed image repo (${registry.imageName})`,
|
||||
);
|
||||
return registry.imageName;
|
||||
});
|
||||
const imageName = d.image[0].is_stored_at__image_location || '';
|
||||
const registry = getRegistryAndName(imageName);
|
||||
logger.logDebug(
|
||||
`Requesting access to previously pushed image repo (${registry.imageName})`,
|
||||
);
|
||||
return registry.imageName;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
@ -339,7 +336,7 @@ export const authorizePush = function (
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('docker-toolbelt')} docker
|
||||
* @param {import('dockerode')} docker
|
||||
* @param {string} token
|
||||
* @param {Array<import('./compose-types').TaggedImage>} images
|
||||
* @param {(serviceImage: import('balena-release/build/models').ImageModel, props: object) => void} afterEach
|
||||
@ -357,7 +354,7 @@ export const pushAndUpdateServiceImages = function (
|
||||
|
||||
const opts = { authconfig: { registrytoken: token } };
|
||||
|
||||
const progress = new DockerProgress({ dockerToolbelt: docker });
|
||||
const progress = new DockerProgress({ docker });
|
||||
const renderer = pushProgressRenderer(
|
||||
tty,
|
||||
getChalk().blue('[Push]') + ' ',
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018-2020 Balena Ltd.
|
||||
* Copyright 2018-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -1249,7 +1249,6 @@ export async function validateProjectDirectory(
|
||||
}
|
||||
|
||||
async function getTokenForPreviousRepos(
|
||||
docker: import('docker-toolbelt'),
|
||||
logger: Logger,
|
||||
appId: number,
|
||||
apiEndpoint: string,
|
||||
@ -1258,7 +1257,7 @@ async function getTokenForPreviousRepos(
|
||||
logger.logDebug('Authorizing push...');
|
||||
const { authorizePush, getPreviousRepos } = await import('./compose');
|
||||
const sdk = getBalenaSdk();
|
||||
const previousRepos = await getPreviousRepos(sdk, docker, logger, appId);
|
||||
const previousRepos = await getPreviousRepos(sdk, logger, appId);
|
||||
|
||||
const token = await authorizePush(
|
||||
sdk,
|
||||
@ -1271,7 +1270,7 @@ async function getTokenForPreviousRepos(
|
||||
}
|
||||
|
||||
async function pushServiceImages(
|
||||
docker: import('docker-toolbelt'),
|
||||
docker: import('dockerode'),
|
||||
logger: Logger,
|
||||
pineClient: ReturnType<typeof import('balena-release').createClient>,
|
||||
taggedImages: TaggedImage[],
|
||||
@ -1295,7 +1294,7 @@ async function pushServiceImages(
|
||||
}
|
||||
|
||||
export async function deployProject(
|
||||
docker: import('docker-toolbelt'),
|
||||
docker: import('dockerode'),
|
||||
logger: Logger,
|
||||
composition: Composition,
|
||||
images: BuiltImage[],
|
||||
@ -1332,7 +1331,6 @@ export async function deployProject(
|
||||
const taggedImages = await tagServiceImages(docker, images, serviceImages);
|
||||
try {
|
||||
const token = await getTokenForPreviousRepos(
|
||||
docker,
|
||||
logger,
|
||||
appId,
|
||||
apiEndpoint,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Balena Ltd.
|
||||
* Copyright 2017-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -31,7 +31,7 @@ const getBuilderLogPushEndpoint = function (baseUrl, buildId, owner, app) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('docker-toolbelt')} docker
|
||||
* @param {import('dockerode')} docker
|
||||
* @param {string} imageId
|
||||
* @param {string} bufferFile
|
||||
*/
|
||||
@ -156,7 +156,7 @@ const uploadLogs = function (logs, token, url, buildId, username, appName) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('docker-toolbelt')} docker
|
||||
* @param {import('dockerode')} docker
|
||||
* @param {import('./logger')} logger
|
||||
* @param {string} token
|
||||
* @param {string} username
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018-2020 Balena Ltd.
|
||||
* Copyright 2018-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -355,7 +355,7 @@ export async function performBuilds(
|
||||
}
|
||||
|
||||
logger.logDebug('Starting builds...');
|
||||
await assignOutputHandlers(buildTasks, logger, logHandlers);
|
||||
assignOutputHandlers(buildTasks, logger, logHandlers);
|
||||
const localImages = await multibuild.performBuilds(
|
||||
buildTasks,
|
||||
docker,
|
||||
|
@ -1,174 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2017-2020 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Functions to help actions which rely on using docker
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { ExpectedError } from '../errors';
|
||||
|
||||
const generateConnectOpts = async function (opts) {
|
||||
const { promises: fs } = await import('fs');
|
||||
|
||||
const connectOpts = {};
|
||||
|
||||
// Start with docker-modem defaults which take several env vars into account,
|
||||
// including DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH, SSH_AUTH_SOCK
|
||||
// https://github.com/apocas/docker-modem/blob/v2.1.3/lib/modem.js#L15-L65
|
||||
const Modem = await import('docker-modem');
|
||||
const defaultOpts = new Modem();
|
||||
const optsOfInterest = [
|
||||
'ca',
|
||||
'cert',
|
||||
'key',
|
||||
'host',
|
||||
'port',
|
||||
'socketPath',
|
||||
'protocol',
|
||||
'username',
|
||||
'sshAuthAgent',
|
||||
'timeout',
|
||||
];
|
||||
for (const opt of optsOfInterest) {
|
||||
connectOpts[opt] = defaultOpts[opt];
|
||||
}
|
||||
|
||||
// Now override the default options with any explicit command line options
|
||||
if (opts.docker != null && opts.dockerHost == null) {
|
||||
// good, local docker socket
|
||||
connectOpts.socketPath = opts.docker;
|
||||
delete connectOpts.host;
|
||||
delete connectOpts.port;
|
||||
} else if (opts.dockerHost != null && opts.docker == null) {
|
||||
// Good a host is provided, and local socket isn't
|
||||
connectOpts.host = opts.dockerHost;
|
||||
connectOpts.port = opts.dockerPort || 2376;
|
||||
delete connectOpts.socketPath;
|
||||
} else if (opts.docker != null && opts.dockerHost != null) {
|
||||
// Both provided, no obvious way to continue
|
||||
throw new ExpectedError(
|
||||
"Both a local docker socket and docker host have been provided. Don't know how to continue.",
|
||||
);
|
||||
}
|
||||
|
||||
// Now need to check if the user wants to connect over TLS
|
||||
// to the host
|
||||
|
||||
// If any are set...
|
||||
if (opts.ca != null || opts.cert != null || opts.key != null) {
|
||||
// but not all
|
||||
if (!(opts.ca != null && opts.cert != null && opts.key != null)) {
|
||||
throw new ExpectedError(
|
||||
'You must provide a CA, certificate and key in order to use TLS',
|
||||
);
|
||||
}
|
||||
|
||||
const [ca, cert, key] = await Promise.all([
|
||||
fs.readFile(opts.ca, 'utf-8'),
|
||||
fs.readFile(opts.cert, 'utf-8'),
|
||||
fs.readFile(opts.key, 'utf-8'),
|
||||
]);
|
||||
return _.merge(connectOpts, {
|
||||
ca,
|
||||
cert,
|
||||
key,
|
||||
});
|
||||
}
|
||||
|
||||
return connectOpts;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* ca?: string; // path to ca (Certificate Authority) file (TLS)
|
||||
* cert?: string; // path to cert (Certificate) file (TLS)
|
||||
* key?: string; // path to key file (TLS)
|
||||
* docker?: string; // dockerode DockerOptions.socketPath
|
||||
* dockerHost?: string; // dockerode DockerOptions.host
|
||||
* dockerPort?: number; // dockerode DockerOptions.port
|
||||
* host?: string;
|
||||
* port?: number;
|
||||
* timeout?: number;
|
||||
* }} options
|
||||
* @returns {Promise<import('docker-toolbelt')>}
|
||||
*/
|
||||
export async function getDocker(options) {
|
||||
const connectOpts = await generateConnectOpts(options);
|
||||
const client = createClient(connectOpts);
|
||||
await ensureDockerSeemsAccessible(client);
|
||||
return client;
|
||||
}
|
||||
|
||||
const getDockerToolbelt = _.once(function () {
|
||||
const Docker = require('docker-toolbelt');
|
||||
const Bluebird = require('bluebird');
|
||||
Bluebird.promisifyAll(Docker.prototype, {
|
||||
filter(name) {
|
||||
return name === 'run';
|
||||
},
|
||||
multiArgs: true,
|
||||
});
|
||||
Bluebird.promisifyAll(Docker.prototype);
|
||||
// @ts-ignore `getImage()` should have a param but this whole thing is a hack that should be removed
|
||||
Bluebird.promisifyAll(new Docker({}).getImage().constructor.prototype);
|
||||
// @ts-ignore `getContainer()` should have a param but this whole thing is a hack that should be removed
|
||||
Bluebird.promisifyAll(new Docker({}).getContainer().constructor.prototype);
|
||||
return Docker;
|
||||
});
|
||||
|
||||
// docker-toolbelt v3 is not backwards compatible as it removes all *Async
|
||||
// methods that are in wide use in the CLI. The workaround for now is to
|
||||
// manually promisify the client and replace all `new Docker()` calls with
|
||||
// this shared function that returns a promisified client.
|
||||
//
|
||||
// **New code must not use the *Async methods.**
|
||||
//
|
||||
/**
|
||||
* @param {{
|
||||
* host: string;
|
||||
* port: number;
|
||||
* timeout?: number;
|
||||
* socketPath?: string
|
||||
* }} opts
|
||||
* @returns {import('docker-toolbelt')}
|
||||
*/
|
||||
export const createClient = function (opts) {
|
||||
const Docker = getDockerToolbelt();
|
||||
const docker = new Docker(opts);
|
||||
const { modem } = docker;
|
||||
// Workaround for a docker-modem 2.0.x bug where it sets a default
|
||||
// socketPath on Windows even if the input options specify a host/port.
|
||||
if (modem.socketPath && modem.host) {
|
||||
if (opts.socketPath) {
|
||||
modem.host = undefined;
|
||||
modem.port = undefined;
|
||||
} else if (opts.host) {
|
||||
modem.socketPath = undefined;
|
||||
}
|
||||
}
|
||||
return docker;
|
||||
};
|
||||
|
||||
var ensureDockerSeemsAccessible = function (docker) {
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
return docker
|
||||
.ping()
|
||||
.catch((e) =>
|
||||
exitWithExpectedError(
|
||||
`Docker seems to be unavailable. Is it installed and running?\n${e}`,
|
||||
),
|
||||
);
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2018-2019 Balena Ltd.
|
||||
* Copyright 2018-2021 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,8 +21,6 @@ import { flags } from '@oclif/command';
|
||||
import { ExpectedError } from '../errors';
|
||||
import { parseAsInteger } from './validation';
|
||||
|
||||
export * from './docker-js';
|
||||
|
||||
interface BalenaEngineVersion extends dockerode.DockerVersion {
|
||||
Engine?: string;
|
||||
}
|
||||
@ -173,3 +171,120 @@ export async function isBalenaEngine(docker: dockerode): Promise<boolean> {
|
||||
dockerVersion.Engine && dockerVersion.Engine.match(/balena|balaena/)
|
||||
);
|
||||
}
|
||||
|
||||
export interface ExtendedDockerOptions extends dockerode.DockerOptions {
|
||||
docker?: string; // socket path, e.g. /var/run/docker.sock
|
||||
dockerHost?: string; // host name or IP address
|
||||
dockerPort?: number; // TCP port number, e.g. 2375
|
||||
}
|
||||
|
||||
export async function getDocker(
|
||||
options: ExtendedDockerOptions,
|
||||
): Promise<dockerode> {
|
||||
const connectOpts = await generateConnectOpts(options);
|
||||
const client = await createClient(connectOpts);
|
||||
await checkThatDockerIsReachable(client);
|
||||
return client;
|
||||
}
|
||||
|
||||
export async function createClient(
|
||||
opts: dockerode.DockerOptions,
|
||||
): Promise<dockerode> {
|
||||
const Docker = await import('dockerode');
|
||||
const docker = new Docker(opts);
|
||||
const { modem } = docker;
|
||||
// Workaround for a docker-modem 2.0.x bug where it sets a default
|
||||
// socketPath on Windows even if the input options specify a host/port.
|
||||
if (modem.socketPath && modem.host) {
|
||||
if (opts.socketPath) {
|
||||
modem.host = undefined;
|
||||
modem.port = undefined;
|
||||
} else if (opts.host) {
|
||||
modem.socketPath = undefined;
|
||||
}
|
||||
}
|
||||
return docker;
|
||||
}
|
||||
|
||||
async function generateConnectOpts(opts: ExtendedDockerOptions) {
|
||||
let connectOpts: dockerode.DockerOptions = {};
|
||||
|
||||
// Start with docker-modem defaults which take several env vars into account,
|
||||
// including DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH, SSH_AUTH_SOCK
|
||||
// https://github.com/apocas/docker-modem/blob/v3.0.0/lib/modem.js#L15-L70
|
||||
const Modem = require('docker-modem');
|
||||
const defaultOpts = new Modem();
|
||||
const optsOfInterest: Array<keyof dockerode.DockerOptions> = [
|
||||
'ca',
|
||||
'cert',
|
||||
'key',
|
||||
'host',
|
||||
'port',
|
||||
'socketPath',
|
||||
'protocol',
|
||||
'username',
|
||||
'timeout',
|
||||
];
|
||||
for (const opt of optsOfInterest) {
|
||||
connectOpts[opt] = defaultOpts[opt];
|
||||
}
|
||||
|
||||
// Now override the default options with any explicit command line options
|
||||
if (opts.docker != null && opts.dockerHost == null) {
|
||||
// good, local docker socket
|
||||
connectOpts.socketPath = opts.docker;
|
||||
delete connectOpts.host;
|
||||
delete connectOpts.port;
|
||||
} else if (opts.dockerHost != null && opts.docker == null) {
|
||||
// Good a host is provided, and local socket isn't
|
||||
connectOpts.host = opts.dockerHost;
|
||||
connectOpts.port = opts.dockerPort || 2376;
|
||||
delete connectOpts.socketPath;
|
||||
} else if (opts.docker != null && opts.dockerHost != null) {
|
||||
// Both provided, no obvious way to continue
|
||||
throw new ExpectedError(
|
||||
"Both a local docker socket and docker host have been provided. Don't know how to continue.",
|
||||
);
|
||||
}
|
||||
|
||||
// Process TLS options
|
||||
// These should be file paths (strings)
|
||||
const tlsOpts = [opts.ca, opts.cert, opts.key];
|
||||
|
||||
// If any are set...
|
||||
if (tlsOpts.some((opt) => opt)) {
|
||||
// but not all ()
|
||||
if (!tlsOpts.every((opt) => opt)) {
|
||||
throw new ExpectedError(
|
||||
'You must provide a CA, certificate and key in order to use TLS',
|
||||
);
|
||||
}
|
||||
if (!isStringArray(tlsOpts)) {
|
||||
throw new ExpectedError(
|
||||
'TLS options (CA, certificate and key) must be file paths (strings)',
|
||||
);
|
||||
}
|
||||
const { promises: fs } = await import('fs');
|
||||
const [ca, cert, key] = await Promise.all(
|
||||
tlsOpts.map((opt: string) => fs.readFile(opt, 'utf8')),
|
||||
);
|
||||
connectOpts = { ...connectOpts, ca, cert, key };
|
||||
}
|
||||
|
||||
return connectOpts;
|
||||
}
|
||||
|
||||
// TypeScript "type guard" with "type predicate"
|
||||
function isStringArray(array: any[]): array is string[] {
|
||||
return array.every((opt) => typeof opt === 'string');
|
||||
}
|
||||
|
||||
async function checkThatDockerIsReachable(docker: dockerode) {
|
||||
try {
|
||||
await docker.ping();
|
||||
} catch (e) {
|
||||
throw new ExpectedError(
|
||||
`Docker seems to be unavailable. Is it installed and running?\n${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
996
npm-shrinkwrap.json
generated
996
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -122,7 +122,7 @@
|
||||
"@types/chai-as-promised": "^7.1.3",
|
||||
"@types/cli-truncate": "^1.1.0",
|
||||
"@types/common-tags": "^1.8.0",
|
||||
"@types/dockerode": "^2.5.34",
|
||||
"@types/dockerode": "^3.2.3",
|
||||
"@types/ejs": "^3.0.4",
|
||||
"@types/express": "^4.17.7",
|
||||
"@types/fs-extra": "^8.1.1",
|
||||
@ -159,7 +159,7 @@
|
||||
"@types/tmp": "^0.2.0",
|
||||
"@types/which": "^1.3.2",
|
||||
"archiver": "^3.1.1",
|
||||
"catch-uncommitted": "^1.6.2",
|
||||
"catch-uncommitted": "^2.0.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"cross-env": "^7.0.2",
|
||||
@ -219,11 +219,10 @@
|
||||
"columnify": "^1.5.2",
|
||||
"common-tags": "^1.7.2",
|
||||
"denymount": "^2.3.0",
|
||||
"docker-modem": "^2.1.4",
|
||||
"docker-progress": "^4.0.1",
|
||||
"docker-modem": "^3.0.0",
|
||||
"docker-progress": "^5.0.0",
|
||||
"docker-qemu-transpose": "^1.1.1",
|
||||
"docker-toolbelt": "^3.3.8",
|
||||
"dockerode": "^2.5.8",
|
||||
"dockerode": "^3.3.0",
|
||||
"ejs": "^3.1.3",
|
||||
"etcher-sdk": "^6.2.1",
|
||||
"event-stream": "3.3.4",
|
||||
@ -260,7 +259,7 @@
|
||||
"resin-cli-visuals": "^1.8.0",
|
||||
"resin-compose-parse": "^2.1.3",
|
||||
"resin-doodles": "^0.1.1",
|
||||
"resin-multibuild": "^4.7.2",
|
||||
"resin-multibuild": "^4.11.0",
|
||||
"resin-stream-logger": "^0.1.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"semver": "^7.3.2",
|
||||
|
Loading…
Reference in New Issue
Block a user