diff --git a/automation/capitanodoc/capitanodoc.ts b/automation/capitanodoc/capitanodoc.ts index cee0d606..4ae8a160 100644 --- a/automation/capitanodoc/capitanodoc.ts +++ b/automation/capitanodoc/capitanodoc.ts @@ -118,7 +118,7 @@ const capitanoDoc = { { title: 'OS', files: [ - 'build/actions/os.js', + 'build/actions-oclif/os/build-config.js', 'build/actions-oclif/os/configure.js', 'build/actions-oclif/os/versions.js', 'build/actions-oclif/os/download.js', diff --git a/doc/cli.markdown b/doc/cli.markdown index 29077a6a..c9b2e2a8 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -1585,22 +1585,33 @@ or 'menu' (will show the interactive menu) ## os build-config <image> <device-type> -Use this command to prebuild the OS config once and skip the interactive part of `balena os configure`. +Interactively generate an OS config once, so that the generated config +file can be used in `balena os configure`, skipping the interactive part. -Example: +Examples: $ balena os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json $ balena os configure ../path/rpi3.img --device 7cf02a6 --config rpi3-config.json +### Arguments + +#### IMAGE + +os image + +#### DEVICE-TYPE + +device type + ### Options -#### --advanced, -v +#### -v, --advanced show advanced configuration options -#### --output, -o <output> +#### -o, --output OUTPUT -the path to the output JSON file +path to output JSON file ## os configure IMAGE diff --git a/lib/actions-oclif/os/build-config.ts b/lib/actions-oclif/os/build-config.ts new file mode 100644 index 00000000..4a042934 --- /dev/null +++ b/lib/actions-oclif/os/build-config.ts @@ -0,0 +1,130 @@ +/** + * @license + * 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 { flags } from '@oclif/command'; +import Command from '../../command'; +import * as cf from '../../utils/common-flags'; +import { getCliForm, stripIndent } from '../../utils/lazy'; +import * as _ from 'lodash'; +import type { DeviceType } from 'balena-sdk'; + +interface FlagsDef { + advanced: boolean; + output: string; + help: void; +} + +interface ArgsDef { + image: string; + 'device-type': string; +} + +export default class OsBuildConfigCmd extends Command { + public static description = stripIndent` + Build an OS config and save it to a JSON file. + + Interactively generate an OS config once, so that the generated config + file can be used in \`balena os configure\`, skipping the interactive part. + `; + + public static examples = [ + '$ balena os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json', + '$ balena os configure ../path/rpi3.img --device 7cf02a6 --config rpi3-config.json', + ]; + + public static args = [ + { + name: 'image', + description: 'os image', + required: true, + }, + { + name: 'device-type', + description: 'device type', + required: true, + }, + ]; + + public static usage = 'os build-config '; + + public static flags: flags.Input = { + advanced: flags.boolean({ + description: 'show advanced configuration options', + char: 'v', + }), + output: flags.string({ + description: 'path to output JSON file', + char: 'o', + required: true, + }), + help: cf.help, + }; + + public static authenticated = true; + + public async run() { + const { args: params, flags: options } = this.parse( + OsBuildConfigCmd, + ); + + const { writeFile } = (await import('fs')).promises; + + const config = await this.buildConfig( + params.image, + params['device-type'], + options.advanced, + ); + + await writeFile(options.output, JSON.stringify(config, null, 4)); + + console.info(`Config file ${params.image} created successfully.`); + } + + async buildConfig(image: string, deviceTypeSlug: string, advanced: boolean) { + advanced = advanced || false; + + const { getManifest } = await import('../../utils/helpers'); + + const deviceTypeManifest = await getManifest(image, deviceTypeSlug); + await this.buildConfigForDeviceType(deviceTypeManifest, advanced); + } + + async buildConfigForDeviceType( + deviceTypeManifest: DeviceType, + advanced: boolean, + ) { + if (advanced == null) { + advanced = false; + } + + let override; + const questions = deviceTypeManifest.options; + if (!advanced) { + const advancedGroup = _.find(questions, { + name: 'advanced', + isGroup: true, + }); + + if (advancedGroup != null) { + const { getGroupDefaults } = await import('../../utils/helpers'); + override = getGroupDefaults(advancedGroup); + } + } + + return getCliForm().run(questions, { override }); + } +} diff --git a/lib/actions/index.ts b/lib/actions/index.ts index ad78fa66..5ba1eee4 100644 --- a/lib/actions/index.ts +++ b/lib/actions/index.ts @@ -16,11 +16,8 @@ limitations under the License. export * as config from './config'; export * as help from './help'; -export * as os from './os'; export * as push from './push'; export { build } from './build'; - export { deploy } from './deploy'; - export { preload } from './preload'; diff --git a/lib/actions/os.js b/lib/actions/os.js deleted file mode 100644 index adfd4806..00000000 --- a/lib/actions/os.js +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright 2016-2020 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. -*/ - -import * as commandOptions from './command-options'; -import * as _ from 'lodash'; -import { getCliForm } from '../utils/lazy'; - -const buildConfigForDeviceType = function (deviceType, advanced) { - if (advanced == null) { - advanced = false; - } - const helpers = require('../utils/helpers'); - - let override; - const questions = deviceType.options; - if (!advanced) { - const advancedGroup = _.find(questions, { - name: 'advanced', - isGroup: true, - }); - - if (advancedGroup != null) { - override = helpers.getGroupDefaults(advancedGroup); - } - } - - return getCliForm().run(questions, { override }); -}; - -const $buildConfig = function (image, deviceTypeSlug, advanced) { - if (advanced == null) { - advanced = false; - } - const Bluebird = require('bluebird'); - const helpers = require('../utils/helpers'); - - return Bluebird.resolve( - helpers.getManifest(image, deviceTypeSlug), - ).then((deviceTypeManifest) => - buildConfigForDeviceType(deviceTypeManifest, advanced), - ); -}; - -export const buildConfig = { - signature: 'os build-config ', - description: 'build the OS config and save it to the JSON file', - help: `\ -Use this command to prebuild the OS config once and skip the interactive part of \`balena os configure\`. - -Example: - - $ balena os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json - $ balena os configure ../path/rpi3.img --device 7cf02a6 --config rpi3-config.json\ -`, - permission: 'user', - options: [ - commandOptions.advancedConfig, - { - signature: 'output', - description: 'the path to the output JSON file', - alias: 'o', - required: 'the output path is required', - parameter: 'output', - }, - ], - action(params, options) { - return $buildConfig( - params.image, - params['device-type'], - options.advanced, - ).then((answers) => - require('fs').promises.writeFile( - options.output, - JSON.stringify(answers, null, 4), - ), - ); - }, -}; diff --git a/lib/app-capitano.ts b/lib/app-capitano.ts index b361a7fd..0f271689 100644 --- a/lib/app-capitano.ts +++ b/lib/app-capitano.ts @@ -46,9 +46,6 @@ capitano.globalOption({ // ---------- Help Module ---------- capitano.command(actions.help.help); -// ---------- OS Module ---------- -capitano.command(actions.os.buildConfig); - // ---------- Config Module ---------- capitano.command(actions.config.read); capitano.command(actions.config.write); diff --git a/lib/preparser.ts b/lib/preparser.ts index 56571db9..2a0facb0 100644 --- a/lib/preparser.ts +++ b/lib/preparser.ts @@ -179,6 +179,7 @@ export const convertedCommands = [ 'logout', 'logs', 'note', + 'os:build-config', 'os:configure', 'os:versions', 'os:download', diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index 6e6b1a9f..00cee500 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -28,7 +28,7 @@ import { promisify } from 'util'; import { isOclifCommand } from '../preparser'; export function getGroupDefaults(group: { - options: Array<{ name: string; default?: string }>; + options: Array<{ name: string; default: string | number }>; }): { [name: string]: string | number | undefined } { return _.chain(group) .get('options') diff --git a/tests/commands/help.spec.ts b/tests/commands/help.spec.ts index 0cc71ea3..1ba712d1 100644 --- a/tests/commands/help.spec.ts +++ b/tests/commands/help.spec.ts @@ -79,7 +79,7 @@ Additional commands: local flash flash an image to a drive logout logout from balena note <|note> set a device note - os build-config build the OS config and save it to the JSON file + os build-config build an OS config and save it to a JSON file os configure configure a previously downloaded balenaOS image os download download an unconfigured OS image os initialize initialize an os image for a device