mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-28 09:38:51 +00:00
22b3c39b2b
* split docker connection options from lib.utils.docker.appendOptions Connects to #609 Connects to https://github.com/resin-io/resin-preload/pull/81 Change-Type: minor
218 lines
7.8 KiB
JavaScript
218 lines
7.8 KiB
JavaScript
// Generated by CoffeeScript 1.12.7
|
|
|
|
/*
|
|
Copyright 2016-2017 Resin.io
|
|
|
|
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.
|
|
*/
|
|
var LATEST, dockerUtils, getApplicationsWithSuccessfulBuilds, offerToDisableAutomaticUpdates, selectApplication, selectApplicationCommit;
|
|
|
|
dockerUtils = require('../utils/docker');
|
|
|
|
LATEST = 'latest';
|
|
|
|
getApplicationsWithSuccessfulBuilds = function(resin, deviceType) {
|
|
return resin.pine.get({
|
|
resource: 'my_application',
|
|
options: {
|
|
filter: {
|
|
device_type: deviceType,
|
|
build: {
|
|
$any: {
|
|
$alias: 'b',
|
|
$expr: {
|
|
b: {
|
|
status: 'success'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
expand: {
|
|
environment_variable: {
|
|
$select: ['name', 'value']
|
|
},
|
|
build: {
|
|
$select: ['id', 'commit_hash', 'push_timestamp', 'status'],
|
|
$orderby: 'push_timestamp desc'
|
|
}
|
|
},
|
|
select: ['id', 'app_name', 'device_type', 'commit'],
|
|
orderby: 'app_name asc'
|
|
}
|
|
}).then(function(applications) {
|
|
applications.forEach(function(application) {
|
|
return application.build = application.build.filter(function(build) {
|
|
return build.status === 'success';
|
|
});
|
|
});
|
|
return applications;
|
|
});
|
|
};
|
|
|
|
selectApplication = function(expectedError, resin, form, deviceType) {
|
|
return getApplicationsWithSuccessfulBuilds(resin, deviceType).then(function(applications) {
|
|
if (applications.length === 0) {
|
|
expectedError("You have no apps with successful builds for a '" + deviceType + "' device type.");
|
|
}
|
|
return form.ask({
|
|
message: 'Select an application',
|
|
type: 'list',
|
|
choices: applications.map(function(app) {
|
|
return {
|
|
name: app.app_name,
|
|
value: app
|
|
};
|
|
})
|
|
});
|
|
});
|
|
};
|
|
|
|
selectApplicationCommit = function(expectedError, resin, form, builds) {
|
|
var DEFAULT_CHOICE, choices;
|
|
if (builds.length === 0) {
|
|
expectedError('This application has no successful builds.');
|
|
}
|
|
DEFAULT_CHOICE = {
|
|
'name': LATEST,
|
|
'value': LATEST
|
|
};
|
|
choices = [DEFAULT_CHOICE].concat(builds.map(function(build) {
|
|
return {
|
|
name: build.push_timestamp + " - " + build.commit_hash,
|
|
value: build.commit_hash
|
|
};
|
|
}));
|
|
return form.ask({
|
|
message: 'Select a build',
|
|
type: 'list',
|
|
"default": LATEST,
|
|
choices: choices
|
|
});
|
|
};
|
|
|
|
offerToDisableAutomaticUpdates = function(Promise, form, resin, application, commit) {
|
|
var message;
|
|
if (commit === LATEST || !application.should_track_latest_release) {
|
|
return Promise.resolve();
|
|
}
|
|
message = '\nThis application is set to automatically update all devices to the latest available version.\nThis might be unexpected behaviour: with this enabled, the preloaded device will still\ndownload and install the latest build once it is online.\n\nDo you want to disable automatic updates for this application?';
|
|
return form.ask({
|
|
message: message,
|
|
type: 'confirm'
|
|
}).then(function(update) {
|
|
if (!update) {
|
|
return;
|
|
}
|
|
return resin.pine.patch({
|
|
resource: 'application',
|
|
id: application.id,
|
|
body: {
|
|
should_track_latest_release: false
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
module.exports = {
|
|
signature: 'preload <image>',
|
|
description: '(beta) preload an app on a disk image',
|
|
help: 'Warning: "resin preload" requires Docker to be correctly installed in\nyour shell environment. For more information (including Windows support)\nplease check the README here: https://github.com/resin-io/resin-cli .\n\nUse this command to preload an application to a local disk image with a\nbuilt commit from Resin.io.\nThis can be used with cloud builds, or images deployed with resin deploy.\n\nExamples:\n $ resin preload resin.img --app 1234 --commit e1f2592fc6ee949e68756d4f4a48e49bff8d72a0 --splash-image some-image.png\n $ resin preload resin.img',
|
|
permission: 'user',
|
|
primary: true,
|
|
options: dockerUtils.appendConnectionOptions([
|
|
{
|
|
signature: 'app',
|
|
parameter: 'appId',
|
|
description: 'id of the application to preload',
|
|
alias: 'a'
|
|
}, {
|
|
signature: 'commit',
|
|
parameter: 'hash',
|
|
description: 'a specific application commit to preload (ignored if no appId is given)',
|
|
alias: 'c'
|
|
}, {
|
|
signature: 'splash-image',
|
|
parameter: 'splashImage.png',
|
|
description: 'path to a png image to replace the splash screen',
|
|
alias: 's'
|
|
}, {
|
|
signature: 'dont-detect-flasher-type-images',
|
|
boolean: true,
|
|
description: 'Disables the flasher type images detection: treats all images as non flasher types'
|
|
}
|
|
]),
|
|
action: function(params, options, done) {
|
|
var Promise, _, errors, expectedError, form, preload, resin, streamToPromise;
|
|
_ = require('lodash');
|
|
Promise = require('bluebird');
|
|
resin = require('resin-sdk-preconfigured');
|
|
streamToPromise = require('stream-to-promise');
|
|
form = require('resin-cli-form');
|
|
preload = require('resin-preload');
|
|
errors = require('resin-errors');
|
|
expectedError = require('../utils/patterns').expectedError;
|
|
options.image = params.image;
|
|
options.appId = options.app;
|
|
delete options.app;
|
|
options.dontDetectFlasherTypeImages = options['dont-detect-flasher-type-images'];
|
|
delete options['dont-detect-flasher-type-images'];
|
|
return dockerUtils.getDocker(options).then(function(docker) {
|
|
var buildOutputStream;
|
|
buildOutputStream = preload.build(docker);
|
|
buildOutputStream.pipe(process.stdout);
|
|
return streamToPromise(buildOutputStream).then(resin.settings.getAll).then(function(settings) {
|
|
options.proxy = settings.proxy;
|
|
options.apiHost = settings.apiUrl;
|
|
return preload.getDeviceTypeSlug(docker, options)["catch"](preload.errors.ResinError, expectedError);
|
|
}).then(function(deviceType) {
|
|
return Promise["try"](function() {
|
|
if (options.appId) {
|
|
return preload.getApplication(resin, options.appId)["catch"](errors.ResinApplicationNotFound, expectedError);
|
|
}
|
|
return selectApplication(expectedError, resin, form, deviceType);
|
|
}).then(function(application) {
|
|
options.application = application;
|
|
if (deviceType !== application.device_type) {
|
|
expectedError("Image device type (" + application.device_type + ") and application device type (" + deviceType + ") do not match");
|
|
}
|
|
return Promise["try"](function() {
|
|
if (options.commit) {
|
|
if (_.map(builds, 'commit_hash').indexOf(options.commit) === -1) {
|
|
expectedError('There is no build matching this commit');
|
|
}
|
|
return options.commit;
|
|
}
|
|
return selectApplicationCommit(expectedError, resin, form, application.build);
|
|
}).then(function(commit) {
|
|
if (commit !== LATEST) {
|
|
options.commit = commit;
|
|
}
|
|
return offerToDisableAutomaticUpdates(Promise, form, resin, application, commit);
|
|
});
|
|
});
|
|
}).then(function() {
|
|
return preload.run(resin, docker, options)["catch"](preload.errors.ResinError, expectedError);
|
|
});
|
|
}).then(function(info) {
|
|
info.stdout.pipe(process.stdout);
|
|
info.stderr.pipe(process.stderr);
|
|
return info.statusCodePromise;
|
|
}).then(function(statusCode) {
|
|
if (statusCode !== 0) {
|
|
return process.exit(statusCode);
|
|
}
|
|
}).then(done);
|
|
}
|
|
};
|