mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Convert local flash
to oclif
Change-type: patch Signed-off-by: Scott Lowe <scott@balena.io>
This commit is contained in:
parent
92d37ffcb7
commit
7ebc94c1e5
@ -137,7 +137,10 @@ const capitanoDoc = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Local',
|
title: 'Local',
|
||||||
files: ['build/actions/local/index.js'],
|
files: [
|
||||||
|
'build/actions-oclif/local/flash.js',
|
||||||
|
'build/actions/local/index.js',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Deploy',
|
title: 'Deploy',
|
||||||
|
@ -250,8 +250,8 @@ Users are encouraged to regularly update the balena CLI to the latest version.
|
|||||||
|
|
||||||
- Local
|
- Local
|
||||||
|
|
||||||
- [local configure <target>](#local-configure-target)
|
|
||||||
- [local flash <image>](#local-flash-image)
|
- [local flash <image>](#local-flash-image)
|
||||||
|
- [local configure <target>](#local-configure-target)
|
||||||
|
|
||||||
- Deploy
|
- Deploy
|
||||||
|
|
||||||
@ -2161,6 +2161,36 @@ Examples:
|
|||||||
|
|
||||||
# Local
|
# Local
|
||||||
|
|
||||||
|
## local flash <image>
|
||||||
|
|
||||||
|
Flash a balenaOS image to a drive.
|
||||||
|
Image file may be one of: .img|.zip|.gz|.bz2|.xz
|
||||||
|
|
||||||
|
If --drive is not specified, then it will interactively
|
||||||
|
show a list of available drives for selection.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena local flash path/to/balenaos.img
|
||||||
|
$ balena local flash path/to/balenaos.img --drive /dev/disk2
|
||||||
|
$ balena local flash path/to/balenaos.img --drive /dev/disk2 --yes
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### IMAGE
|
||||||
|
|
||||||
|
path to OS image
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -d, --drive DRIVE
|
||||||
|
|
||||||
|
drive to flash
|
||||||
|
|
||||||
|
#### -y, --yes
|
||||||
|
|
||||||
|
answer "yes" to all questions (non interactive use)
|
||||||
|
|
||||||
## local configure <target>
|
## local configure <target>
|
||||||
|
|
||||||
Use this command to configure or reconfigure a balenaOS drive or image.
|
Use this command to configure or reconfigure a balenaOS drive or image.
|
||||||
@ -2170,26 +2200,6 @@ Examples:
|
|||||||
$ balena local configure /dev/sdc
|
$ balena local configure /dev/sdc
|
||||||
$ balena local configure path/to/image.img
|
$ balena local configure path/to/image.img
|
||||||
|
|
||||||
## local flash <image>
|
|
||||||
|
|
||||||
Use this command to flash a balenaOS image to a drive.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena local flash path/to/balenaos.img[.zip|.gz|.bz2|.xz]
|
|
||||||
$ balena local flash path/to/balenaos.img --drive /dev/disk2
|
|
||||||
$ balena local flash path/to/balenaos.img --drive /dev/disk2 --yes
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --yes, -y
|
|
||||||
|
|
||||||
confirm non-interactively
|
|
||||||
|
|
||||||
#### --drive, -d <drive>
|
|
||||||
|
|
||||||
drive
|
|
||||||
|
|
||||||
# Deploy
|
# Deploy
|
||||||
|
|
||||||
## build [source]
|
## build [source]
|
||||||
|
149
lib/actions-oclif/local/flash.ts
Normal file
149
lib/actions-oclif/local/flash.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* @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 { ExpectedError } from '../../errors';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import {
|
||||||
|
getChalk,
|
||||||
|
getCliForm,
|
||||||
|
getVisuals,
|
||||||
|
stripIndent,
|
||||||
|
} from '../../utils/lazy';
|
||||||
|
import type * as SDK from 'etcher-sdk';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
yes: boolean;
|
||||||
|
drive?: string;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LocalFlashCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Flash an image to a drive.
|
||||||
|
|
||||||
|
Flash a balenaOS image to a drive.
|
||||||
|
Image file may be one of: .img|.zip|.gz|.bz2|.xz
|
||||||
|
|
||||||
|
If --drive is not specified, then it will interactively
|
||||||
|
show a list of available drives for selection.
|
||||||
|
`;
|
||||||
|
|
||||||
|
public static examples = [
|
||||||
|
'$ balena local flash path/to/balenaos.img',
|
||||||
|
'$ balena local flash path/to/balenaos.img --drive /dev/disk2',
|
||||||
|
'$ balena local flash path/to/balenaos.img --drive /dev/disk2 --yes',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args = [
|
||||||
|
{
|
||||||
|
name: 'image',
|
||||||
|
description: 'path to OS image',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'local flash <image>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
drive: flags.string({
|
||||||
|
description: 'drive to flash',
|
||||||
|
char: 'd',
|
||||||
|
}),
|
||||||
|
yes: cf.yes,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
LocalFlashCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { sourceDestination, multiWrite } = await import('etcher-sdk');
|
||||||
|
|
||||||
|
const drive = await this.getDrive(options);
|
||||||
|
|
||||||
|
const yes =
|
||||||
|
options.yes ||
|
||||||
|
(await getCliForm().ask({
|
||||||
|
message: 'This will erase the selected drive. Are you sure?',
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'yes',
|
||||||
|
default: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!yes) {
|
||||||
|
console.log(getChalk().red.bold('Aborted image flash'));
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = new sourceDestination.File(
|
||||||
|
params.image,
|
||||||
|
sourceDestination.File.OpenFlags.Read,
|
||||||
|
);
|
||||||
|
const source = await file.getInnerSource();
|
||||||
|
|
||||||
|
const visuals = getVisuals();
|
||||||
|
const progressBars: { [key: string]: any } = {
|
||||||
|
flashing: new visuals.Progress('Flashing'),
|
||||||
|
verifying: new visuals.Progress('Validating'),
|
||||||
|
};
|
||||||
|
|
||||||
|
await multiWrite.pipeSourceToDestinations(
|
||||||
|
source,
|
||||||
|
[drive],
|
||||||
|
(_, error) => {
|
||||||
|
// onFail
|
||||||
|
console.log(getChalk().red.bold(error.message));
|
||||||
|
},
|
||||||
|
(progress: SDK.multiWrite.MultiDestinationProgress) => {
|
||||||
|
// onProgress
|
||||||
|
progressBars[progress.type].update(progress);
|
||||||
|
},
|
||||||
|
true, // verify
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDrive(options: {
|
||||||
|
drive?: string;
|
||||||
|
}): Promise<SDK.sourceDestination.BlockDevice> {
|
||||||
|
const drive = options.drive || (await getVisuals().drive('Select a drive'));
|
||||||
|
|
||||||
|
const sdk = await import('etcher-sdk');
|
||||||
|
|
||||||
|
const adapter = new sdk.scanner.adapters.BlockDeviceAdapter(() => false);
|
||||||
|
const scanner = new sdk.scanner.Scanner([adapter]);
|
||||||
|
await scanner.start();
|
||||||
|
try {
|
||||||
|
const d = scanner.getBy('device', drive);
|
||||||
|
if (
|
||||||
|
d === undefined ||
|
||||||
|
!(d instanceof sdk.sourceDestination.BlockDevice)
|
||||||
|
) {
|
||||||
|
throw new ExpectedError(`Drive not found: ${options.drive}`);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
} finally {
|
||||||
|
scanner.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017-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 type { CommandDefinition } from 'capitano';
|
|
||||||
import type * as SDK from 'etcher-sdk';
|
|
||||||
|
|
||||||
import {
|
|
||||||
getChalk,
|
|
||||||
getVisuals,
|
|
||||||
stripIndent,
|
|
||||||
getCliForm,
|
|
||||||
} from '../../utils/lazy';
|
|
||||||
import { ExpectedError } from '../../errors';
|
|
||||||
|
|
||||||
async function getDrive(options: {
|
|
||||||
drive?: string;
|
|
||||||
}): Promise<SDK.sourceDestination.BlockDevice> {
|
|
||||||
const drive = options.drive || (await getVisuals().drive('Select a drive'));
|
|
||||||
|
|
||||||
const sdk = await import('etcher-sdk');
|
|
||||||
|
|
||||||
const adapter = new sdk.scanner.adapters.BlockDeviceAdapter(() => false);
|
|
||||||
const scanner = new sdk.scanner.Scanner([adapter]);
|
|
||||||
await scanner.start();
|
|
||||||
try {
|
|
||||||
const d = scanner.getBy('device', drive);
|
|
||||||
if (d === undefined || !(d instanceof sdk.sourceDestination.BlockDevice)) {
|
|
||||||
throw new ExpectedError(`Drive not found: ${options.drive}`);
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
} finally {
|
|
||||||
scanner.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const flash: CommandDefinition<
|
|
||||||
{ image: string },
|
|
||||||
{ drive: string; yes: boolean }
|
|
||||||
> = {
|
|
||||||
signature: 'local flash <image>',
|
|
||||||
description: 'Flash an image to a drive',
|
|
||||||
help: stripIndent`
|
|
||||||
Use this command to flash a balenaOS image to a drive.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena local flash path/to/balenaos.img[.zip|.gz|.bz2|.xz]
|
|
||||||
$ balena local flash path/to/balenaos.img --drive /dev/disk2
|
|
||||||
$ balena local flash path/to/balenaos.img --drive /dev/disk2 --yes
|
|
||||||
`,
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
signature: 'yes',
|
|
||||||
boolean: true,
|
|
||||||
description: 'confirm non-interactively',
|
|
||||||
alias: 'y',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signature: 'drive',
|
|
||||||
parameter: 'drive',
|
|
||||||
description: 'drive',
|
|
||||||
alias: 'd',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
async action(params, options) {
|
|
||||||
const { sourceDestination, multiWrite } = await import('etcher-sdk');
|
|
||||||
|
|
||||||
const drive = await getDrive(options);
|
|
||||||
|
|
||||||
const yes =
|
|
||||||
options.yes ||
|
|
||||||
(await getCliForm().ask({
|
|
||||||
message: 'This will erase the selected drive. Are you sure?',
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'yes',
|
|
||||||
default: false,
|
|
||||||
}));
|
|
||||||
if (yes !== true) {
|
|
||||||
console.log(getChalk().red.bold('Aborted image flash'));
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = new sourceDestination.File(
|
|
||||||
params.image,
|
|
||||||
sourceDestination.File.OpenFlags.Read,
|
|
||||||
);
|
|
||||||
const source = await file.getInnerSource();
|
|
||||||
|
|
||||||
const visuals = getVisuals();
|
|
||||||
const progressBars: { [key: string]: any } = {
|
|
||||||
flashing: new visuals.Progress('Flashing'),
|
|
||||||
verifying: new visuals.Progress('Validating'),
|
|
||||||
};
|
|
||||||
|
|
||||||
await multiWrite.pipeSourceToDestinations(
|
|
||||||
source,
|
|
||||||
[drive],
|
|
||||||
(_, error) => {
|
|
||||||
// onFail
|
|
||||||
console.log(getChalk().red.bold(error.message));
|
|
||||||
},
|
|
||||||
(progress: SDK.multiWrite.MultiDestinationProgress) => {
|
|
||||||
// onProgress
|
|
||||||
progressBars[progress.type].update(progress);
|
|
||||||
},
|
|
||||||
true, // verify
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
@ -15,4 +15,3 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export { configure } from './configure';
|
export { configure } from './configure';
|
||||||
export { flash } from './flash';
|
|
||||||
|
@ -64,7 +64,6 @@ capitano.command(actions.preload);
|
|||||||
|
|
||||||
// ---------- Local balenaOS Module ----------
|
// ---------- Local balenaOS Module ----------
|
||||||
capitano.command(actions.local.configure);
|
capitano.command(actions.local.configure);
|
||||||
capitano.command(actions.local.flash);
|
|
||||||
|
|
||||||
// ------------ Local build and deploy -------
|
// ------------ Local build and deploy -------
|
||||||
capitano.command(actions.build);
|
capitano.command(actions.build);
|
||||||
|
@ -173,6 +173,7 @@ export const convertedCommands = [
|
|||||||
'key:add',
|
'key:add',
|
||||||
'key:rm',
|
'key:rm',
|
||||||
'leave',
|
'leave',
|
||||||
|
'local:flash',
|
||||||
'login',
|
'login',
|
||||||
'logout',
|
'logout',
|
||||||
'logs',
|
'logs',
|
||||||
|
@ -76,7 +76,7 @@ Additional commands:
|
|||||||
key rm <id> remove an SSH key from balenaCloud
|
key rm <id> remove an SSH key from balenaCloud
|
||||||
keys list the SSH keys in balenaCloud
|
keys list the SSH keys in balenaCloud
|
||||||
local configure <target> (Re)configure a balenaOS drive or image
|
local configure <target> (Re)configure a balenaOS drive or image
|
||||||
local flash <image> Flash an image to a drive
|
local flash <image> flash an image to a drive
|
||||||
logout logout from balena
|
logout logout from balena
|
||||||
note <|note> set a device note
|
note <|note> set a device note
|
||||||
os build-config <image> <device-type> build the OS config and save it to the JSON file
|
os build-config <image> <device-type> build the OS config and save it to the JSON file
|
||||||
|
Loading…
Reference in New Issue
Block a user