2014-12-24 16:49:49 +00:00
|
|
|
_ = require('lodash-contrib')
|
2014-12-19 14:05:54 +00:00
|
|
|
async = require('async')
|
2015-01-08 12:04:37 +00:00
|
|
|
resin = require('resin-sdk')
|
2015-01-20 19:34:47 +00:00
|
|
|
os = require('os')
|
|
|
|
fs = require('fs')
|
|
|
|
progressStream = require('progress-stream')
|
2015-01-21 13:50:19 +00:00
|
|
|
visuals = require('resin-cli-visuals')
|
2015-01-15 17:10:14 +00:00
|
|
|
commandOptions = require('./command-options')
|
2014-11-19 17:38:15 +00:00
|
|
|
|
2015-01-15 17:10:14 +00:00
|
|
|
exports.list =
|
|
|
|
signature: 'devices'
|
|
|
|
description: 'list all devices'
|
|
|
|
help: '''
|
|
|
|
Use this command to list all devices that belong to a certain application.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin devices --application 91
|
|
|
|
'''
|
|
|
|
options: [ commandOptions.application ]
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
2015-01-15 17:10:14 +00:00
|
|
|
resin.models.device.getAllByApplication options.application, (error, devices) ->
|
|
|
|
return done(error) if error?
|
2015-01-21 13:50:19 +00:00
|
|
|
console.log visuals.widgets.table.horizontal devices, [
|
2015-01-15 17:10:14 +00:00
|
|
|
'ID'
|
|
|
|
'Name'
|
|
|
|
'Device Display Name'
|
|
|
|
'Is Online'
|
|
|
|
'Application Name'
|
|
|
|
'Status'
|
|
|
|
'Last Seen'
|
|
|
|
]
|
|
|
|
|
|
|
|
return done()
|
|
|
|
|
|
|
|
exports.info =
|
|
|
|
signature: 'device <id>'
|
|
|
|
description: 'list a single device'
|
|
|
|
help: '''
|
|
|
|
Use this command to show information about a single device.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin device 317
|
|
|
|
'''
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
2015-01-15 17:10:14 +00:00
|
|
|
resin.models.device.get params.id, (error, device) ->
|
|
|
|
return done(error) if error?
|
2015-01-21 13:50:19 +00:00
|
|
|
console.log visuals.widgets.table.vertical device, [
|
2015-01-15 17:10:14 +00:00
|
|
|
'ID'
|
|
|
|
'Name'
|
|
|
|
'Device Display Name'
|
|
|
|
'Is Online'
|
|
|
|
'IP Address'
|
|
|
|
'Application Name'
|
|
|
|
'Status'
|
|
|
|
'Last Seen'
|
|
|
|
'UUID'
|
|
|
|
'Commit'
|
|
|
|
'Supervisor Version'
|
|
|
|
'Is Web Accessible'
|
|
|
|
'Note'
|
|
|
|
]
|
|
|
|
|
|
|
|
return done()
|
|
|
|
|
|
|
|
exports.remove =
|
|
|
|
signature: 'device rm <id>'
|
|
|
|
description: 'remove a device'
|
|
|
|
help: '''
|
|
|
|
Use this command to remove a device from resin.io.
|
|
|
|
|
|
|
|
Notice this command asks for confirmation interactively.
|
|
|
|
You can avoid this by passing the `--yes` boolean option.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin device rm 317
|
|
|
|
$ resin device rm 317 --yes
|
|
|
|
'''
|
|
|
|
options: [ commandOptions.yes ]
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
2015-01-21 13:50:19 +00:00
|
|
|
visuals.patterns.remove 'device', options.yes, (callback) ->
|
2015-01-15 17:10:14 +00:00
|
|
|
resin.models.device.remove(params.id, callback)
|
|
|
|
, done
|
|
|
|
|
|
|
|
exports.identify =
|
|
|
|
signature: 'device identify <uuid>'
|
|
|
|
description: 'identify a device with a UUID'
|
|
|
|
help: '''
|
|
|
|
Use this command to identify a device.
|
|
|
|
|
|
|
|
In the Raspberry Pi, the ACT led is blinked several times.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin device identify 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828
|
|
|
|
'''
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
2015-01-15 17:10:14 +00:00
|
|
|
resin.models.device.identify(params.uuid, done)
|
|
|
|
|
|
|
|
exports.rename =
|
|
|
|
signature: 'device rename <id> [name]'
|
|
|
|
description: 'rename a resin device'
|
|
|
|
help: '''
|
|
|
|
Use this command to rename a device.
|
|
|
|
|
|
|
|
If you omit the name, you'll get asked for it interactively.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin device rename 317 MyPi
|
|
|
|
$ resin device rename 317
|
|
|
|
'''
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
2015-01-15 17:10:14 +00:00
|
|
|
async.waterfall [
|
|
|
|
|
|
|
|
(callback) ->
|
|
|
|
if not _.isEmpty(params.name)
|
|
|
|
return callback(null, params.name)
|
2015-01-21 13:50:19 +00:00
|
|
|
visuals.widgets.ask('How do you want to name this device?', callback)
|
2015-01-15 17:10:14 +00:00
|
|
|
|
|
|
|
(name, callback) ->
|
|
|
|
resin.models.device.rename(params.id, name, callback)
|
|
|
|
|
|
|
|
], done
|
|
|
|
|
|
|
|
exports.supported =
|
|
|
|
signature: 'devices supported'
|
|
|
|
description: 'list all supported devices'
|
|
|
|
help: '''
|
|
|
|
Use this command to get the list of all supported devices
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin devices supported
|
|
|
|
'''
|
2015-01-16 12:34:59 +00:00
|
|
|
permission: 'user'
|
|
|
|
action: ->
|
2015-01-15 17:10:14 +00:00
|
|
|
devices = resin.models.device.getSupportedDeviceTypes()
|
|
|
|
_.each(devices, _.unary(console.log))
|
2015-01-20 19:34:47 +00:00
|
|
|
|
|
|
|
exports.init =
|
|
|
|
signature: 'device init <image> <device>'
|
|
|
|
description: 'write an operating system image to a device'
|
|
|
|
help: '''
|
|
|
|
Use this command to write an operating system image to a device.
|
|
|
|
|
|
|
|
Note that this command requires admin privileges.
|
|
|
|
|
|
|
|
Notice this command asks for confirmation interactively.
|
|
|
|
You can avoid this by passing the `--yes` boolean option.
|
|
|
|
|
|
|
|
You can quiet the progress bar by passing the `--quiet` boolean option.
|
|
|
|
|
|
|
|
You may have to unmount the device before attempting this operation.
|
|
|
|
|
|
|
|
In Mac OS X:
|
2015-01-20 19:36:01 +00:00
|
|
|
$ sudo diskutil unmountDisk /dev/xxx
|
2015-01-20 19:34:47 +00:00
|
|
|
|
|
|
|
In GNU/Linux:
|
|
|
|
$ sudo umount /dev/xxx
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
$ resin device init rpi.iso /dev/disk2
|
|
|
|
'''
|
|
|
|
options: [ commandOptions.yes ]
|
|
|
|
permission: 'user'
|
|
|
|
action: (params, options, done) ->
|
|
|
|
if os.platform() is 'win32'
|
|
|
|
error = new Error('This functionality is only available on UNIX based systems for now.')
|
|
|
|
return done(error)
|
|
|
|
|
|
|
|
if not fs.existsSync(params.image)
|
|
|
|
error = new Error("Invalid OS image: #{params.image}")
|
|
|
|
return done(error)
|
|
|
|
|
|
|
|
if not fs.existsSync(params.device)
|
|
|
|
error = new Error("Invalid device: #{params.device}")
|
|
|
|
return done(error)
|
|
|
|
|
|
|
|
async.waterfall([
|
|
|
|
|
|
|
|
(callback) ->
|
|
|
|
if options.yes
|
|
|
|
return callback(null, true)
|
|
|
|
else
|
2015-01-21 13:50:19 +00:00
|
|
|
confirmMessage = "This will completely erase #{params.device}. Are you sure you want to continue?"
|
|
|
|
visuals.widgets.confirm(confirmMessage, callback)
|
2015-01-20 19:34:47 +00:00
|
|
|
|
|
|
|
(confirmed, callback) ->
|
|
|
|
return done() if not confirmed
|
|
|
|
|
|
|
|
imageFile = fs.createReadStream(params.image)
|
|
|
|
deviceFile = fs.createWriteStream(params.device)
|
|
|
|
imageFileSize = fs.statSync(params.image).size
|
|
|
|
|
|
|
|
progress = progressStream
|
|
|
|
length: imageFileSize
|
|
|
|
time: 500
|
|
|
|
|
|
|
|
if not options.quiet
|
2015-01-21 13:50:19 +00:00
|
|
|
progressBar = new visuals.widgets.Progress('Writing device OS', imageFileSize)
|
2015-01-20 19:34:47 +00:00
|
|
|
progress.on 'progress', (status) ->
|
|
|
|
progressBar.tick(status.delta)
|
|
|
|
|
|
|
|
imageFile
|
|
|
|
.pipe(progress)
|
|
|
|
.pipe(deviceFile)
|
|
|
|
.on 'error', (error) ->
|
|
|
|
if error.code is 'EBUSY'
|
|
|
|
error.message = "Try umounting #{error.path} first."
|
|
|
|
return callback(error)
|
|
|
|
.on('close', callback)
|
|
|
|
|
|
|
|
], done)
|
|
|
|
|