Merge pull request #201 from resin-io/jviotti/feature/os-configure

Implement os configure
This commit is contained in:
Juan Cruz Viotti 2015-09-29 14:26:03 -04:00
commit 61474fba5c
11 changed files with 161 additions and 82 deletions

View File

@ -152,26 +152,28 @@
}
return vcs.getApplicationName(process.cwd());
}).then(resin.models.application.get).then(function(application) {
console.info('Getting configuration options');
return patterns.askDeviceOptions(application.device_type).tap(function(answers) {
var message;
if (answers.drive != null) {
message = "This will erase " + answers.drive + ". Are you sure?";
return patterns.confirm(options.yes, message)["return"](answers.drive).then(umount.umountAsync);
}
}).then(function(answers) {
return tmp.tmpNameAsync().then(function(temporalPath) {
return capitano.runAsync("os download --output " + temporalPath);
}).then(function(temporalPath) {
var uuid;
uuid = resin.models.device.generateUUID();
console.log("Registering to " + application.app_name + ": " + uuid);
return resin.models.device.register(application.app_name, uuid).tap(function(device) {
console.log('Configuring operating system');
return init.configure(temporalPath, device.uuid, answers).then(stepHandler).then(function() {
console.log('Initializing device');
return init.initialize(temporalPath, device.uuid, answers).then(stepHandler);
}).tap(function() {
return tmp.tmpNameAsync().then(function(temporalPath) {
return capitano.runAsync("os download --output " + temporalPath);
}).then(function(temporalPath) {
var uuid;
uuid = resin.models.device.generateUUID();
console.log("Registering to " + application.app_name + ": " + uuid);
return resin.models.device.register(application.app_name, uuid).tap(function(device) {
console.log('Configuring operating system');
return capitano.runAsync("os configure " + temporalPath + " " + uuid).then(function() {
console.log('Initializing device');
return resin.models.device.getManifestBySlug(application.device_type).then(function(manifest) {
var ref;
return form.run((ref = manifest.initialization) != null ? ref.options : void 0);
}).tap(function(answers) {
var message;
if (answers.drive != null) {
message = "This will erase " + answers.drive + ". Are you sure?";
return patterns.confirm(options.yes, message)["return"](answers.drive).then(umount.umountAsync);
}
}).then(function(answers) {
return init.initialize(temporalPath, device.uuid, answers).then(stepHandler)["return"](answers);
}).tap(function(answers) {
if (answers.drive == null) {
return;
}
@ -179,21 +181,21 @@
return console.log("You can safely remove " + answers.drive + " now");
});
});
}).then(function(device) {
console.log('Done');
return device.uuid;
})["finally"](function() {
return fs.statAsync(temporalPath).then(function(stat) {
if (stat.isDirectory()) {
return rimraf(temporalPath);
}
return fs.unlinkAsync(temporalPath);
})["catch"](function(error) {
if (error.code === 'ENOENT') {
return;
}
throw error;
});
});
}).then(function(device) {
console.log('Done');
return device.uuid;
})["finally"](function() {
return fs.statAsync(temporalPath).then(function(stat) {
if (stat.isDirectory()) {
return rimraf(temporalPath);
}
return fs.unlinkAsync(temporalPath);
})["catch"](function(error) {
if (error.code === 'ENOENT') {
return;
}
throw error;
});
});
});

View File

@ -1,12 +1,20 @@
(function() {
var fs, helpers, manager, visuals;
var _, form, fs, helpers, init, manager, resin, stepHandler, visuals;
fs = require('fs');
_ = require('lodash');
resin = require('resin-sdk');
manager = require('resin-image-manager');
visuals = require('resin-cli-visuals');
form = require('resin-cli-form');
init = require('resin-device-init');
helpers = require('../utils/helpers');
exports.download = {
@ -47,4 +55,32 @@
}
};
stepHandler = function(step) {
var bar;
step.on('stdout', _.bind(process.stdout.write, process.stdout));
step.on('stderr', _.bind(process.stderr.write, process.stderr));
step.on('state', function(state) {
if (state.operation.command === 'burn') {
return;
}
return console.log(helpers.stateToString(state));
});
bar = new visuals.Progress('Writing Device OS');
step.on('burn', _.bind(bar.update, bar));
return helpers.waitStream(step);
};
exports.configure = {
signature: 'os configure <image> <uuid>',
description: 'configure an os image',
help: 'Use this command to configure a previously download operating system image with a device.\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9',
permission: 'user',
action: function(params, options, done) {
console.info('Configuring operating system image');
return resin.models.device.get(params.uuid).get('device_type').then(resin.models.device.getManifestBySlug).get('options').then(form.run).then(function(answers) {
return init.configure(params.image, params.uuid, answers).then(stepHandler);
}).nodeify(done);
}
};
}).call(this);

View File

@ -92,6 +92,8 @@
capitano.command(actions.os.download);
capitano.command(actions.os.configure);
capitano.command(actions.logs);
update.notify();

View File

@ -39,6 +39,7 @@
exports.waitStream = function(stream) {
return new Promise(function(resolve, reject) {
stream.on('close', resolve);
stream.on('end', resolve);
return stream.on('error', reject);
});
};

View File

@ -98,13 +98,4 @@
});
};
exports.askDeviceOptions = function(deviceType) {
return resin.models.config.getDeviceOptions(deviceType).then(form.run).then(function(answers) {
if (answers.os == null) {
answers.os = helpers.getOperatingSystem();
}
return answers;
});
};
}).call(this);

View File

@ -72,6 +72,7 @@ Now you have access to all the commands referenced below.
- OS
- [os download &#60;type&#62;](#os-download-60-type-62-)
- [os configure &#60;image&#62; &#60;uuid&#62;](#os-configure-60-image-62-60-uuid-62-)
- Wizard
@ -560,6 +561,14 @@ Examples:
output path
## os configure &#60;image&#62; &#60;uuid&#62;
Use this command to configure a previously download operating system image with a device.
Examples:
$ resin os configure ../path/rpi.img 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9
# Wizard
## quickstart [name]

View File

@ -198,42 +198,44 @@ exports.init =
return vcs.getApplicationName(process.cwd())
.then(resin.models.application.get)
.then (application) ->
console.info('Getting configuration options')
patterns.askDeviceOptions(application.device_type).tap (answers) ->
if answers.drive?
message = "This will erase #{answers.drive}. Are you sure?"
patterns.confirm(options.yes, message)
.return(answers.drive)
.then(umount.umountAsync)
.then (answers) ->
tmp.tmpNameAsync().then (temporalPath) ->
return capitano.runAsync("os download --output #{temporalPath}")
.then (temporalPath) ->
uuid = resin.models.device.generateUUID()
console.log("Registering to #{application.app_name}: #{uuid}")
resin.models.device.register(application.app_name, uuid).tap (device) ->
console.log('Configuring operating system')
init.configure(temporalPath, device.uuid, answers).then(stepHandler).then ->
console.log('Initializing device')
init.initialize(temporalPath, device.uuid, answers).then(stepHandler)
.tap ->
tmp.tmpNameAsync().then (temporalPath) ->
return capitano.runAsync("os download --output #{temporalPath}")
.then (temporalPath) ->
uuid = resin.models.device.generateUUID()
console.log("Registering to #{application.app_name}: #{uuid}")
resin.models.device.register(application.app_name, uuid).tap (device) ->
console.log('Configuring operating system')
capitano.runAsync("os configure #{temporalPath} #{uuid}").then ->
console.log('Initializing device')
resin.models.device.getManifestBySlug(application.device_type).then (manifest) ->
return form.run(manifest.initialization?.options)
.tap (answers) ->
if answers.drive?
message = "This will erase #{answers.drive}. Are you sure?"
patterns.confirm(options.yes, message)
.return(answers.drive)
.then(umount.umountAsync)
.then (answers) ->
init.initialize(temporalPath, device.uuid, answers)
.then(stepHandler)
.return(answers)
.tap (answers) ->
return if not answers.drive?
umount.umountAsync(answers.drive).tap ->
console.log("You can safely remove #{answers.drive} now")
.then (device) ->
console.log('Done')
return device.uuid
.then (device) ->
console.log('Done')
return device.uuid
.finally ->
fs.statAsync(temporalPath).then (stat) ->
return rimraf(temporalPath) if stat.isDirectory()
return fs.unlinkAsync(temporalPath)
.catch (error) ->
.finally ->
fs.statAsync(temporalPath).then (stat) ->
return rimraf(temporalPath) if stat.isDirectory()
return fs.unlinkAsync(temporalPath)
.catch (error) ->
# Ignore errors if temporary file does not exist
return if error.code is 'ENOENT'
# Ignore errors if temporary file does not exist
return if error.code is 'ENOENT'
throw error
throw error
.nodeify(done)

View File

@ -1,6 +1,10 @@
fs = require('fs')
_ = require('lodash')
resin = require('resin-sdk')
manager = require('resin-image-manager')
visuals = require('resin-cli-visuals')
form = require('resin-cli-form')
init = require('resin-device-init')
helpers = require('../utils/helpers')
exports.download =
@ -43,3 +47,39 @@ exports.download =
.tap (output) ->
console.log("The image was downloaded to #{output}")
.nodeify(done)
stepHandler = (step) ->
step.on('stdout', _.bind(process.stdout.write, process.stdout))
step.on('stderr', _.bind(process.stderr.write, process.stderr))
step.on 'state', (state) ->
return if state.operation.command is 'burn'
console.log(helpers.stateToString(state))
bar = new visuals.Progress('Writing Device OS')
step.on('burn', _.bind(bar.update, bar))
return helpers.waitStream(step)
exports.configure =
signature: 'os configure <image> <uuid>'
description: 'configure an os image'
help: '''
Use this command to configure a previously download operating system image with a device.
Examples:
$ resin os configure ../path/rpi.img 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9
'''
permission: 'user'
action: (params, options, done) ->
console.info('Configuring operating system image')
resin.models.device.get(params.uuid)
.get('device_type')
.then(resin.models.device.getManifestBySlug)
.get('options')
.then(form.run)
.then (answers) ->
init.configure(params.image, params.uuid, answers).then(stepHandler)
.nodeify(done)

View File

@ -66,6 +66,7 @@ capitano.command(actions.env.remove)
# ---------- OS Module ----------
capitano.command(actions.os.download)
capitano.command(actions.os.configure)
# ---------- Logs Module ----------
capitano.command(actions.logs)

View File

@ -26,4 +26,5 @@ exports.stateToString = (state) ->
exports.waitStream = (stream) ->
return new Promise (resolve, reject) ->
stream.on('close', resolve)
stream.on('end', resolve)
stream.on('error', reject)

View File

@ -69,9 +69,3 @@ exports.awaitDevice = (uuid) ->
resin.models.device.getName(uuid).then (deviceName) ->
console.info("Waiting for #{deviceName} to connect to resin...")
poll().return(uuid)
exports.askDeviceOptions = (deviceType) ->
resin.models.config.getDeviceOptions(deviceType).then(form.run)
.then (answers) ->
answers.os ?= helpers.getOperatingSystem()
return answers