Update resin-preload to 4.0.2 to support preloading Edison images

Change-Type: patch
This commit is contained in:
Alexis Svinartchouk 2017-10-06 11:05:24 +02:00
parent dad655c9ec
commit 119fa78927
3 changed files with 203 additions and 138 deletions

View File

@ -127,8 +127,8 @@ offerToDisableAutomaticUpdates = function(application, commit) {
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',
description: '(beta) preload an app on a disk image (or Edison zip archive)',
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 (or\nEdison zip archive) with a built 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([
@ -158,7 +158,7 @@ module.exports = {
}
]),
action: function(params, options, done) {
var Promise, _, errors, expectedError, form, imageInfoSpinner, preload, resin, streamToPromise, visuals;
var Promise, _, errors, expectedError, form, nodeCleanup, preload, progressBars, progressHandler, resin, spinnerHandler, spinners, streamToPromise, visuals;
_ = require('lodash');
Promise = require('bluebird');
resin = require('resin-sdk-preconfigured');
@ -167,8 +167,33 @@ module.exports = {
preload = require('resin-preload');
errors = require('resin-errors');
visuals = require('resin-cli-visuals');
nodeCleanup = require('node-cleanup');
expectedError = require('../utils/patterns').expectedError;
imageInfoSpinner = new visuals.Spinner('Reading image device type and preloaded builds.');
progressBars = {};
progressHandler = function(event) {
var progressBar;
progressBar = progressBars[event.name];
if (!progressBar) {
progressBar = progressBars[event.name] = new visuals.Progress(event.name);
}
return progressBar.update({
percentage: event.percentage
});
};
spinners = {};
spinnerHandler = function(event) {
var spinner;
spinner = spinners[event.name];
if (!spinner) {
spinner = spinners[event.name] = new visuals.Spinner(event.name);
}
if (event.action === 'start') {
return spinner.start();
} else {
console.log();
return spinner.stop();
}
};
options.image = params.image;
options.appId = options.app;
delete options.app;
@ -176,72 +201,79 @@ module.exports = {
delete options['dont-detect-flasher-type-images'];
options.splashImage = options['splash-image'];
delete options['splash-image'];
if (options['dont-check-device-type'] && !options.appId) {
expectedError('You need to specify an app id if you disable the device type check.');
}
return dockerUtils.getDocker(options).then(function(docker) {
var buildOutputStream;
buildOutputStream = preload.build(docker);
if (process.env.DEBUG) {
buildOutputStream.pipe(process.stdout);
}
return streamToPromise(buildOutputStream).then(resin.settings.getAll).then(function(settings) {
options.proxy = settings.proxy;
options.apiHost = settings.apiUrl;
imageInfoSpinner.start();
return preload.getDeviceTypeSlugAndPreloadedBuilds(docker, options)["catch"](preload.errors.ResinError, expectedError);
}).then(function(arg) {
var builds, slug;
slug = arg.slug, builds = arg.builds;
imageInfoSpinner.stop();
return Promise["try"](function() {
if (options['dont-check-device-type'] && !options.appId) {
expectedError('You need to specify an app id if you disable the device type check.');
}
if (options.appId) {
return preload.getApplication(resin, options.appId)["catch"](errors.ResinApplicationNotFound, expectedError);
}
return selectApplication(slug);
}).then(function(application) {
options.application = application;
if (slug !== application.device_type) {
expectedError("Image device type (" + application.device_type + ") and application device type (" + slug + ") do not match");
}
return Promise["try"](function() {
if (options.commit) {
if (!_.find(application.build, {
commit_hash: options.commit
})) {
expectedError('There is no build matching this commit');
}
return options.commit;
}
return selectApplicationCommit(application.build);
}).then(function(commit) {
if (commit === LATEST) {
options.commit = application.commit;
} else {
options.commit = commit;
}
return offerToDisableAutomaticUpdates(application, commit);
var gotSignal, preloader;
preloader = new preload.Preloader(resin, docker, options.appId, options.commit, options.image, options.splashImage, options.proxy, options.dontDetectFlasherTypeImages);
gotSignal = false;
nodeCleanup(function(exitCode, signal) {
if (signal) {
gotSignal = true;
nodeCleanup.uninstall();
preloader.cleanup().then(function() {
return process.kill(process.pid, signal);
});
}).then(function() {
var ref;
builds = builds.map(function(build) {
return build.slice(-preload.BUILD_HASH_LENGTH);
});
if (ref = options.commit, indexOf.call(builds, ref) >= 0) {
console.log('This build is already preloaded in this image.');
process.exit(0);
}
return preload.run(resin, docker, options)["catch"](preload.errors.ResinError, expectedError);
});
return false;
}
});
}).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);
if (process.env.DEBUG) {
preloader.stderr.pipe(process.stderr);
}
}).then(done);
preloader.on('progress', progressHandler);
preloader.on('spinner', spinnerHandler);
return new Promise(function(resolve, reject) {
preloader.on('error', reject);
return preloader.build().then(function() {
return preloader.prepare();
}).then(function() {
return preloader.getDeviceTypeAndPreloadedBuilds();
}).then(function(info) {
return Promise["try"](function() {
if (options.appId) {
return preloader.fetchApplication()["catch"](errors.ResinApplicationNotFound, expectedError);
}
return selectApplication(info.device_type);
}).then(function(application) {
preloader.setApplication(application);
if (info.device_type !== application.device_type) {
expectedError("Image device type (" + application.device_type + ") and application device type (" + slug + ") do not match");
}
return Promise["try"](function() {
if (options.commit) {
if (!_.find(application.build, {
commit_hash: options.commit
})) {
expectedError('There is no build matching this commit');
}
return options.commit;
}
return selectApplicationCommit(application.build);
}).then(function(commit) {
if (commit === LATEST) {
preloader.commit = application.commit;
} else {
preloader.commit = commit;
}
return offerToDisableAutomaticUpdates(application, commit);
});
}).then(function() {
var builds, ref;
builds = info.preloaded_builds.map(function(build) {
return build.slice(-preload.BUILD_HASH_LENGTH);
});
if (ref = preloader.commit, indexOf.call(builds, ref) >= 0) {
throw new preload.errors.ResinError('This build is already preloaded in this image.');
}
return preloader.preload()["catch"](preload.errors.ResinError, expectedError);
});
}).then(resolve)["catch"](reject);
}).then(done)["finally"](function() {
if (!gotSignal) {
return preloader.cleanup();
}
});
});
}
};

View File

@ -102,14 +102,14 @@ offerToDisableAutomaticUpdates = (application, commit) ->
module.exports =
signature: 'preload <image>'
description: '(beta) preload an app on a disk image'
description: '(beta) preload an app on a disk image (or Edison zip archive)'
help: '''
Warning: "resin preload" requires Docker to be correctly installed in
your shell environment. For more information (including Windows support)
please check the README here: https://github.com/resin-io/resin-cli .
Use this command to preload an application to a local disk image with a
built commit from Resin.io.
Use this command to preload an application to a local disk image (or
Edison zip archive) with a built commit from Resin.io.
This can be used with cloud builds, or images deployed with resin deploy.
Examples:
@ -157,9 +157,28 @@ module.exports =
preload = require('resin-preload')
errors = require('resin-errors')
visuals = require('resin-cli-visuals')
nodeCleanup = require('node-cleanup')
{ expectedError } = require('../utils/patterns')
imageInfoSpinner = new visuals.Spinner('Reading image device type and preloaded builds.')
progressBars = {}
progressHandler = (event) ->
progressBar = progressBars[event.name]
if not progressBar
progressBar = progressBars[event.name] = new visuals.Progress(event.name)
progressBar.update(percentage: event.percentage)
spinners = {}
spinnerHandler = (event) ->
spinner = spinners[event.name]
if not spinner
spinner = spinners[event.name] = new visuals.Spinner(event.name)
if event.action == 'start'
spinner.start()
else
console.log()
spinner.stop()
options.image = params.image
options.appId = options.app
@ -171,79 +190,92 @@ module.exports =
options.splashImage = options['splash-image']
delete options['splash-image']
if options['dont-check-device-type'] and not options.appId
expectedError('You need to specify an app id if you disable the device type check.')
# Get a configured dockerode instance
dockerUtils.getDocker(options)
.then (docker) ->
# Build the preloader image
buildOutputStream = preload.build(docker)
preloader = new preload.Preloader(
resin,
docker,
options.appId,
options.commit,
options.image,
options.splashImage,
options.proxy,
options.dontDetectFlasherTypeImages
)
gotSignal = false
nodeCleanup (exitCode, signal) ->
if signal
gotSignal = true
nodeCleanup.uninstall() # don't call cleanup handler again
preloader.cleanup()
.then ->
# calling process.exit() won't inform parent process of signal
process.kill(process.pid, signal)
return false
if process.env.DEBUG
buildOutputStream.pipe(process.stdout)
preloader.stderr.pipe(process.stderr)
streamToPromise(buildOutputStream)
preloader.on('progress', progressHandler)
preloader.on('spinner', spinnerHandler)
# Get resin sdk settings so we can pass them to the preloader
.then(resin.settings.getAll)
.then (settings) ->
options.proxy = settings.proxy
options.apiHost = settings.apiUrl
return new Promise (resolve, reject) ->
preloader.on('error', reject)
# Use the preloader docker image to extract the deviceType of the image
imageInfoSpinner.start()
preload.getDeviceTypeSlugAndPreloadedBuilds(docker, options)
.catch(preload.errors.ResinError, expectedError)
.then ({ slug, builds }) ->
imageInfoSpinner.stop()
# Use the appId given as --app or show an interactive app selection menu
Promise.try ->
if options['dont-check-device-type'] and not options.appId
expectedError('You need to specify an app id if you disable the device type check.')
if options.appId
return preload.getApplication(resin, options.appId)
.catch(errors.ResinApplicationNotFound, expectedError)
selectApplication(slug)
.then (application) ->
options.application = application
# Check that the app device type and the image device type match
if slug != application.device_type
expectedError(
"Image device type (#{application.device_type}) and application device type (#{slug}) do not match"
)
# Use the commit given as --commit or show an interactive commit selection menu
Promise.try ->
if options.commit
if not _.find(application.build, commit_hash: options.commit)
expectedError('There is no build matching this commit')
return options.commit
selectApplicationCommit(application.build)
.then (commit) ->
# No commit specified => use the latest commit
if commit == LATEST
options.commit = application.commit
else
options.commit = commit
# Propose to disable automatic app updates if the commit is not the latest
offerToDisableAutomaticUpdates(application, commit)
preloader.build()
.then ->
preloader.prepare()
.then ->
preloader.getDeviceTypeAndPreloadedBuilds()
.then (info) ->
Promise.try ->
if options.appId
return preloader.fetchApplication()
.catch(errors.ResinApplicationNotFound, expectedError)
selectApplication(info.device_type)
.then (application) ->
preloader.setApplication(application)
# Check that the app device type and the image device type match
if info.device_type != application.device_type
expectedError(
"Image device type (#{application.device_type}) and application device type (#{slug}) do not match"
)
builds = builds.map (build) ->
build.slice(-preload.BUILD_HASH_LENGTH)
if options.commit in builds
console.log('This build is already preloaded in this image.')
process.exit(0)
# All options are ready: preload the image.
preload.run(resin, docker, options)
.catch(preload.errors.ResinError, expectedError)
.then (info) ->
info.stdout.pipe(process.stdout)
info.stderr.pipe(process.stderr)
info.statusCodePromise
.then (statusCode) ->
if statusCode != 0
process.exit(statusCode)
.then(done)
# Use the commit given as --commit or show an interactive commit selection menu
Promise.try ->
if options.commit
if not _.find(application.build, commit_hash: options.commit)
expectedError('There is no build matching this commit')
return options.commit
selectApplicationCommit(application.build)
.then (commit) ->
# No commit specified => use the latest commit
if commit == LATEST
preloader.commit = application.commit
else
preloader.commit = commit
# Propose to disable automatic app updates if the commit is not the latest
offerToDisableAutomaticUpdates(application, commit)
.then ->
builds = info.preloaded_builds.map (build) ->
build.slice(-preload.BUILD_HASH_LENGTH)
if preloader.commit in builds
throw new preload.errors.ResinError('This build is already preloaded in this image.')
# All options are ready: preload the image.
preloader.preload()
.catch(preload.errors.ResinError, expectedError)
.then(resolve)
.catch(reject)
.then(done)
.finally ->
if not gotSignal
preloader.cleanup()

View File

@ -66,6 +66,7 @@
"mixpanel": "^0.4.0",
"moment": "^2.12.0",
"mz": "^2.6.0",
"node-cleanup": "^2.1.2",
"nplugm": "^3.0.0",
"president": "^2.0.1",
"prettyjson": "^1.1.3",
@ -85,7 +86,7 @@
"resin-doodles": "0.0.1",
"resin-image-fs": "^2.3.0",
"resin-image-manager": "^4.1.1",
"resin-preload": "^3.1.4",
"resin-preload": "^4.0.2",
"resin-sdk-preconfigured": "^6.9.0",
"resin-settings-client": "^3.6.1",
"resin-stream-logger": "^0.0.4",
@ -103,4 +104,4 @@
"optionalDependencies": {
"removedrive": "^1.0.0"
}
}
}