diff --git a/lib/actions/device.coffee b/lib/actions/device.coffee deleted file mode 100644 index 4c51e99f..00000000 --- a/lib/actions/device.coffee +++ /dev/null @@ -1,443 +0,0 @@ -### -Copyright 2016-2017 Balena - -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. -### - -commandOptions = require('./command-options') -_ = require('lodash') -{ normalizeUuidProp } = require('../utils/normalization') -{ getBalenaSdk, getVisuals } = require('../utils/lazy') - -expandForAppName = { - $expand: belongs_to__application: $select: 'app_name' -} - -exports.list = - signature: 'devices' - description: 'list all devices' - help: ''' - Use this command to list all devices that belong to you. - - You can filter the devices by application by using the `--application` option. - - Examples: - - $ balena devices - $ balena devices --application MyApp - $ balena devices --app MyApp - $ balena devices -a MyApp - ''' - options: [ commandOptions.optionalApplication ] - permission: 'user' - primary: true - action: (params, options) -> - Promise = require('bluebird') - balena = getBalenaSdk() - - Promise.try -> - if options.application? - return balena.models.device.getAllByApplication(options.application, expandForAppName) - return balena.models.device.getAll(expandForAppName) - - .tap (devices) -> - devices = _.map devices, (device) -> - device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid) - device.application_name = - if device.belongs_to__application?[0] then device.belongs_to__application[0].app_name else 'N/a' - device.uuid = device.uuid.slice(0, 7) - return device - - console.log getVisuals().table.horizontal devices, [ - 'id' - 'uuid' - 'device_name' - 'device_type' - 'application_name' - 'status' - 'is_online' - 'supervisor_version' - 'os_version' - 'dashboard_url' - ] - -exports.info = - signature: 'device <uuid>' - description: 'list a single device' - help: ''' - Use this command to show information about a single device. - - Examples: - - $ balena device 7cf02a6 - ''' - permission: 'user' - primary: true - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - - balena.models.device.get(params.uuid, expandForAppName) - .then (device) -> - balena.models.device.getStatus(device).then (status) -> - device.status = status - device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid) - device.application_name = - if device.belongs_to__application?[0] then device.belongs_to__application[0].app_name else 'N/a' - device.commit = device.is_on__commit - - console.log getVisuals().table.vertical device, [ - "$#{device.device_name}$" - 'id' - 'device_type' - 'status' - 'is_online' - 'ip_address' - 'application_name' - 'last_seen' - 'uuid' - 'commit' - 'supervisor_version' - 'is_web_accessible' - 'note' - 'os_version' - 'dashboard_url' - ] - -exports.register = - signature: 'device register <application>' - description: 'register a device' - help: ''' - Use this command to register a device to an application. - - Examples: - - $ balena device register MyApp - $ balena device register MyApp --uuid <uuid> - ''' - permission: 'user' - options: [ - { - signature: 'uuid' - description: 'custom uuid' - parameter: 'uuid' - alias: 'u' - } - ] - action: (params, options) -> - Promise = require('bluebird') - balena = getBalenaSdk() - - Promise.join( - balena.models.application.get(params.application) - options.uuid ? balena.models.device.generateUniqueKey() - (application, uuid) -> - console.info("Registering to #{application.app_name}: #{uuid}") - return balena.models.device.register(application.id, uuid) - ) - .get('uuid') - -exports.remove = - signature: 'device rm <uuid>' - description: 'remove a device' - help: ''' - Use this command to remove a device from balena. - - Notice this command asks for confirmation interactively. - You can avoid this by passing the `--yes` boolean option. - - Examples: - - $ balena device rm 7cf02a6 - $ balena device rm 7cf02a6 --yes - ''' - options: [ commandOptions.yes ] - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - patterns = require('../utils/patterns') - - patterns.confirm(options.yes, 'Are you sure you want to delete the device?').then -> - balena.models.device.remove(params.uuid) - -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: - - $ balena device identify 23c73a1 - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.identify(params.uuid) - -exports.reboot = - signature: 'device reboot <uuid>' - description: 'restart a device' - help: ''' - Use this command to remotely reboot a device - - Examples: - - $ balena device reboot 23c73a1 - ''' - options: [ commandOptions.forceUpdateLock ] - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.reboot(params.uuid, options) - -exports.shutdown = - signature: 'device shutdown <uuid>' - description: 'shutdown a device' - help: ''' - Use this command to remotely shutdown a device - - Examples: - - $ balena device shutdown 23c73a1 - ''' - options: [ commandOptions.forceUpdateLock ] - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.shutdown(params.uuid, options) - -exports.enableDeviceUrl = - signature: 'device public-url enable <uuid>' - description: 'enable public URL for a device' - help: ''' - Use this command to enable public URL for a device - - Examples: - - $ balena device public-url enable 23c73a1 - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.enableDeviceUrl(params.uuid) - -exports.disableDeviceUrl = - signature: 'device public-url disable <uuid>' - description: 'disable public URL for a device' - help: ''' - Use this command to disable public URL for a device - - Examples: - - $ balena device public-url disable 23c73a1 - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.disableDeviceUrl(params.uuid) - -exports.getDeviceUrl = - signature: 'device public-url <uuid>' - description: 'gets the public URL of a device' - help: ''' - Use this command to get the public URL of a device - - Examples: - - $ balena device public-url 23c73a1 - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.getDeviceUrl(params.uuid).then (url) -> - console.log(url) - -exports.hasDeviceUrl = - signature: 'device public-url status <uuid>' - description: 'Returns true if public URL is enabled for a device' - help: ''' - Use this command to determine if public URL is enabled for a device - - Examples: - - $ balena device public-url status 23c73a1 - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - balena.models.device.hasDeviceUrl(params.uuid).then (hasDeviceUrl) -> - console.log(hasDeviceUrl) - -exports.rename = - signature: 'device rename <uuid> [newName]' - description: 'rename a balena device' - help: ''' - Use this command to rename a device. - - If you omit the name, you'll get asked for it interactively. - - Examples: - - $ balena device rename 7cf02a6 - $ balena device rename 7cf02a6 MyPi - ''' - permission: 'user' - action: (params, options) -> - normalizeUuidProp(params) - Promise = require('bluebird') - balena = getBalenaSdk() - form = require('resin-cli-form') - - Promise.try -> - return params.newName if not _.isEmpty(params.newName) - - form.ask - message: 'How do you want to name this device?' - type: 'input' - - .then(_.partial(balena.models.device.rename, params.uuid)) - -exports.move = - signature: 'device move <uuid>' - description: 'move a device to another application' - help: ''' - Use this command to move a device to another application you own. - - If you omit the application, you'll get asked for it interactively. - - Examples: - - $ balena device move 7cf02a6 - $ balena device move 7cf02a6 --application MyNewApp - ''' - permission: 'user' - options: [ commandOptions.optionalApplication ] - action: (params, options) -> - normalizeUuidProp(params) - balena = getBalenaSdk() - patterns = require('../utils/patterns') - - balena.models.device.get(params.uuid, expandForAppName).then (device) -> - device.application_name = - if device.belongs_to__application?[0] then device.belongs_to__application[0].app_name else 'N/a' - return options.application if options.application - - return Promise.all([ - balena.models.device.getManifestBySlug(device.device_type) - balena.models.config.getDeviceTypes() - ]).then ([deviceDeviceType, deviceTypes]) -> - compatibleDeviceTypes = deviceTypes.filter (dt) -> - balena.models.os.isArchitectureCompatibleWith(deviceDeviceType.arch, dt.arch) && - !!dt.isDependent == !!deviceDeviceType.isDependent && - dt.state != 'DISCONTINUED' - - return patterns.selectApplication (application) -> - return _.every [ - _.some(compatibleDeviceTypes, (dt) -> dt.slug == application.device_type) - device.application_name isnt application.app_name - ] - .tap (application) -> - return balena.models.device.move(params.uuid, application) - .then (application) -> - console.info("#{params.uuid} was moved to #{application}") - -exports.init = - signature: 'device init' - description: 'initialise a device with balenaOS' - help: ''' - Use this command to download the OS image of a certain application and write it to an SD Card. - - Notice this command may ask for confirmation interactively. - You can avoid this by passing the `--yes` boolean option. - - Examples: - - $ balena device init - $ balena device init --application MyApp - ''' - options: [ - commandOptions.optionalApplication - commandOptions.yes - commandOptions.advancedConfig - _.assign({}, commandOptions.osVersionOrSemver, { signature: 'os-version', parameter: 'os-version' }) - commandOptions.drive - { - signature: 'config' - description: 'path to the config JSON file, see `balena os build-config`' - parameter: 'config' - } - ] - permission: 'user' - action: (params, options) -> - Promise = require('bluebird') - rimraf = Promise.promisify(require('rimraf')) - tmp = require('tmp') - tmpNameAsync = Promise.promisify(tmp.tmpName) - tmp.setGracefulCleanup() - - balena = getBalenaSdk() - patterns = require('../utils/patterns') - { runCommand } = require('../utils/helpers') - - Promise.try -> - return options.application if options.application? - return patterns.selectApplication() - .then(balena.models.application.get) - .then (application) -> - - download = -> - tmpNameAsync().then (tempPath) -> - osVersion = options['os-version'] or 'default' - runCommand("os download #{application.device_type} --output '#{tempPath}' --version #{osVersion}") - .disposer (tempPath) -> - return rimraf(tempPath) - - Promise.using download(), (tempPath) -> - runCommand("device register #{application.app_name}") - .then(balena.models.device.get) - .tap (device) -> - configureCommand = "os configure '#{tempPath}' --device #{device.uuid}" - if options.config - configureCommand += " --config '#{options.config}'" - else if options.advanced - configureCommand += ' --advanced' - runCommand(configureCommand) - .then -> - osInitCommand = "os initialize '#{tempPath}' --type #{application.device_type}" - if options.yes - osInitCommand += ' --yes' - if options.drive - osInitCommand += " --drive #{options.drive}" - runCommand(osInitCommand) - # Make sure the device resource is removed if there is an - # error when configuring or initializing a device image - .catch (error) -> - balena.models.device.remove(device.uuid).finally -> - throw error - .then (device) -> - console.log('Done') - return device.uuid - -tsActions = require('./device_ts') -exports.osUpdate = tsActions.osUpdate diff --git a/lib/actions/device.js b/lib/actions/device.js new file mode 100644 index 00000000..8b5501c9 --- /dev/null +++ b/lib/actions/device.js @@ -0,0 +1,535 @@ +/* +Copyright 2016-2020 Balena Ltd. + +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. +*/ + +import * as commandOptions from './command-options'; + +import * as _ from 'lodash'; +import { normalizeUuidProp } from '../utils/normalization'; +import { getBalenaSdk, getVisuals } from '../utils/lazy'; + +/** @type {import('balena-sdk').PineOptionsFor<import('balena-sdk').Device>} */ +const expandForAppName = { + $expand: { belongs_to__application: { $select: 'app_name' } }, +}; + +export const list = { + signature: 'devices', + description: 'list all devices', + help: `\ +Use this command to list all devices that belong to you. + +You can filter the devices by application by using the \`--application\` option. + +Examples: + + $ balena devices + $ balena devices --application MyApp + $ balena devices --app MyApp + $ balena devices -a MyApp\ +`, + options: [commandOptions.optionalApplication], + permission: 'user', + primary: true, + action(_params, options) { + const Promise = require('bluebird'); + const balena = getBalenaSdk(); + + return Promise.try(function() { + if (options.application != null) { + return balena.models.device.getAllByApplication( + options.application, + expandForAppName, + ); + } + return balena.models.device.getAll(expandForAppName); + }).tap(function(devices) { + devices = _.map(devices, function(device) { + // @ts-ignore extending the device object with extra props + device.dashboard_url = balena.models.device.getDashboardUrl( + device.uuid, + ); + // @ts-ignore extending the device object with extra props + device.application_name = device.belongs_to__application?.[0] + ? device.belongs_to__application[0].app_name + : 'N/a'; + device.uuid = device.uuid.slice(0, 7); + return device; + }); + + console.log( + getVisuals().table.horizontal(devices, [ + 'id', + 'uuid', + 'device_name', + 'device_type', + 'application_name', + 'status', + 'is_online', + 'supervisor_version', + 'os_version', + 'dashboard_url', + ]), + ); + }); + }, +}; + +export const info = { + signature: 'device <uuid>', + description: 'list a single device', + help: `\ +Use this command to show information about a single device. + +Examples: + + $ balena device 7cf02a6\ +`, + permission: 'user', + primary: true, + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + + return balena.models.device + .get(params.uuid, expandForAppName) + .then(device => + // @ts-ignore `device.getStatus` requires a device with service info, but + // this device isn't typed with them, possibly needs fixing? + balena.models.device.getStatus(device).then(function(status) { + device.status = status; + // @ts-ignore extending the device object with extra props + device.dashboard_url = balena.models.device.getDashboardUrl( + device.uuid, + ); + // @ts-ignore extending the device object with extra props + device.application_name = device.belongs_to__application?.[0] + ? device.belongs_to__application[0].app_name + : 'N/a'; + // @ts-ignore extending the device object with extra props + device.commit = device.is_on__commit; + + console.log( + getVisuals().table.vertical(device, [ + `$${device.device_name}$`, + 'id', + 'device_type', + 'status', + 'is_online', + 'ip_address', + 'application_name', + 'last_seen', + 'uuid', + 'commit', + 'supervisor_version', + 'is_web_accessible', + 'note', + 'os_version', + 'dashboard_url', + ]), + ); + }), + ); + }, +}; + +export const register = { + signature: 'device register <application>', + description: 'register a device', + help: `\ +Use this command to register a device to an application. + +Examples: + + $ balena device register MyApp + $ balena device register MyApp --uuid <uuid>\ +`, + permission: 'user', + options: [ + { + signature: 'uuid', + description: 'custom uuid', + parameter: 'uuid', + alias: 'u', + }, + ], + action(params, options) { + const Promise = require('bluebird'); + const balena = getBalenaSdk(); + + return Promise.join( + balena.models.application.get(params.application), + options.uuid ?? balena.models.device.generateUniqueKey(), + function(application, uuid) { + console.info(`Registering to ${application.app_name}: ${uuid}`); + return balena.models.device.register(application.id, uuid); + }, + ).get('uuid'); + }, +}; + +export const remove = { + signature: 'device rm <uuid>', + description: 'remove a device', + help: `\ +Use this command to remove a device from balena. + +Notice this command asks for confirmation interactively. +You can avoid this by passing the \`--yes\` boolean option. + +Examples: + + $ balena device rm 7cf02a6 + $ balena device rm 7cf02a6 --yes\ +`, + options: [commandOptions.yes], + permission: 'user', + action(params, options) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + const patterns = require('../utils/patterns'); + + return patterns + .confirm(options.yes, 'Are you sure you want to delete the device?') + .then(() => balena.models.device.remove(params.uuid)); + }, +}; + +export const 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: + + $ balena device identify 23c73a1\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.identify(params.uuid); + }, +}; + +export const reboot = { + signature: 'device reboot <uuid>', + description: 'restart a device', + help: `\ +Use this command to remotely reboot a device + +Examples: + + $ balena device reboot 23c73a1\ +`, + options: [commandOptions.forceUpdateLock], + permission: 'user', + action(params, options) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.reboot(params.uuid, options); + }, +}; + +export const shutdown = { + signature: 'device shutdown <uuid>', + description: 'shutdown a device', + help: `\ +Use this command to remotely shutdown a device + +Examples: + + $ balena device shutdown 23c73a1\ +`, + options: [commandOptions.forceUpdateLock], + permission: 'user', + action(params, options) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.shutdown(params.uuid, options); + }, +}; + +export const enableDeviceUrl = { + signature: 'device public-url enable <uuid>', + description: 'enable public URL for a device', + help: `\ +Use this command to enable public URL for a device + +Examples: + + $ balena device public-url enable 23c73a1\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.enableDeviceUrl(params.uuid); + }, +}; + +export const disableDeviceUrl = { + signature: 'device public-url disable <uuid>', + description: 'disable public URL for a device', + help: `\ +Use this command to disable public URL for a device + +Examples: + + $ balena device public-url disable 23c73a1\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.disableDeviceUrl(params.uuid); + }, +}; + +export const getDeviceUrl = { + signature: 'device public-url <uuid>', + description: 'gets the public URL of a device', + help: `\ +Use this command to get the public URL of a device + +Examples: + + $ balena device public-url 23c73a1\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.getDeviceUrl(params.uuid).then(url => { + console.log(url); + }); + }, +}; + +export const hasDeviceUrl = { + signature: 'device public-url status <uuid>', + description: 'Returns true if public URL is enabled for a device', + help: `\ +Use this command to determine if public URL is enabled for a device + +Examples: + + $ balena device public-url status 23c73a1\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + return balena.models.device.hasDeviceUrl(params.uuid).then(hasUrl => { + console.log(hasUrl); + }); + }, +}; + +export const rename = { + signature: 'device rename <uuid> [newName]', + description: 'rename a balena device', + help: `\ +Use this command to rename a device. + +If you omit the name, you'll get asked for it interactively. + +Examples: + + $ balena device rename 7cf02a6 + $ balena device rename 7cf02a6 MyPi\ +`, + permission: 'user', + action(params) { + normalizeUuidProp(params); + const Promise = require('bluebird'); + const balena = getBalenaSdk(); + const form = require('resin-cli-form'); + + return Promise.try(function() { + if (!_.isEmpty(params.newName)) { + return params.newName; + } + + return form.ask({ + message: 'How do you want to name this device?', + type: 'input', + }); + }).then(_.partial(balena.models.device.rename, params.uuid)); + }, +}; + +export const move = { + signature: 'device move <uuid>', + description: 'move a device to another application', + help: `\ +Use this command to move a device to another application you own. + +If you omit the application, you'll get asked for it interactively. + +Examples: + + $ balena device move 7cf02a6 + $ balena device move 7cf02a6 --application MyNewApp\ +`, + permission: 'user', + options: [commandOptions.optionalApplication], + action(params, options) { + normalizeUuidProp(params); + const balena = getBalenaSdk(); + const patterns = require('../utils/patterns'); + + return balena.models.device + .get(params.uuid, expandForAppName) + .then(function(device) { + // @ts-ignore extending the device object with extra props + device.application_name = device.belongs_to__application?.[0] + ? device.belongs_to__application[0].app_name + : 'N/a'; + if (options.application) { + return options.application; + } + + return Promise.all([ + balena.models.device.getManifestBySlug(device.device_type), + balena.models.config.getDeviceTypes(), + ]).then(function([deviceDeviceType, deviceTypes]) { + const compatibleDeviceTypes = deviceTypes.filter( + dt => + balena.models.os.isArchitectureCompatibleWith( + deviceDeviceType.arch, + dt.arch, + ) && + !!dt.isDependent === !!deviceDeviceType.isDependent && + dt.state !== 'DISCONTINUED', + ); + + return patterns.selectApplication(application => + _.every([ + _.some( + compatibleDeviceTypes, + dt => dt.slug === application.device_type, + ), + // @ts-ignore using the extended device object prop + device.application_name !== application.app_name, + ]), + ); + }); + }) + .tap(application => balena.models.device.move(params.uuid, application)) + .then(application => { + console.info(`${params.uuid} was moved to ${application}`); + }); + }, +}; + +export const init = { + signature: 'device init', + description: 'initialise a device with balenaOS', + help: `\ +Use this command to download the OS image of a certain application and write it to an SD Card. + +Notice this command may ask for confirmation interactively. +You can avoid this by passing the \`--yes\` boolean option. + +Examples: + + $ balena device init + $ balena device init --application MyApp\ +`, + options: [ + commandOptions.optionalApplication, + commandOptions.yes, + commandOptions.advancedConfig, + _.assign({}, commandOptions.osVersionOrSemver, { + signature: 'os-version', + parameter: 'os-version', + }), + commandOptions.drive, + { + signature: 'config', + description: 'path to the config JSON file, see `balena os build-config`', + parameter: 'config', + }, + ], + permission: 'user', + action(_params, options) { + const Promise = require('bluebird'); + const rimraf = Promise.promisify(require('rimraf')); + const tmp = require('tmp'); + const tmpNameAsync = Promise.promisify(tmp.tmpName); + tmp.setGracefulCleanup(); + + const balena = getBalenaSdk(); + const patterns = require('../utils/patterns'); + const { runCommand } = require('../utils/helpers'); + + return Promise.try(function() { + if (options.application != null) { + return options.application; + } + return patterns.selectApplication(); + }) + .then(balena.models.application.get) + .then(function(application) { + const download = () => + tmpNameAsync() + .then(function(tempPath) { + const osVersion = options['os-version'] || 'default'; + return runCommand( + `os download ${application.device_type} --output '${tempPath}' --version ${osVersion}`, + ); + }) + .disposer(tempPath => rimraf(tempPath)); + + return Promise.using(download(), tempPath => + runCommand(`device register ${application.app_name}`) + .then(balena.models.device.get) + .tap(function(device) { + let configureCommand = `os configure '${tempPath}' --device ${device.uuid}`; + if (options.config) { + configureCommand += ` --config '${options.config}'`; + } else if (options.advanced) { + configureCommand += ' --advanced'; + } + return runCommand(configureCommand) + .then(function() { + let osInitCommand = `os initialize '${tempPath}' --type ${application.device_type}`; + if (options.yes) { + osInitCommand += ' --yes'; + } + if (options.drive) { + osInitCommand += ` --drive ${options.drive}`; + } + return runCommand(osInitCommand); + }) + .catch(error => + balena.models.device.remove(device.uuid).finally(function() { + throw error; + }), + ); + }), + ).then(function(device) { + console.log('Done'); + return device.uuid; + }); + }); + }, +}; + +export { osUpdate } from './device_ts'; diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index 207f5696..5a092954 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -94,7 +94,7 @@ export async function sudo( await executeWithPrivileges(command, stderr, isCLIcmd); } -export function runCommand(command: string): Bluebird<void> { +export function runCommand<T>(command: string): Bluebird<T> { const capitano = require('capitano'); return Bluebird.fromCallback(resolver => capitano.run(command, resolver)); } diff --git a/lib/utils/patterns.ts b/lib/utils/patterns.ts index 6797ffd3..5b8706c4 100644 --- a/lib/utils/patterns.ts +++ b/lib/utils/patterns.ts @@ -179,7 +179,7 @@ export function confirm( } export function selectApplication( - filter: (app: BalenaSdk.Application) => boolean, + filter?: (app: BalenaSdk.Application) => boolean, ) { const balena = getBalenaSdk(); return balena.models.application diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d69074ff..ed8d53d6 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1336,6 +1336,12 @@ "@types/node": "*" } }, + "@types/tmp": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.34.tgz", + "integrity": "sha512-Tx7JYeYR+pkAnDQjN1Cj43KuOuUvyybZHl+fAezReXuH/SQoxLhsuPvHZH/SA4XtrBEhaTcbb5gVc1WQcjQgdg==", + "dev": true + }, "@types/tough-cookie": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz", diff --git a/package.json b/package.json index b7df6412..cc6fc2ff 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "@types/stream-to-promise": "2.2.0", "@types/tar-stream": "^2.1.0", "@types/through2": "^2.0.34", + "@types/tmp": "0.0.34", "@types/which": "^1.3.2", "catch-uncommitted": "^1.5.0", "chai": "^4.2.0",