From 3b35aed3bf28e0968c3f0f0b3fd917850c3e861c Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 10 Nov 2015 14:27:01 -0400 Subject: [PATCH] Implement config write command This command allows the user to overwrite properties of the config.json file. --- build/actions/config.js | 93 +++++++++++++++++++++++++++++++------- build/app.js | 2 + doc/cli.markdown | 23 +++++++++- lib/actions/config.coffee | 94 ++++++++++++++++++++++++++++++++------- lib/app.coffee | 1 + package.json | 1 + 6 files changed, 183 insertions(+), 31 deletions(-) diff --git a/build/actions/config.js b/build/actions/config.js index d9c84614..a0c585d6 100644 --- a/build/actions/config.js +++ b/build/actions/config.js @@ -1,10 +1,14 @@ (function() { - var Promise, imagefs, prettyjson, resin, rindle, umount, visuals; + var Promise, _, getConfigPartitionInformationByType, imagefs, prettyjson, readConfigJSON, resin, rindle, stringToStream, umount, visuals, writeConfigJSON; + + _ = require('lodash'); Promise = require('bluebird'); umount = Promise.promisifyAll(require('umount')); + stringToStream = require('string-to-stream'); + resin = require('resin-sdk'); imagefs = require('resin-image-fs'); @@ -15,10 +19,41 @@ rindle = require('rindle'); + getConfigPartitionInformationByType = function(type) { + return resin.models.device.getManifestBySlug(type).then(function(manifest) { + var config, ref; + config = (ref = manifest.configuration) != null ? ref.config : void 0; + if (config == null) { + throw new Error("Unsupported device type: " + type); + } + return config; + }); + }; + + readConfigJSON = function(drive, type) { + return getConfigPartitionInformationByType(type).then(function(configuration) { + return imagefs.read({ + image: drive, + partition: configuration.partition, + path: configuration.path + }); + }).then(rindle.extract).then(JSON.parse); + }; + + writeConfigJSON = function(drive, type, config) { + return getConfigPartitionInformationByType(type).then(function(configuration) { + return imagefs.write({ + image: drive, + partition: configuration.partition, + path: configuration.path + }, stringToStream(config)); + }).then(rindle.wait); + }; + exports.read = { signature: 'config read', description: 'read a device configuration', - help: 'Use this command to read the config.json file from a provisioned device\n\nExample:\n\n $ resin config read --type raspberry-pi\n $ resin config read --type raspberry-pi --drive /dev/disk2', + help: 'Use this command to read the config.json file from a provisioned device\n\nExamples:\n\n $ resin config read --type raspberry-pi\n $ resin config read --type raspberry-pi --drive /dev/disk2', options: [ { signature: 'type', @@ -39,20 +74,48 @@ return Promise["try"](function() { return options.drive || visuals.drive('Select the device drive'); }).tap(umount.umountAsync).then(function(drive) { - return resin.models.device.getManifestBySlug(options.type).then(function(manifest) { - var config, ref; - config = (ref = manifest.configuration) != null ? ref.config : void 0; - if (config == null) { - throw new Error("Unsupported device type: " + options.type); - } - return imagefs.read({ - image: drive, - partition: config.partition, - path: config.path - }); + return readConfigJSON(drive, options.type); + }).tap(function(config) { + return console.info(prettyjson.render(config)); + }).nodeify(done); + } + }; + + exports.write = { + signature: 'config write ', + description: 'write a device configuration', + help: 'Use this command to write the config.json file of a provisioned device\n\nExamples:\n\n $ resin config write --type raspberry-pi username johndoe\n $ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe\n $ resin config write --type raspberry-pi files.network/settings "..."', + options: [ + { + signature: 'type', + description: 'device type', + parameter: 'type', + alias: 't', + required: 'You have to specify a device type' + }, { + signature: 'drive', + description: 'drive', + parameter: 'drive', + alias: 'd' + } + ], + permission: 'user', + root: true, + action: function(params, options, done) { + return Promise["try"](function() { + return options.drive || visuals.drive('Select the device drive'); + }).tap(umount.umountAsync).then(function(drive) { + return readConfigJSON(drive, options.type).then(function(config) { + console.info("Setting " + params.key + " to " + params.value); + _.set(config, params.key, params.value); + return JSON.stringify(config); + }).tap(function() { + return umount.umountAsync(drive); + }).then(function(config) { + return writeConfigJSON(drive, options.type, config); }); - }).then(rindle.extract).then(JSON.parse).then(function(config) { - return console.log(prettyjson.render(config)); + }).tap(function() { + return console.info('Done'); }).nodeify(done); } }; diff --git a/build/app.js b/build/app.js index 891617b4..9c0e610c 100644 --- a/build/app.js +++ b/build/app.js @@ -98,6 +98,8 @@ capitano.command(actions.config.read); + capitano.command(actions.config.write); + capitano.command(actions.logs); update.notify(); diff --git a/doc/cli.markdown b/doc/cli.markdown index a2470fed..b44449f7 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -79,6 +79,7 @@ Now you have access to all the commands referenced below. - Config - [config read](#config-read) + - [config write <key> <value>](#config-write-60-key-62-60-value-62-) - Wizard @@ -604,7 +605,7 @@ drive Use this command to read the config.json file from a provisioned device -Example: +Examples: $ resin config read --type raspberry-pi $ resin config read --type raspberry-pi --drive /dev/disk2 @@ -619,6 +620,26 @@ device type drive +## config write <key> <value> + +Use this command to write the config.json file of a provisioned device + +Examples: + + $ resin config write --type raspberry-pi username johndoe + $ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe + $ resin config write --type raspberry-pi files.network/settings "..." + +### Options + +#### --type, -t <type> + +device type + +#### --drive, -d <drive> + +drive + # Wizard ## quickstart [name] diff --git a/lib/actions/config.coffee b/lib/actions/config.coffee index 7c9aea43..79a378ae 100644 --- a/lib/actions/config.coffee +++ b/lib/actions/config.coffee @@ -1,18 +1,47 @@ +_ = require('lodash') Promise = require('bluebird') umount = Promise.promisifyAll(require('umount')) +stringToStream = require('string-to-stream') resin = require('resin-sdk') imagefs = require('resin-image-fs') visuals = require('resin-cli-visuals') prettyjson = require('prettyjson') rindle = require('rindle') +getConfigPartitionInformationByType = (type) -> + return resin.models.device.getManifestBySlug(type).then (manifest) -> + config = manifest.configuration?.config + + if not config? + throw new Error("Unsupported device type: #{type}") + + return config + +readConfigJSON = (drive, type) -> + return getConfigPartitionInformationByType(type).then (configuration) -> + return imagefs.read + image: drive + partition: configuration.partition + path: configuration.path + .then(rindle.extract) + .then(JSON.parse) + +writeConfigJSON = (drive, type, config) -> + return getConfigPartitionInformationByType(type).then (configuration) -> + return imagefs.write + image: drive + partition: configuration.partition + path: configuration.path + , stringToStream(config) + .then(rindle.wait) + exports.read = signature: 'config read' description: 'read a device configuration' help: ''' Use this command to read the config.json file from a provisioned device - Example: + Examples: $ resin config read --type raspberry-pi $ resin config read --type raspberry-pi --drive /dev/disk2 @@ -39,18 +68,53 @@ exports.read = return options.drive or visuals.drive('Select the device drive') .tap(umount.umountAsync) .then (drive) -> - resin.models.device.getManifestBySlug(options.type).then (manifest) -> - config = manifest.configuration?.config - - if not config? - throw new Error("Unsupported device type: #{options.type}") - - imagefs.read - image: drive - partition: config.partition - path: config.path - .then(rindle.extract) - .then(JSON.parse) - .then (config) -> - console.log(prettyjson.render(config)) + return readConfigJSON(drive, options.type) + .tap (config) -> + console.info(prettyjson.render(config)) + .nodeify(done) + +exports.write = + signature: 'config write ' + description: 'write a device configuration' + help: ''' + Use this command to write the config.json file of a provisioned device + + Examples: + + $ resin config write --type raspberry-pi username johndoe + $ resin config write --type raspberry-pi --drive /dev/disk2 username johndoe + $ resin config write --type raspberry-pi files.network/settings "..." + ''' + options: [ + { + signature: 'type' + description: 'device type' + parameter: 'type' + alias: 't' + required: 'You have to specify a device type' + } + { + signature: 'drive' + description: 'drive' + parameter: 'drive' + alias: 'd' + } + ] + permission: 'user' + root: true + action: (params, options, done) -> + Promise.try -> + return options.drive or visuals.drive('Select the device drive') + .tap(umount.umountAsync) + .then (drive) -> + readConfigJSON(drive, options.type).then (config) -> + console.info("Setting #{params.key} to #{params.value}") + _.set(config, params.key, params.value) + return JSON.stringify(config) + .tap -> + return umount.umountAsync(drive) + .then (config) -> + return writeConfigJSON(drive, options.type, config) + .tap -> + console.info('Done') .nodeify(done) diff --git a/lib/app.coffee b/lib/app.coffee index e3666619..86a1bd80 100644 --- a/lib/app.coffee +++ b/lib/app.coffee @@ -71,6 +71,7 @@ capitano.command(actions.os.initialize) # ---------- Config Module ---------- capitano.command(actions.config.read) +capitano.command(actions.config.write) # ---------- Logs Module ---------- capitano.command(actions.logs) diff --git a/package.json b/package.json index 6f2d362c..0011fc18 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "resin-vcs": "^2.0.0", "rimraf": "^2.4.3", "rindle": "^1.0.0", + "string-to-stream": "^1.0.1", "tmp": "0.0.28", "umount": "^1.1.1", "underscore.string": "^3.1.1",