mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Start using Prettier
Change-Type: patch
This commit is contained in:
parent
6c988241eb
commit
83a76f7d6f
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"single-quote": true,
|
||||
"trailing-comma": "all",
|
||||
"use-tabs": true
|
||||
}
|
@ -7,28 +7,30 @@ const ROOT = path.join(__dirname, '..');
|
||||
|
||||
console.log('Building package...\n');
|
||||
|
||||
execPkg([
|
||||
'--target', 'host',
|
||||
'--output', 'build-bin/resin',
|
||||
'package.json'
|
||||
]).then(() => fs.copy(
|
||||
path.join(ROOT, 'node_modules', 'opn', 'xdg-open'),
|
||||
path.join(ROOT, 'build-bin', 'xdg-open')
|
||||
)).then(() => {
|
||||
return filehound.create()
|
||||
.paths(path.join(ROOT, 'node_modules'))
|
||||
.ext(['node', 'dll'])
|
||||
.find();
|
||||
}).then((nativeExtensions) => {
|
||||
console.log(`\nCopying to build-bin:\n${nativeExtensions.join('\n')}`);
|
||||
execPkg(['--target', 'host', '--output', 'build-bin/resin', 'package.json'])
|
||||
.then(() =>
|
||||
fs.copy(
|
||||
path.join(ROOT, 'node_modules', 'opn', 'xdg-open'),
|
||||
path.join(ROOT, 'build-bin', 'xdg-open'),
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
return filehound
|
||||
.create()
|
||||
.paths(path.join(ROOT, 'node_modules'))
|
||||
.ext(['node', 'dll'])
|
||||
.find();
|
||||
})
|
||||
.then(nativeExtensions => {
|
||||
console.log(`\nCopying to build-bin:\n${nativeExtensions.join('\n')}`);
|
||||
|
||||
return nativeExtensions.map((extPath) => {
|
||||
return fs.copy(
|
||||
extPath,
|
||||
extPath.replace(
|
||||
path.join(ROOT, 'node_modules'),
|
||||
path.join(ROOT, 'build-bin')
|
||||
)
|
||||
);
|
||||
return nativeExtensions.map(extPath => {
|
||||
return fs.copy(
|
||||
extPath,
|
||||
extPath.replace(
|
||||
path.join(ROOT, 'node_modules'),
|
||||
path.join(ROOT, 'build-bin'),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,13 +4,13 @@ import * as path from 'path';
|
||||
import * as markdown from './markdown';
|
||||
import { Document, Category } from './doc-types';
|
||||
|
||||
const result = <Document> {};
|
||||
const result = <Document>{};
|
||||
result.title = capitanodoc.title;
|
||||
result.introduction = capitanodoc.introduction;
|
||||
result.categories = [];
|
||||
|
||||
for (let commandCategory of capitanodoc.categories) {
|
||||
const category = <Category> {};
|
||||
const category = <Category>{};
|
||||
category.title = commandCategory.title;
|
||||
category.commands = [];
|
||||
|
||||
|
@ -10,7 +10,9 @@ export function renderCommand(command: Command) {
|
||||
result += '\n### Options';
|
||||
|
||||
for (let option of command.options!) {
|
||||
result += `\n\n#### ${utils.parseSignature(option)}\n\n${option.description}`;
|
||||
result += `\n\n#### ${utils.parseSignature(option)}\n\n${
|
||||
option.description
|
||||
}`;
|
||||
}
|
||||
|
||||
result += '\n';
|
||||
@ -30,27 +32,31 @@ export function renderCategory(category: Category) {
|
||||
}
|
||||
|
||||
function getAnchor(command: Command) {
|
||||
return '#' + command.signature
|
||||
.replace(/\s/g,'-')
|
||||
.replace(/</g, '60-')
|
||||
.replace(/>/g, '-62-')
|
||||
.replace(/\[/g, '')
|
||||
.replace(/\]/g, '-')
|
||||
.replace(/--/g, '-')
|
||||
.replace(/\.\.\./g, '')
|
||||
.replace(/\|/g, '')
|
||||
.toLowerCase();
|
||||
return (
|
||||
'#' +
|
||||
command.signature
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/</g, '60-')
|
||||
.replace(/>/g, '-62-')
|
||||
.replace(/\[/g, '')
|
||||
.replace(/\]/g, '-')
|
||||
.replace(/--/g, '-')
|
||||
.replace(/\.\.\./g, '')
|
||||
.replace(/\|/g, '')
|
||||
.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
export function renderToc(categories: Category[]) {
|
||||
let result = `# Table of contents\n`;
|
||||
|
||||
for (let category of categories) {
|
||||
|
||||
result += `\n- ${category.title}\n\n`;
|
||||
|
||||
for (let command of category.commands) {
|
||||
result += `\t- [${ent.encode(command.signature)}](${getAnchor(command)})\n`;
|
||||
result += `\t- [${ent.encode(command.signature)}](${getAnchor(
|
||||
command,
|
||||
)})\n`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +64,9 @@ export function renderToc(categories: Category[]) {
|
||||
}
|
||||
|
||||
export function render(doc: Document) {
|
||||
let result = `# ${doc.title}\n\n${doc.introduction}\n\n${renderToc(doc.categories)}`;
|
||||
let result = `# ${doc.title}\n\n${doc.introduction}\n\n${renderToc(
|
||||
doc.categories,
|
||||
)}`;
|
||||
|
||||
for (let category of doc.categories) {
|
||||
result += `\n${renderCategory(category)}`;
|
||||
|
5
automation/custom-types.d.ts
vendored
5
automation/custom-types.d.ts
vendored
@ -29,7 +29,10 @@ declare module 'publish-release' {
|
||||
html_url: string;
|
||||
}
|
||||
|
||||
let publishRelease: (args: PublishOptions, callback: (e: Error, release: Release) => void) => void;
|
||||
let publishRelease: (
|
||||
args: PublishOptions,
|
||||
callback: (e: Error, release: Release) => void,
|
||||
) => void;
|
||||
|
||||
export = publishRelease;
|
||||
}
|
||||
|
@ -14,43 +14,54 @@ const { GITHUB_TOKEN } = process.env;
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
|
||||
const version = 'v' + packageJSON.version;
|
||||
const outputFile = path.join(ROOT, 'build-zip', `resin-cli-${version}-${os.platform()}-${os.arch()}.zip`);
|
||||
const outputFile = path.join(
|
||||
ROOT,
|
||||
'build-zip',
|
||||
`resin-cli-${version}-${os.platform()}-${os.arch()}.zip`,
|
||||
);
|
||||
|
||||
mkdirpAsync(path.dirname(outputFile)).then(() => new Promise((resolve, reject) => {
|
||||
console.log('Zipping build...');
|
||||
mkdirpAsync(path.dirname(outputFile))
|
||||
.then(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
console.log('Zipping build...');
|
||||
|
||||
let archive = archiver('zip', {
|
||||
zlib: { level: 7 },
|
||||
let archive = archiver('zip', {
|
||||
zlib: { level: 7 },
|
||||
});
|
||||
archive.directory(path.join(ROOT, 'build-bin'), 'resin-cli');
|
||||
|
||||
let outputStream = fs.createWriteStream(outputFile);
|
||||
|
||||
outputStream.on('close', resolve);
|
||||
outputStream.on('error', reject);
|
||||
|
||||
archive.on('error', reject);
|
||||
archive.on('warning', console.warn);
|
||||
|
||||
archive.pipe(outputStream);
|
||||
archive.finalize();
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
console.log('Build zipped');
|
||||
console.log('Publishing build...');
|
||||
|
||||
return publishReleaseAsync({
|
||||
token: <string>GITHUB_TOKEN,
|
||||
owner: 'resin-io',
|
||||
repo: 'resin-cli',
|
||||
tag: version,
|
||||
name: `Resin-CLI ${version}`,
|
||||
reuseRelease: true,
|
||||
assets: [outputFile],
|
||||
});
|
||||
})
|
||||
.then(release => {
|
||||
console.log(`Release ${version} successful: ${release.html_url}`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Release failed');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
archive.directory(path.join(ROOT, 'build-bin'), 'resin-cli');
|
||||
|
||||
let outputStream = fs.createWriteStream(outputFile);
|
||||
|
||||
outputStream.on('close', resolve);
|
||||
outputStream.on('error', reject);
|
||||
|
||||
archive.on('error', reject);
|
||||
archive.on('warning', console.warn);
|
||||
|
||||
archive.pipe(outputStream);
|
||||
archive.finalize();
|
||||
})).then(() => {
|
||||
console.log('Build zipped');
|
||||
console.log('Publishing build...');
|
||||
|
||||
return publishReleaseAsync({
|
||||
token: <string> GITHUB_TOKEN,
|
||||
owner: 'resin-io',
|
||||
repo: 'resin-cli',
|
||||
tag: version,
|
||||
name: `Resin-CLI ${version}`,
|
||||
reuseRelease: true,
|
||||
assets: [outputFile],
|
||||
});
|
||||
}).then((release) => {
|
||||
console.log(`Release ${version} successful: ${release.html_url}`);
|
||||
}).catch((err) => {
|
||||
console.error('Release failed');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
@ -30,7 +30,8 @@ Examples:
|
||||
const resin = (await import('resin-sdk')).fromSharedOptions();
|
||||
const prettyjson = await import('prettyjson');
|
||||
|
||||
return resin.settings.getAll()
|
||||
return resin.settings
|
||||
.getAll()
|
||||
.then(prettyjson.render)
|
||||
.then(console.log)
|
||||
.nodeify(done);
|
||||
|
@ -1 +1,2 @@
|
||||
export const sentryDsn = 'https://56d2a46124614b01b0f4086897e96110:6e175465accc41b595a96947155f61fb@sentry.io/149239';
|
||||
export const sentryDsn =
|
||||
'https://56d2a46124614b01b0f4086897e96110:6e175465accc41b595a96947155f61fb@sentry.io/149239';
|
||||
|
@ -19,11 +19,16 @@ import patterns = require('./utils/patterns');
|
||||
import Raven = require('raven');
|
||||
import Promise = require('bluebird');
|
||||
|
||||
const captureException = Promise.promisify<string, Error>(Raven.captureException, { context: Raven });
|
||||
const captureException = Promise.promisify<string, Error>(
|
||||
Raven.captureException,
|
||||
{ context: Raven },
|
||||
);
|
||||
|
||||
exports.handle = function(error: any) {
|
||||
let message = errors.interpret(error);
|
||||
if ((message == null)) { return; }
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.DEBUG) {
|
||||
message = error.stack;
|
||||
@ -32,8 +37,9 @@ exports.handle = function(error: any) {
|
||||
patterns.printErrorMessage(message);
|
||||
|
||||
return captureException(error)
|
||||
.timeout(1000)
|
||||
.catch(function() {
|
||||
// Ignore any errors (from error logging, or timeouts)
|
||||
}).finally(() => process.exit(error.exitCode || 1));
|
||||
.timeout(1000)
|
||||
.catch(function() {
|
||||
// Ignore any errors (from error logging, or timeouts)
|
||||
})
|
||||
.finally(() => process.exit(error.exitCode || 1));
|
||||
};
|
||||
|
@ -9,34 +9,40 @@ import packageJSON = require('../package.json');
|
||||
|
||||
const resin = ResinSdk.fromSharedOptions();
|
||||
const getMatchCommandAsync = Promise.promisify(Capitano.state.getMatchCommand);
|
||||
const getMixpanel = _.memoize<any>(() => resin.models.config.getAll().get('mixpanelToken').then(Mixpanel.init));
|
||||
const getMixpanel = _.memoize<any>(() =>
|
||||
resin.models.config
|
||||
.getAll()
|
||||
.get('mixpanelToken')
|
||||
.then(Mixpanel.init),
|
||||
);
|
||||
|
||||
export function trackCommand(capitanoCli: Capitano.Cli) {
|
||||
return Promise.props({
|
||||
resinUrl: resin.settings.get('resinUrl'),
|
||||
username: resin.auth.whoami().catchReturn(undefined),
|
||||
mixpanel: getMixpanel(),
|
||||
}).then(({ username, resinUrl, mixpanel }) => {
|
||||
return getMatchCommandAsync(capitanoCli.command).then((command) => {
|
||||
Raven.mergeContext({
|
||||
user: {
|
||||
id: username,
|
||||
username,
|
||||
},
|
||||
});
|
||||
|
||||
return mixpanel.track(`[CLI] ${command.signature.toString()}`, {
|
||||
distinct_id: username,
|
||||
argv: process.argv.join(' '),
|
||||
version: packageJSON.version,
|
||||
node: process.version,
|
||||
arch: process.arch,
|
||||
resinUrl,
|
||||
platform: process.platform,
|
||||
command: capitanoCli,
|
||||
});
|
||||
});
|
||||
})
|
||||
.timeout(100)
|
||||
.catchReturn(undefined);
|
||||
.then(({ username, resinUrl, mixpanel }) => {
|
||||
return getMatchCommandAsync(capitanoCli.command).then(command => {
|
||||
Raven.mergeContext({
|
||||
user: {
|
||||
id: username,
|
||||
username,
|
||||
},
|
||||
});
|
||||
|
||||
return mixpanel.track(`[CLI] ${command.signature.toString()}`, {
|
||||
distinct_id: username,
|
||||
argv: process.argv.join(' '),
|
||||
version: packageJSON.version,
|
||||
node: process.version,
|
||||
arch: process.arch,
|
||||
resinUrl,
|
||||
platform: process.platform,
|
||||
command: capitanoCli,
|
||||
});
|
||||
});
|
||||
})
|
||||
.timeout(100)
|
||||
.catchReturn(undefined);
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ import deviceConfig = require('resin-device-config');
|
||||
|
||||
const resin = ResinSdk.fromSharedOptions();
|
||||
|
||||
export function generateBaseConfig(application: ResinSdk.Application, options: {}) {
|
||||
export function generateBaseConfig(
|
||||
application: ResinSdk.Application,
|
||||
options: {},
|
||||
) {
|
||||
options = _.mapValues(options, function(value, key) {
|
||||
if (key === 'appUpdatePollInterval') {
|
||||
return value * 60 * 1000;
|
||||
@ -37,30 +40,37 @@ export function generateBaseConfig(application: ResinSdk.Application, options: {
|
||||
registryUrl: resin.settings.get('registryUrl'),
|
||||
deltaUrl: resin.settings.get('deltaUrl'),
|
||||
apiConfig: resin.models.config.getAll(),
|
||||
}).then((results) => {
|
||||
return deviceConfig.generate({
|
||||
application,
|
||||
user: {
|
||||
id: results.userId,
|
||||
username: results.username,
|
||||
}).then(results => {
|
||||
return deviceConfig.generate(
|
||||
{
|
||||
application,
|
||||
user: {
|
||||
id: results.userId,
|
||||
username: results.username,
|
||||
},
|
||||
endpoints: {
|
||||
api: results.apiUrl,
|
||||
vpn: results.vpnUrl,
|
||||
registry: results.registryUrl,
|
||||
delta: results.deltaUrl,
|
||||
},
|
||||
pubnub: results.apiConfig.pubnub,
|
||||
mixpanel: {
|
||||
token: results.apiConfig.mixpanelToken,
|
||||
},
|
||||
},
|
||||
endpoints: {
|
||||
api: results.apiUrl,
|
||||
vpn: results.vpnUrl,
|
||||
registry: results.registryUrl,
|
||||
delta: results.deltaUrl,
|
||||
},
|
||||
pubnub: results.apiConfig.pubnub,
|
||||
mixpanel: {
|
||||
token: results.apiConfig.mixpanelToken,
|
||||
},
|
||||
}, options);
|
||||
options,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function generateApplicationConfig(application: ResinSdk.Application, options: {}) {
|
||||
return generateBaseConfig(application, options)
|
||||
.tap(config => addApplicationKey(config, application.id));
|
||||
export function generateApplicationConfig(
|
||||
application: ResinSdk.Application,
|
||||
options: {},
|
||||
) {
|
||||
return generateBaseConfig(application, options).tap(config =>
|
||||
addApplicationKey(config, application.id),
|
||||
);
|
||||
}
|
||||
|
||||
export function generateDeviceConfig(
|
||||
@ -68,41 +78,43 @@ export function generateDeviceConfig(
|
||||
deviceApiKey: string | null,
|
||||
options: {},
|
||||
) {
|
||||
return resin.models.application.get(device.application_name)
|
||||
.then(application => {
|
||||
return generateBaseConfig(application, options)
|
||||
.tap((config) => {
|
||||
// Device API keys are only safe for ResinOS 2.0.3+. We could somehow obtain
|
||||
// the expected version for this config and generate one when we know it's safe,
|
||||
// but instead for now we fall back to app keys unless the user has explicitly opted in.
|
||||
if (deviceApiKey) {
|
||||
return addDeviceKey(config, device.uuid, deviceApiKey);
|
||||
} else {
|
||||
return addApplicationKey(config, application.id);
|
||||
}
|
||||
});
|
||||
}).then((config) => {
|
||||
// Associate a device, to prevent the supervisor
|
||||
// from creating another one on its own.
|
||||
config.registered_at = Math.floor(Date.now() / 1000);
|
||||
config.deviceId = device.id;
|
||||
config.uuid = device.uuid;
|
||||
return resin.models.application
|
||||
.get(device.application_name)
|
||||
.then(application => {
|
||||
return generateBaseConfig(application, options).tap(config => {
|
||||
// Device API keys are only safe for ResinOS 2.0.3+. We could somehow obtain
|
||||
// the expected version for this config and generate one when we know it's safe,
|
||||
// but instead for now we fall back to app keys unless the user has explicitly opted in.
|
||||
if (deviceApiKey) {
|
||||
return addDeviceKey(config, device.uuid, deviceApiKey);
|
||||
} else {
|
||||
return addApplicationKey(config, application.id);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(config => {
|
||||
// Associate a device, to prevent the supervisor
|
||||
// from creating another one on its own.
|
||||
config.registered_at = Math.floor(Date.now() / 1000);
|
||||
config.deviceId = device.id;
|
||||
config.uuid = device.uuid;
|
||||
|
||||
return config;
|
||||
});
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
function addApplicationKey(config: any, applicationNameOrId: string | number) {
|
||||
return resin.models.application.generateApiKey(applicationNameOrId)
|
||||
.tap((apiKey) => {
|
||||
config.apiKey = apiKey;
|
||||
});
|
||||
return resin.models.application
|
||||
.generateApiKey(applicationNameOrId)
|
||||
.tap(apiKey => {
|
||||
config.apiKey = apiKey;
|
||||
});
|
||||
}
|
||||
|
||||
function addDeviceKey(config: any, uuid: string, customDeviceApiKey: string) {
|
||||
return Promise.try(() => {
|
||||
return customDeviceApiKey || resin.models.device.generateDeviceKey(uuid);
|
||||
}).tap((deviceApiKey) => {
|
||||
}).tap(deviceApiKey => {
|
||||
config.deviceApiKey = deviceApiKey;
|
||||
});
|
||||
}
|
||||
|
@ -32,25 +32,31 @@ const presidentExecuteAsync = Promise.promisify(execute);
|
||||
|
||||
const resin = ResinSdk.fromSharedOptions();
|
||||
|
||||
export function getGroupDefaults(
|
||||
group: { options: { name: string, default?: string }[] },
|
||||
): { [name: string]: string | undefined } {
|
||||
export function getGroupDefaults(group: {
|
||||
options: { name: string; default?: string }[];
|
||||
}): { [name: string]: string | undefined } {
|
||||
return _.chain(group)
|
||||
.get('options')
|
||||
.map((question) => [ question.name, question.default ])
|
||||
.map(question => [question.name, question.default])
|
||||
.fromPairs()
|
||||
.value();
|
||||
}
|
||||
|
||||
export function stateToString(state: OperationState) {
|
||||
const percentage = _.padStart(`${state.percentage}`, 3, '0');
|
||||
const result = `${chalk.blue(percentage + '%')} ${chalk.cyan(state.operation.command)}`;
|
||||
const result = `${chalk.blue(percentage + '%')} ${chalk.cyan(
|
||||
state.operation.command,
|
||||
)}`;
|
||||
|
||||
switch (state.operation.command) {
|
||||
case 'copy':
|
||||
return `${result} ${state.operation.from.path} -> ${state.operation.to.path}`;
|
||||
return `${result} ${state.operation.from.path} -> ${
|
||||
state.operation.to.path
|
||||
}`;
|
||||
case 'replace':
|
||||
return `${result} ${state.operation.file.path}, ${state.operation.copy} -> ${state.operation.replace}`;
|
||||
return `${result} ${state.operation.file.path}, ${
|
||||
state.operation.copy
|
||||
} -> ${state.operation.replace}`;
|
||||
case 'run-script':
|
||||
return `${result} ${state.operation.script}`;
|
||||
default:
|
||||
@ -68,20 +74,24 @@ export function sudo(command: string[]) {
|
||||
return presidentExecuteAsync(command);
|
||||
}
|
||||
|
||||
export function getManifest(image: string, deviceType: string): Promise<ResinSdk.DeviceType> {
|
||||
export function getManifest(
|
||||
image: string,
|
||||
deviceType: string,
|
||||
): Promise<ResinSdk.DeviceType> {
|
||||
// Attempt to read manifest from the first
|
||||
// partition, but fallback to the API if
|
||||
// we encounter any errors along the way.
|
||||
return imagefs.read({
|
||||
image,
|
||||
partition: {
|
||||
primary: 1,
|
||||
},
|
||||
path: '/device-type.json',
|
||||
})
|
||||
.then(extractStreamAsync)
|
||||
.then(JSON.parse)
|
||||
.catch(() => resin.models.device.getManifestBySlug(deviceType));
|
||||
return imagefs
|
||||
.read({
|
||||
image,
|
||||
partition: {
|
||||
primary: 1,
|
||||
},
|
||||
path: '/device-type.json',
|
||||
})
|
||||
.then(extractStreamAsync)
|
||||
.then(JSON.parse)
|
||||
.catch(() => resin.models.device.getManifestBySlug(deviceType));
|
||||
}
|
||||
|
||||
export function osProgressHandler(step: InitializeEmitter) {
|
||||
@ -89,7 +99,9 @@ export function osProgressHandler(step: InitializeEmitter) {
|
||||
step.on('stderr', process.stderr.write.bind(process.stderr));
|
||||
|
||||
step.on('state', function(state) {
|
||||
if (state.operation.command === 'burn') { return; }
|
||||
if (state.operation.command === 'burn') {
|
||||
return;
|
||||
}
|
||||
console.log(exports.stateToString(state));
|
||||
});
|
||||
|
||||
@ -103,11 +115,13 @@ export function osProgressHandler(step: InitializeEmitter) {
|
||||
return waitStreamAsync(step);
|
||||
}
|
||||
|
||||
export function getArchAndDeviceType(applicationName: string): Promise<{ arch: string, device_type: string }> {
|
||||
export function getArchAndDeviceType(
|
||||
applicationName: string,
|
||||
): Promise<{ arch: string; device_type: string }> {
|
||||
return Promise.join(
|
||||
getApplication(applicationName),
|
||||
resin.models.config.getDeviceTypes(),
|
||||
function (app, deviceTypes) {
|
||||
function(app, deviceTypes) {
|
||||
const config = _.find(deviceTypes, { slug: app.device_type });
|
||||
|
||||
if (!config) {
|
||||
@ -139,12 +153,12 @@ export function getSubShellCommand(command: string) {
|
||||
if (os.platform() === 'win32') {
|
||||
return {
|
||||
program: 'cmd.exe',
|
||||
args: [ '/s', '/c', command ],
|
||||
args: ['/s', '/c', command],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
program: '/bin/sh',
|
||||
args: [ '-c', command ],
|
||||
args: ['-c', command],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -26,36 +26,49 @@ import messages = require('./messages');
|
||||
const resin = ResinSdk.fromSharedOptions();
|
||||
|
||||
export function authenticate(options: {}): Promise<void> {
|
||||
return form.run([{
|
||||
message: 'Email:',
|
||||
name: 'email',
|
||||
type: 'input',
|
||||
validate: validation.validateEmail,
|
||||
}, {
|
||||
message: 'Password:',
|
||||
name: 'password',
|
||||
type: 'password',
|
||||
}], { override: options })
|
||||
.then(resin.auth.login)
|
||||
.then(resin.auth.twoFactor.isPassed)
|
||||
.then((isTwoFactorAuthPassed: boolean) => {
|
||||
if (isTwoFactorAuthPassed) { return; }
|
||||
return form
|
||||
.run(
|
||||
[
|
||||
{
|
||||
message: 'Email:',
|
||||
name: 'email',
|
||||
type: 'input',
|
||||
validate: validation.validateEmail,
|
||||
},
|
||||
{
|
||||
message: 'Password:',
|
||||
name: 'password',
|
||||
type: 'password',
|
||||
},
|
||||
],
|
||||
{ override: options },
|
||||
)
|
||||
.then(resin.auth.login)
|
||||
.then(resin.auth.twoFactor.isPassed)
|
||||
.then((isTwoFactorAuthPassed: boolean) => {
|
||||
if (isTwoFactorAuthPassed) {
|
||||
return;
|
||||
}
|
||||
|
||||
return form.ask({
|
||||
message: 'Two factor auth challenge:',
|
||||
name: 'code',
|
||||
type: 'input',
|
||||
})
|
||||
.then(resin.auth.twoFactor.challenge)
|
||||
.catch((error: any) => {
|
||||
return resin.auth.logout().then(() => {
|
||||
if ((error.name === 'ResinRequestError') && (error.statusCode === 401)) {
|
||||
throw new Error('Invalid two factor authentication code');
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
return form
|
||||
.ask({
|
||||
message: 'Two factor auth challenge:',
|
||||
name: 'code',
|
||||
type: 'input',
|
||||
})
|
||||
.then(resin.auth.twoFactor.challenge)
|
||||
.catch((error: any) => {
|
||||
return resin.auth.logout().then(() => {
|
||||
if (
|
||||
error.name === 'ResinRequestError' &&
|
||||
error.statusCode === 401
|
||||
) {
|
||||
throw new Error('Invalid two factor authentication code');
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function askLoginType() {
|
||||
@ -63,25 +76,29 @@ export function askLoginType() {
|
||||
message: 'How would you like to login?',
|
||||
name: 'loginType',
|
||||
type: 'list',
|
||||
choices: [{
|
||||
name: 'Web authorization (recommended)',
|
||||
value: 'web',
|
||||
}, {
|
||||
name: 'Credentials',
|
||||
value: 'credentials',
|
||||
}, {
|
||||
name: 'Authentication token',
|
||||
value: 'token',
|
||||
}, {
|
||||
name: 'I don\'t have a Resin account!',
|
||||
value: 'register',
|
||||
}],
|
||||
choices: [
|
||||
{
|
||||
name: 'Web authorization (recommended)',
|
||||
value: 'web',
|
||||
},
|
||||
{
|
||||
name: 'Credentials',
|
||||
value: 'credentials',
|
||||
},
|
||||
{
|
||||
name: 'Authentication token',
|
||||
value: 'token',
|
||||
},
|
||||
{
|
||||
name: "I don't have a Resin account!",
|
||||
value: 'register',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export function selectDeviceType() {
|
||||
return resin.models.device.getSupportedDeviceTypes()
|
||||
.then(deviceTypes => {
|
||||
return resin.models.device.getSupportedDeviceTypes().then(deviceTypes => {
|
||||
return form.ask({
|
||||
message: 'Device Type',
|
||||
type: 'list',
|
||||
@ -90,10 +107,16 @@ export function selectDeviceType() {
|
||||
});
|
||||
}
|
||||
|
||||
export function confirm(yesOption: string, message: string, yesMessage: string) {
|
||||
return Promise.try(function () {
|
||||
export function confirm(
|
||||
yesOption: string,
|
||||
message: string,
|
||||
yesMessage: string,
|
||||
) {
|
||||
return Promise.try(function() {
|
||||
if (yesOption) {
|
||||
if (yesMessage) { console.log(yesMessage); }
|
||||
if (yesMessage) {
|
||||
console.log(yesMessage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -109,73 +132,79 @@ export function confirm(yesOption: string, message: string, yesMessage: string)
|
||||
});
|
||||
}
|
||||
|
||||
export function selectApplication(filter: (app: ResinSdk.Application) => boolean) {
|
||||
resin.models.application.hasAny().then(function(hasAnyApplications) {
|
||||
if (!hasAnyApplications) {
|
||||
throw new Error('You don\'t have any applications');
|
||||
}
|
||||
|
||||
return resin.models.application.getAll();
|
||||
})
|
||||
.filter(filter || _.constant(true))
|
||||
.then(applications => {
|
||||
return form.ask({
|
||||
message: 'Select an application',
|
||||
type: 'list',
|
||||
choices: _.map(applications, application =>
|
||||
({
|
||||
name: `${application.app_name} (${application.device_type})`,
|
||||
value: application.app_name,
|
||||
}),
|
||||
)});
|
||||
});
|
||||
}
|
||||
|
||||
export function selectOrCreateApplication() {
|
||||
return resin.models.application.hasAny().then((hasAnyApplications) => {
|
||||
if (!hasAnyApplications) return;
|
||||
|
||||
return resin.models.application.getAll().then((applications) => {
|
||||
const appOptions = _.map<
|
||||
ResinSdk.Application,
|
||||
{ name: string, value: string | null }
|
||||
>(applications, application => ({
|
||||
name: `${application.app_name} (${application.device_type})`,
|
||||
value: application.app_name,
|
||||
}));
|
||||
|
||||
appOptions.unshift({
|
||||
name: 'Create a new application',
|
||||
value: null,
|
||||
});
|
||||
export function selectApplication(
|
||||
filter: (app: ResinSdk.Application) => boolean,
|
||||
) {
|
||||
resin.models.application
|
||||
.hasAny()
|
||||
.then(function(hasAnyApplications) {
|
||||
if (!hasAnyApplications) {
|
||||
throw new Error("You don't have any applications");
|
||||
}
|
||||
|
||||
return resin.models.application.getAll();
|
||||
})
|
||||
.filter(filter || _.constant(true))
|
||||
.then(applications => {
|
||||
return form.ask({
|
||||
message: 'Select an application',
|
||||
type: 'list',
|
||||
choices: appOptions,
|
||||
choices: _.map(applications, application => ({
|
||||
name: `${application.app_name} (${application.device_type})`,
|
||||
value: application.app_name,
|
||||
})),
|
||||
});
|
||||
});
|
||||
}).then((application) => {
|
||||
if (application) {
|
||||
return application;
|
||||
}
|
||||
}
|
||||
|
||||
return form.ask({
|
||||
message: 'Choose a Name for your new application',
|
||||
type: 'input',
|
||||
validate: validation.validateApplicationName,
|
||||
export function selectOrCreateApplication() {
|
||||
return resin.models.application
|
||||
.hasAny()
|
||||
.then(hasAnyApplications => {
|
||||
if (!hasAnyApplications) return;
|
||||
|
||||
return resin.models.application.getAll().then(applications => {
|
||||
const appOptions = _.map<
|
||||
ResinSdk.Application,
|
||||
{ name: string; value: string | null }
|
||||
>(applications, application => ({
|
||||
name: `${application.app_name} (${application.device_type})`,
|
||||
value: application.app_name,
|
||||
}));
|
||||
|
||||
appOptions.unshift({
|
||||
name: 'Create a new application',
|
||||
value: null,
|
||||
});
|
||||
|
||||
return form.ask({
|
||||
message: 'Select an application',
|
||||
type: 'list',
|
||||
choices: appOptions,
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(application => {
|
||||
if (application) {
|
||||
return application;
|
||||
}
|
||||
|
||||
return form.ask({
|
||||
message: 'Choose a Name for your new application',
|
||||
type: 'input',
|
||||
validate: validation.validateApplicationName,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function awaitDevice(uuid: string) {
|
||||
return resin.models.device.getName(uuid)
|
||||
.then((deviceName) => {
|
||||
const spinner = new visuals.Spinner(`Waiting for ${deviceName} to come online`);
|
||||
return resin.models.device.getName(uuid).then(deviceName => {
|
||||
const spinner = new visuals.Spinner(
|
||||
`Waiting for ${deviceName} to come online`,
|
||||
);
|
||||
|
||||
const poll = (): Promise<void> => {
|
||||
return resin.models.device.isOnline(uuid)
|
||||
.then(function(isOnline) {
|
||||
return resin.models.device.isOnline(uuid).then(function(isOnline) {
|
||||
if (isOnline) {
|
||||
spinner.stop();
|
||||
console.info(`The device **${deviceName}** is online!`);
|
||||
@ -196,27 +225,28 @@ export function awaitDevice(uuid: string) {
|
||||
}
|
||||
|
||||
export function inferOrSelectDevice(preferredUuid: string) {
|
||||
return resin.models.device.getAll()
|
||||
.filter<ResinSdk.Device>((device) => device.is_online)
|
||||
.then((onlineDevices) => {
|
||||
if (_.isEmpty(onlineDevices)) {
|
||||
throw new Error('You don\'t have any devices online');
|
||||
}
|
||||
return resin.models.device
|
||||
.getAll()
|
||||
.filter<ResinSdk.Device>(device => device.is_online)
|
||||
.then(onlineDevices => {
|
||||
if (_.isEmpty(onlineDevices)) {
|
||||
throw new Error("You don't have any devices online");
|
||||
}
|
||||
|
||||
const defaultUuid = _.map(onlineDevices, 'uuid').includes(preferredUuid) ?
|
||||
preferredUuid :
|
||||
onlineDevices[0].uuid;
|
||||
const defaultUuid = _.map(onlineDevices, 'uuid').includes(preferredUuid)
|
||||
? preferredUuid
|
||||
: onlineDevices[0].uuid;
|
||||
|
||||
return form.ask({
|
||||
message: 'Select a device',
|
||||
type: 'list',
|
||||
default: defaultUuid,
|
||||
choices: _.map(onlineDevices, device => ({
|
||||
name: `${device.name || 'Untitled'} (${device.uuid.slice(0, 7)})`,
|
||||
value: device.uuid,
|
||||
}),
|
||||
)});
|
||||
});
|
||||
return form.ask({
|
||||
message: 'Select a device',
|
||||
type: 'list',
|
||||
default: defaultUuid,
|
||||
choices: _.map(onlineDevices, device => ({
|
||||
name: `${device.name || 'Untitled'} (${device.uuid.slice(0, 7)})`,
|
||||
value: device.uuid,
|
||||
})),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function printErrorMessage(message: string) {
|
||||
|
@ -20,14 +20,17 @@ import capitano = require('capitano');
|
||||
import patterns = require('./patterns');
|
||||
|
||||
export function register(regex: RegExp): Promise<void> {
|
||||
return nplugm.list(regex).map(async function(plugin: any) {
|
||||
const command = await import(plugin);
|
||||
command.plugin = true;
|
||||
if (!_.isArray(command)) {
|
||||
return capitano.command(command);
|
||||
}
|
||||
return _.each(command, capitano.command);
|
||||
}).catch((error: Error) => {
|
||||
return patterns.printErrorMessage(error.message);
|
||||
});
|
||||
return nplugm
|
||||
.list(regex)
|
||||
.map(async function(plugin: any) {
|
||||
const command = await import(plugin);
|
||||
command.plugin = true;
|
||||
if (!_.isArray(command)) {
|
||||
return capitano.command(command);
|
||||
}
|
||||
return _.each(command, capitano.command);
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
return patterns.printErrorMessage(error.message);
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
export async function buffer(stream: NodeJS.ReadableStream, bufferFile: string) {
|
||||
export async function buffer(
|
||||
stream: NodeJS.ReadableStream,
|
||||
bufferFile: string,
|
||||
) {
|
||||
const Promise = await import('bluebird');
|
||||
const fs = await import('fs');
|
||||
|
||||
@ -6,14 +9,15 @@ export async function buffer(stream: NodeJS.ReadableStream, bufferFile: string)
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
stream
|
||||
.on('error', reject)
|
||||
.on('end', resolve)
|
||||
.pipe(fileWriteStream);
|
||||
}).then(() => new Promise(function(resolve, reject) {
|
||||
const stream = fs.createReadStream(bufferFile);
|
||||
.on('error', reject)
|
||||
.on('end', resolve)
|
||||
.pipe(fileWriteStream);
|
||||
}).then(
|
||||
() =>
|
||||
new Promise(function(resolve, reject) {
|
||||
const stream = fs.createReadStream(bufferFile);
|
||||
|
||||
stream
|
||||
.on('open', () => resolve(stream))
|
||||
.on('error', reject);
|
||||
}));
|
||||
stream.on('open', () => resolve(stream)).on('error', reject);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ export function notify() {
|
||||
notifier.notify({ defer: false });
|
||||
|
||||
if (notifier.update != null) {
|
||||
console.log('Notice that you might need administrator privileges depending on your setup\n');
|
||||
console.log(
|
||||
'Notice that you might need administrator privileges depending on your setup\n',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
"scripts": {
|
||||
"prebuild": "rimraf build/ build-bin/ build-zip/",
|
||||
"build": "npm run build:src && npm run build:bin",
|
||||
"build:src": "npm run lint && gulp build && tsc && npm run build:doc",
|
||||
"build:src": "npm run prettify && npm run lint && gulp build && tsc && npm run build:doc",
|
||||
"build:doc": "mkdirp doc/ && ts-node automation/capitanodoc/index.ts > doc/cli.markdown",
|
||||
"build:bin": "ts-node --type-check -P automation automation/build-bin.ts",
|
||||
"release": "npm run build && ts-node --type-check -P automation automation/deploy-bin.ts",
|
||||
@ -39,6 +39,7 @@
|
||||
"test": "gulp test",
|
||||
"ci": "npm run test && catch-uncommitted",
|
||||
"watch": "gulp watch",
|
||||
"prettify": "prettier --write \"{lib,tests,automation,typings}/**/*.ts\"",
|
||||
"lint": "resin-lint lib/ tests/ && resin-lint --typescript automation/ lib/ typings/ tests/",
|
||||
"prepublish": "require-npm4-to-publish",
|
||||
"prepublishOnly": "npm run build"
|
||||
@ -71,6 +72,7 @@
|
||||
"gulp-shell": "^0.5.2",
|
||||
"mochainon": "^2.0.0",
|
||||
"pkg": "^4.3.0-beta.1",
|
||||
"prettier": "^1.9.2",
|
||||
"publish-release": "^1.3.3",
|
||||
"require-npm4-to-publish": "^1.0.0",
|
||||
"resin-lint": "^1.5.0",
|
||||
@ -147,4 +149,4 @@
|
||||
"optionalDependencies": {
|
||||
"removedrive": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
5
typings/capitano.d.ts
vendored
5
typings/capitano.d.ts
vendored
@ -48,6 +48,9 @@ declare module 'capitano' {
|
||||
export function command(command: CommandDefinition): void;
|
||||
|
||||
export const state: {
|
||||
getMatchCommand: (signature: string, callback: (e: Error, cmd: Command) => void) => void
|
||||
getMatchCommand: (
|
||||
signature: string,
|
||||
callback: (e: Error, cmd: Command) => void,
|
||||
) => void;
|
||||
};
|
||||
}
|
||||
|
5
typings/president.d.ts
vendored
5
typings/president.d.ts
vendored
@ -1,3 +1,6 @@
|
||||
declare module 'president' {
|
||||
export function execute(command: string[], callback: (err: Error) => void): void;
|
||||
export function execute(
|
||||
command: string[],
|
||||
callback: (err: Error) => void,
|
||||
): void;
|
||||
}
|
||||
|
12
typings/resin-device-init.d.ts
vendored
12
typings/resin-device-init.d.ts
vendored
@ -3,7 +3,11 @@ declare module 'resin-device-init' {
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
interface OperationState {
|
||||
operation: CopyOperation | ReplaceOperation | RunScriptOperation | BurnOperation;
|
||||
operation:
|
||||
| CopyOperation
|
||||
| ReplaceOperation
|
||||
| RunScriptOperation
|
||||
| BurnOperation;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
@ -56,5 +60,9 @@ declare module 'resin-device-init' {
|
||||
on(event: 'burn', callback: (state: BurnProgress) => void): void;
|
||||
}
|
||||
|
||||
export function initialize(image: string, deviceType: string, config: {}): Promise<InitializeEmitter>;
|
||||
export function initialize(
|
||||
image: string,
|
||||
deviceType: string,
|
||||
config: {},
|
||||
): Promise<InitializeEmitter>;
|
||||
}
|
||||
|
4
typings/update-notifier.d.ts
vendored
4
typings/update-notifier.d.ts
vendored
@ -4,7 +4,9 @@
|
||||
declare module 'update-notifier' {
|
||||
export = UpdateNotifier;
|
||||
|
||||
function UpdateNotifier(settings?: UpdateNotifier.Settings): UpdateNotifier.UpdateNotifier;
|
||||
function UpdateNotifier(
|
||||
settings?: UpdateNotifier.Settings,
|
||||
): UpdateNotifier.UpdateNotifier;
|
||||
|
||||
namespace UpdateNotifier {
|
||||
class UpdateNotifier {
|
||||
|
Loading…
Reference in New Issue
Block a user