Compare commits

...

9 Commits

Author SHA1 Message Date
b602e9c294 Add balena update command for updating the CLI
Change-type: minor
2023-07-06 13:27:16 -04:00
f621daec82 Update oclif, improve help command
Change-type: minor
2023-07-06 13:26:29 -04:00
338477463a v16.6.3 2023-06-30 17:07:34 +00:00
d1275760fa Merge pull request #2641 from balena-io/drop-toolbelt
Pin dockerode and drop docker-toolbelt
2023-06-30 20:06:46 +03:00
0f4054fa4d Remove redundant dependency on docker-toolbelt
Change-type: patch
2023-06-30 19:22:07 +03:00
7545fc5d6e Pin dockerode to v3.3.3
v3.3.4 introduces a regression that is fixed by https://github.com/apocas/dockerode/pull/695 but Dockerode has not published a version that includes the fix yet. Pin the dependency to ensure we don’t ever update to a broken version.

Change-type: patch
2023-06-30 19:19:52 +03:00
a1f25809cb v16.6.2 2023-06-29 12:27:14 +00:00
e0a3c4bd95 Merge pull request #2640 from balena-io/make-apple-notarization-team-id-public
macos notarization: Expose team ID instead of keeping it in secrets
2023-06-29 12:26:27 +00:00
d843e75512 macos notarization: Expose team ID instead of keeping it in secrets
Change-type: patch
2023-06-29 07:41:07 -04:00
15 changed files with 8548 additions and 8738 deletions

View File

@ -124,7 +124,7 @@ runs:
# Apple notarization (automation/build-bin.ts)
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }}
XCODE_APP_LOADER_TEAM_ID: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_TEAM_ID }}
XCODE_APP_LOADER_TEAM_ID: ${{ inputs.XCODE_APP_LOADER_TEAM_ID }}
- name: Upload artifacts
uses: actions/upload-artifact@v3

View File

@ -1,3 +1,39 @@
- commits:
- subject: Remove redundant dependency on docker-toolbelt
hash: 0f4054fa4ddf74a8c7ec869bef74cee43f182df1
body: ""
footer:
Change-type: patch
change-type: patch
author: Akis Kesoglou
nested: []
- subject: Pin dockerode to v3.3.3
hash: 7545fc5d6e3d2c224a6c2024678b872538e3795c
body: >
v3.3.4 introduces a regression that is fixed by
https://github.com/apocas/dockerode/pull/695 but Dockerode has not
published a version that includes the fix yet. Pin the dependency to
ensure we dont ever update to a broken version.
footer:
Change-type: patch
change-type: patch
author: Akis Kesoglou
nested: []
version: 16.6.3
title: ""
date: 2023-06-30T17:07:32.165Z
- commits:
- subject: "macos notarization: Expose team ID instead of keeping it in secrets"
hash: d843e75512ebb9a54f00207b1b17aa65dc3244fc
body: ""
footer:
Change-type: patch
change-type: patch
author: myarmolinsky
nested: []
version: 16.6.2
title: ""
date: 2023-06-29T12:27:11.915Z
- commits:
- subject: Drop `electron-notarize` dependency in favor of `@electron/notarize`
hash: 10b5af69679d04323c920d7fc08b9d691b6590b2

View File

@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
## 16.6.3 - 2023-06-30
* Remove redundant dependency on docker-toolbelt [Akis Kesoglou]
* Pin dockerode to v3.3.3 [Akis Kesoglou]
## 16.6.2 - 2023-06-29
* macos notarization: Expose team ID instead of keeping it in secrets [myarmolinsky]
## 16.6.1 - 2023-06-28
* Drop `electron-notarize` dependency in favor of `@electron/notarize` [myarmolinsky]

View File

@ -465,7 +465,7 @@ async function signWindowsInstaller() {
* Wait for Apple Installer Notarization to continue
*/
async function notarizeMacInstaller(): Promise<void> {
const teamId = process.env.XCODE_APP_LOADER_TEAM_ID;
const teamId = process.env.XCODE_APP_LOADER_TEAM_ID || '66H43P8FRG';
const appleId =
process.env.XCODE_APP_LOADER_EMAIL || 'accounts+apple@balena.io';
const appleIdPassword = process.env.XCODE_APP_LOADER_PASSWORD;

View File

@ -208,7 +208,7 @@ ${dockerignoreHelp}
* buildEmulated
* buildOpts: arguments to forward to docker build command
*
* @param {DockerToolbelt} docker
* @param {Dockerode} docker
* @param {Logger} logger
* @param {ComposeOpts} composeOpts
* @param opts

View File

@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Help from '@oclif/plugin-help';
import { Help } from '@oclif/core';
import { HelpFormatter } from '@oclif/core/lib/help/formatter';
import * as indent from 'indent-string';
import { getChalk } from './utils/lazy';
import { renderList } from '@oclif/plugin-help/lib/list';
import { ExpectedError } from './errors';
// Partially overrides standard implementation of help plugin
@ -39,9 +39,11 @@ function getHelpSubject(args: string[]): string | undefined {
}
export default class BalenaHelp extends Help {
public helpFormatter = new HelpFormatter(this.config);
public static usage: 'help [command]';
public showHelp(argv: string[]) {
public async showHelp(argv: string[]) {
const chalk = getChalk();
const subject = getHelpSubject(argv);
if (!subject) {
@ -52,7 +54,7 @@ export default class BalenaHelp extends Help {
const command = this.config.findCommand(subject);
if (command) {
this.showCommandHelp(command);
await this.showCommandHelp(command);
return;
}
@ -187,14 +189,15 @@ See: https://git.io/JRHUW#deprecation-policy`,
return '';
}
const body = renderList(
const body = this.helpFormatter.renderList(
commands
.filter((c) => c.usage != null && c.usage !== '')
.map((c) => [c.usage, this.formatDescription(c.description)]),
{
spacer: '\n',
stripAnsi: this.opts.stripAnsi,
maxWidth: this.opts.maxWidth - 2,
indentation: 2,
multiline: true,
},
);

View File

@ -20,7 +20,7 @@ import type * as BalenaSdk from 'balena-sdk';
import type { Chalk } from 'chalk';
import type * as visuals from 'resin-cli-visuals';
import type * as CliForm from 'resin-cli-form';
import type { ux } from 'cli-ux';
import type { ux } from '@oclif/core';
// Equivalent of _.once but avoiding the need to import lodash for lazy deps
const once = <T>(fn: () => T) => {
@ -57,7 +57,9 @@ export const getCliForm = once(
() => require('resin-cli-form') as typeof CliForm,
);
export const getCliUx = once(() => require('cli-ux').ux as typeof ux);
export const getCliUx = once(
() => require('@oclif/core/lib/cli-ux') as typeof ux,
);
// Directly export stripIndent as we always use it immediately, but importing just `stripIndent` reduces startup time
export const stripIndent =

View File

@ -176,7 +176,7 @@ async function selectLocalBalenaOsDevice(timeout = 4000): Promise<string> {
});
const responsiveDevices: typeof devices = [];
const Docker = await import('docker-toolbelt');
const Docker = await import('dockerode');
await Promise.all(
devices.map(async function (device) {
const address = device?.address;

16517
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "balena-cli",
"version": "16.6.1",
"version": "16.6.3",
"description": "The official balena Command Line Interface",
"main": "./build/app.js",
"homepage": "https://github.com/balena-io/balena-cli",
@ -109,7 +109,8 @@
"sign": "Developer ID Installer: Balena Ltd (66H43P8FRG)"
},
"plugins": [
"@oclif/plugin-help"
"@oclif/plugin-help",
"@oclif/plugin-update"
]
},
"devDependencies": {
@ -197,6 +198,7 @@
"@balena/dockerignore": "^1.0.2",
"@balena/es-version": "^1.0.1",
"@oclif/command": "^1.8.16",
"@oclif/plugin-update": "^3.1.15",
"@resin.io/valid-email": "^0.1.0",
"@sentry/node": "^6.16.1",
"@types/fast-levenshtein": "0.0.1",
@ -216,15 +218,13 @@
"chalk": "^3.0.0",
"chokidar": "^3.5.2",
"cli-truncate": "^2.1.0",
"cli-ux": "^5.5.1",
"color-hash": "^1.1.1",
"columnify": "^1.5.2",
"common-tags": "^1.7.2",
"denymount": "^2.3.0",
"docker-modem": "3.0.0",
"docker-progress": "^5.1.3",
"docker-toolbelt": "^3.3.10",
"dockerode": "^3.3.1",
"dockerode": "3.3.3",
"ejs": "^3.1.6",
"etcher-sdk": "^8.5.3",
"event-stream": "3.3.4",
@ -253,7 +253,7 @@
"net-keepalive": "^3.0.0",
"node-cleanup": "^2.1.2",
"node-unzip-2": "^0.2.8",
"oclif": "^1.18.4",
"oclif": "^3.9.1",
"open": "^7.1.0",
"patch-package": "^6.4.7",
"prettyjson": "^1.2.5",
@ -285,6 +285,6 @@
"windosu": "^0.3.0"
},
"versionist": {
"publishedAt": "2023-06-28T12:47:55.666Z"
"publishedAt": "2023-06-30T17:07:33.152Z"
}
}

View File

@ -0,0 +1,43 @@
diff --git a/node_modules/@oclif/core/lib/help/command.js b/node_modules/@oclif/core/lib/help/command.js
index 6de139b..b625b46 100644
--- a/node_modules/@oclif/core/lib/help/command.js
+++ b/node_modules/@oclif/core/lib/help/command.js
@@ -206,7 +206,7 @@ class CommandHelp extends formatter_1.HelpFormatter {
if (args.filter(a => a.description).length === 0)
return;
return args.map(a => {
- const name = a.name.toUpperCase();
+ const name = a.required ? `<${a.name}>` : `[${a.name}]`;
let description = a.description || '';
if (a.default)
description = `[default: ${a.default}] ${description}`;
@@ -244,9 +244,7 @@ class CommandHelp extends formatter_1.HelpFormatter {
}
if (flag.multiple)
value += '...';
- if (!value.includes('|'))
- value = underline(value);
- label += `=${value}`;
+ label += ` <${value}>`
}
return label;
}
diff --git a/node_modules/@oclif/core/lib/help/index.js b/node_modules/@oclif/core/lib/help/index.js
index f584e65..394ec36 100644
--- a/node_modules/@oclif/core/lib/help/index.js
+++ b/node_modules/@oclif/core/lib/help/index.js
@@ -132,11 +132,12 @@ class Help extends HelpBase {
}
this.log(this.formatCommand(command));
this.log('');
- if (subTopics.length > 0) {
+ const SUPPRESS_SUBTOPICS = true;
+ if (subTopics.length > 0 && !SUPPRESS_SUBTOPICS) {
this.log(this.formatTopics(subTopics));
this.log('');
}
- if (subCommands.length > 0) {
+ if (subCommands.length > 0 && !SUPPRESS_SUBTOPICS) {
const aliases = [];
const uniqueSubCommands = subCommands.filter(p => {
aliases.push(...p.aliases);

View File

@ -1,43 +0,0 @@
diff --git a/node_modules/@oclif/plugin-help/lib/command.js b/node_modules/@oclif/plugin-help/lib/command.js
index b3b9010..788e5c6 100644
--- a/node_modules/@oclif/plugin-help/lib/command.js
+++ b/node_modules/@oclif/plugin-help/lib/command.js
@@ -88,7 +88,7 @@ class CommandHelp {
return;
const body = list_1.renderList(args.map(a => {
var _a;
- const name = a.name.toUpperCase();
+ const name = a.required ? `<${a.name}>` : `[${a.name}]`;
let description = a.description || '';
// `a.default` is actually not always a string (typing bug), hence `toString()`
if (a.default || ((_a = a.default) === null || _a === void 0 ? void 0 : _a.toString()) === '0')
@@ -133,9 +133,7 @@ class CommandHelp {
if (!flag.helpValue && flag.options) {
value = flag.options.join('|');
}
- if (!value.includes('|'))
- value = underline(value);
- left += `=${value}`;
+ left += ` <${value}>`;
}
let right = flag.description || '';
// `flag.default` is not always a string (typing bug), hence `toString()`
diff --git a/node_modules/@oclif/plugin-help/lib/index.js b/node_modules/@oclif/plugin-help/lib/index.js
index 04d7861..c2fb591 100644
--- a/node_modules/@oclif/plugin-help/lib/index.js
+++ b/node_modules/@oclif/plugin-help/lib/index.js
@@ -98,11 +98,12 @@ class Help extends HelpBase {
console.log(title + '\n');
console.log(this.formatCommand(command));
console.log('');
- if (subTopics.length > 0) {
+ const SUPPRESS_SUBTOPICS = true;
+ if (subTopics.length > 0 && !SUPPRESS_SUBTOPICS) {
console.log(this.formatTopics(subTopics));
console.log('');
}
- if (subCommands.length > 0) {
+ if (subCommands.length > 0 && !SUPPRESS_SUBTOPICS) {
console.log(this.formatCommands(subCommands));
console.log('');
}

View File

@ -1,278 +0,0 @@
diff --git a/node_modules/oclif/lib/commands/pack/macos.js b/node_modules/oclif/lib/commands/pack/macos.js
index 924f092..a69e60b 100644
--- a/node_modules/oclif/lib/commands/pack/macos.js
+++ b/node_modules/oclif/lib/commands/pack/macos.js
@@ -133,6 +133,7 @@ class PackMacos extends command_1.Command {
if (process.env.OSX_KEYCHAIN)
args.push('--keychain', process.env.OSX_KEYCHAIN);
args.push(dist);
+ console.error(`[debug] oclif pkgbuild "${args.join('" "')}"`);
await qq.x('pkgbuild', args);
}
}
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
index bf4657e..fd58c7d 100644
--- a/node_modules/oclif/lib/commands/pack/win.js
+++ b/node_modules/oclif/lib/commands/pack/win.js
@@ -52,6 +52,13 @@ VIAddVersionKey /LANG=\${LANG_ENGLISH} "ProductVersion" "\${VERSION}.0"
InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
Section "${config.name} CLI \${VERSION}"
+ ; First remove any old client files.
+ ; (Remnants of old versions were causing CLI errors)
+ ; Initially tried running the Uninstall.exe, but was
+ ; unable to make script wait for completion (despite using _?)
+ DetailPrint "Removing files from previous version."
+ RMDir /r "$INSTDIR\\client"
+
SetOutPath $INSTDIR
File /r bin
File /r client
@@ -61,6 +68,8 @@ Section "${config.name} CLI \${VERSION}"
WriteUninstaller "$INSTDIR\\Uninstall.exe"
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
"DisplayName" "${config.name}"
+ WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
+ "DisplayVersion" "\${VERSION}"
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
"UninstallString" "$\\"$INSTDIR\\uninstall.exe$\\""
WriteRegStr HKLM "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${config.dirname}" \\
@@ -193,7 +202,8 @@ class PackWin extends command_1.Command {
async run() {
await this.checkForNSIS();
const { flags } = this.parse(PackWin);
- const buildConfig = await Tarballs.buildConfig(flags.root);
+ const $targets = flags.targets ? flags.targets.split(',') : undefined;
+ const buildConfig = await Tarballs.buildConfig(flags.root, { targets: $targets });
const { config, version, gitSha, targets, tmp } = buildConfig;
await Tarballs.build(buildConfig, { platform: 'win32', pack: false });
const arches = targets.filter(t => t.platform === 'win32').map(t => t.arch);
@@ -208,7 +218,8 @@ class PackWin extends command_1.Command {
// eslint-disable-next-line no-await-in-loop
await qq.mv(buildConfig.workspace({ platform: 'win32', arch }), [installerBase, 'client']);
// eslint-disable-next-line no-await-in-loop
- await qq.x(`makensis ${installerBase}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
+ const { msysExec, toMsysPath } = require("../../util");
+ await msysExec(`makensis ${toMsysPath(installerBase)}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
const templateKey = upload_util_1.templateShortKey('win32', { bin: config.bin, version: version, sha: gitSha, arch });
const o = buildConfig.dist(`win32/${templateKey}`);
// eslint-disable-next-line no-await-in-loop
@@ -255,4 +266,5 @@ PackWin.hidden = true;
PackWin.description = 'create windows installer from oclif CLI';
PackWin.flags = {
root: command_1.flags.string({ char: 'r', description: 'path to oclif CLI root', default: '.', required: true }),
+ targets: command_1.flags.string({char: 't', description: 'comma-separated targets to pack (e.g.: win32-x86,win32-x64)'}),
};
diff --git a/node_modules/oclif/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
index d3e8e89..a5d29e2 100644
--- a/node_modules/oclif/lib/tarballs/build.js
+++ b/node_modules/oclif/lib/tarballs/build.js
@@ -18,8 +18,9 @@ const pack = async (from, to) => {
qq.cd(prevCwd);
};
async function build(c, options = {}) {
- const { xz, config, version, s3Config, gitSha, nodeVersion, targets, updateConfig } = c;
+ const { xz, config, version, s3Config, gitSha, nodeVersion, targets, updateConfig, tmp } = c;
const prevCwd = qq.cwd();
+ console.error(`[debug] oclif cwd="${prevCwd}"\n c.root="${c.root}" c.workspace()="${c.workspace()}"`);
const packCLI = async () => {
const stdout = await qq.x.stdout('npm', ['pack', '--unsafe-perm'], { cwd: c.root });
return path.join(c.root, stdout.split('\n').pop());
@@ -30,11 +31,19 @@ async function build(c, options = {}) {
tarball = path.basename(tarball);
tarball = qq.join([c.workspace(), tarball]);
qq.cd(c.workspace());
- await qq.x(`tar -xzf ${tarball}`);
+ const { msysExec, toMsysPath } = require("../util");
+ await msysExec(`tar -xzf ${toMsysPath(tarball)}`);
// eslint-disable-next-line no-await-in-loop
for (const f of await qq.ls('package', { fullpath: true }))
await qq.mv(f, '.');
await qq.rm('package', tarball, 'bin/run.cmd');
+ // rename the original balena-cli ./bin/balena entry point for oclif compatibility
+ await qq.mv('bin/balena', 'bin/run');
+ // The oclif installers are a production installation, while the source
+ // `bin` folder may contain a `.fast-boot.json` file of a dev installation.
+ // This has previously led to issues preventing the CLI from starting, so
+ // delete `.fast-boot.json` (if any) from the destination folder.
+ await qq.rm('bin/.fast-boot.json');
};
const updatePJSON = async () => {
qq.cd(c.workspace());
@@ -46,21 +55,21 @@ async function build(c, options = {}) {
await qq.writeJSON('package.json', pjson);
};
const addDependencies = async () => {
- qq.cd(c.workspace());
- const yarnRoot = findYarnWorkspaceRoot(c.root) || c.root;
- const yarn = await qq.exists([yarnRoot, 'yarn.lock']);
- if (yarn) {
- await qq.cp([yarnRoot, 'yarn.lock'], '.');
- await qq.x('yarn --no-progress --production --non-interactive');
- }
- else {
- let lockpath = qq.join(c.root, 'package-lock.json');
- if (!await qq.exists(lockpath)) {
- lockpath = qq.join(c.root, 'npm-shrinkwrap.json');
- }
- await qq.cp(lockpath, '.');
- await qq.x('npm install --production');
+ const ws = c.workspace();
+ qq.cd(ws);
+ console.error(`[debug] oclif copying node_modules to "${ws}"`)
+ const source = path.join(c.root, 'node_modules');
+ if (process.platform === 'win32') {
+ // xcopy is much faster than `qq.cp(source, ws)`
+ await qq.x(`xcopy "${source}" "${ws}\\node_modules" /S /E /B /I /K /Q /Y`);
+ } else {
+ // use the shell's `cp` on macOS in order to preserve extended
+ // file attributes containing `codesign` digital signatures
+ await qq.x(`cp -pR "${source}" "${ws}"`);
}
+ console.error(`[debug] oclif running "npm prune --production" in "${ws}"`);
+ await qq.x('npm prune --production');
+ console.error(`[debug] oclif done`);
};
const pretarball = async () => {
qq.cd(c.workspace());
@@ -99,7 +108,8 @@ async function build(c, options = {}) {
output: path.join(workspace, 'bin', 'node'),
platform: target.platform,
arch: target.arch,
- tmp: qq.join(config.root, 'tmp'),
+ tmp,
+ projectRootPath: c.root,
});
if (options.pack === false)
return;
diff --git a/node_modules/oclif/lib/tarballs/config.js b/node_modules/oclif/lib/tarballs/config.js
index 0dc3cd7..1336219 100644
--- a/node_modules/oclif/lib/tarballs/config.js
+++ b/node_modules/oclif/lib/tarballs/config.js
@@ -18,7 +18,10 @@ function gitSha(cwd, options = {}) {
}
exports.gitSha = gitSha;
async function Tmp(config) {
- const tmp = path.join(config.root, 'tmp');
+ const tmp = process.env.BUILD_TMP
+ ? path.join(process.env.BUILD_TMP, 'oclif')
+ : path.join(config.root, 'tmp');
+ console.error(`[debug] oclif tmp="${tmp}"`);
await qq.mkdirp(tmp);
return tmp;
}
@@ -43,7 +46,7 @@ async function buildConfig(root, options = {}) {
s3Config: updateConfig.s3,
nodeVersion: updateConfig.node.version || process.versions.node,
workspace(target) {
- const base = qq.join(config.root, 'tmp');
+ const base = tmp;
if (target && target.platform)
return qq.join(base, [target.platform, target.arch].join('-'), upload_util_1.templateShortKey('baseDir', { bin: config.bin }));
return qq.join(base, upload_util_1.templateShortKey('baseDir', { bin: config.bin }));
diff --git a/node_modules/oclif/lib/tarballs/node.js b/node_modules/oclif/lib/tarballs/node.js
index fabe5c4..e32dd76 100644
--- a/node_modules/oclif/lib/tarballs/node.js
+++ b/node_modules/oclif/lib/tarballs/node.js
@@ -4,9 +4,10 @@ const errors_1 = require("@oclif/errors");
const path = require("path");
const qq = require("qqjs");
const log_1 = require("../log");
+const { isMSYS2, msysExec, toMsysPath } = require("../util");
async function checkFor7Zip() {
try {
- await qq.x('7z', { stdio: [0, null, 2] });
+ await msysExec('7z', { stdio: [0, null, 2] });
}
catch (error) {
if (error.code === 127)
@@ -41,7 +42,8 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
const basedir = path.dirname(tarball);
await qq.mkdirp(basedir);
await qq.download(url, tarball);
- await qq.x(`grep ${path.basename(tarball)} ${shasums} | shasum -a 256 -c -`, { cwd: basedir });
+ const shaCmd = isMSYS2 ? 'sha256sum -c -' : 'shasum -a 256 -c -';
+ await msysExec(`grep ${path.basename(tarball)} ${toMsysPath(shasums)} | ${shaCmd}`, { cwd: basedir });
};
const extract = async () => {
log_1.log(`extracting ${nodeBase}`);
@@ -51,7 +53,7 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
await qq.mkdirp(path.dirname(cache));
if (platform === 'win32') {
qq.pushd(nodeTmp);
- await qq.x(`7z x -bd -y ${tarball} > /dev/null`);
+ await msysExec(`7z x -bd -y ${toMsysPath(tarball)} > /dev/null`);
await qq.mv([nodeBase, 'node.exe'], cache);
qq.popd();
}
diff --git a/node_modules/oclif/lib/upload-util.js b/node_modules/oclif/lib/upload-util.js
index 45392cb..3c806c7 100644
--- a/node_modules/oclif/lib/upload-util.js
+++ b/node_modules/oclif/lib/upload-util.js
@@ -28,10 +28,10 @@ function templateShortKey(type, ext, options = { root: '.' }) {
const templates = {
baseDir: '<%- bin %>',
unversioned: '<%- bin %>-<%- platform %>-<%- arch %><%- ext %>',
- versioned: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %><%- ext %>',
- manifest: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %>-buildmanifest',
- macos: '<%- bin %>-v<%- version %>-<%- sha %>.pkg',
- win32: '<%- bin %>-v<%- version %>-<%- sha %>-<%- arch %>.exe',
+ versioned: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %><%- ext %>',
+ manifest: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %>-buildmanifest',
+ macos: '<%- bin %>-v<%- version %>.pkg',
+ win32: '<%- bin %>-v<%- version %>-<%- arch %>.exe',
deb: '<%- bin %>_<%- versionShaRevision %>_<%- arch %>.deb',
};
return _.template(templates[type])(Object.assign({}, options));
diff --git a/node_modules/oclif/lib/util.js b/node_modules/oclif/lib/util.js
index 17748ad..4928fc9 100644
--- a/node_modules/oclif/lib/util.js
+++ b/node_modules/oclif/lib/util.js
@@ -67,3 +67,47 @@ exports.sortVersionsObjectByKeysDesc = (input) => {
}
return result;
};
+
+// OSTYPE is 'msys' for MSYS 1.0 and for MSYS2, or 'cygwin' for Cygwin
+// but note that OSTYPE is not "exported" by default, so run: export OSTYPE=$OSTYPE
+// MSYSTEM is 'MINGW32' for MSYS 1.0, 'MSYS' for MSYS2, and undefined for Cygwin
+const isCygwin = process.env.OSTYPE === 'cygwin';
+const isMinGW = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MINGW');
+const isMSYS2 = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MSYS');
+const MSYSSHELLPATH = process.env.MSYSSHELLPATH ||
+ (isMSYS2 ? 'C:\\msys64\\usr\\bin\\bash.exe' :
+ (isMinGW ? 'C:\\MinGW\\msys\\1.0\\bin\\bash.exe' :
+ (isCygwin ? 'C:\\cygwin64\\bin\\bash.exe' : '/bin/sh')));
+
+exports.isCygwin = isCygwin;
+exports.isMinGW = isMinGW;
+exports.isMSYS2 = isMSYS2;
+console.error(`[debug] oclif MSYSSHELLPATH=${MSYSSHELLPATH} MSYSTEM=${process.env.MSYSTEM} OSTYPE=${process.env.OSTYPE} isMSYS2=${isMSYS2} isMingGW=${isMinGW} isCygwin=${isCygwin}`);
+
+const qq = require("qqjs");
+
+/* Convert a Windows path like 'C:\tmp' to a MSYS path like '/c/tmp' */
+function toMsysPath(windowsPath) {
+ // 'c:\myfolder' -> '/c/myfolder' or '/cygdrive/c/myfolder'
+ let msysPath = windowsPath.replace(/\\/g, '/');
+ if (isMSYS2 || isMinGW) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/$1');
+ } else if (isCygwin) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/cygdrive/$1');
+ }
+ console.error(`[debug] oclif toMsysPath before="${windowsPath}" after="${msysPath}"`);
+ return msysPath;
+}
+exports.toMsysPath = toMsysPath;
+
+/* Like qqjs qq.x(), but using MSYS bash on Windows instead of cmd.exe */
+async function msysExec(cmd, options = {}) {
+ if (process.platform !== 'win32') {
+ return qq.x(cmd, options);
+ }
+ const sh = MSYSSHELLPATH;
+ const args = ['-c', cmd];
+ console.error(`[debug] oclif msysExec sh="${sh}" args=${JSON.stringify(args)} options=${JSON.stringify(options)}`);
+ return qq.x(sh, args, options);
+}
+exports.msysExec = msysExec;

View File

@ -0,0 +1,294 @@
diff --git a/node_modules/oclif/lib/commands/pack/macos.js b/node_modules/oclif/lib/commands/pack/macos.js
index d06d0b3..4bdcd34 100644
--- a/node_modules/oclif/lib/commands/pack/macos.js
+++ b/node_modules/oclif/lib/commands/pack/macos.js
@@ -177,6 +177,7 @@ class PackMacos extends core_1.Command {
if (process.env.OSX_KEYCHAIN)
args.push('--keychain', process.env.OSX_KEYCHAIN);
args.push(dist);
+ console.error(`[debug] oclif pkgbuild "${args.join('" "')}"`);
await exec(`pkgbuild ${args.join(' ')}`);
};
const arches = _.uniq(buildConfig.targets
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
index 360c34b..4e1047b 100644
--- a/node_modules/oclif/lib/commands/pack/win.js
+++ b/node_modules/oclif/lib/commands/pack/win.js
@@ -59,6 +59,13 @@ InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
${customization}
Section "${config.name} CLI \${VERSION}"
+ ; First remove any old client files.
+ ; (Remnants of old versions were causing CLI errors)
+ ; Initially tried running the Uninstall.exe, but was
+ ; unable to make script wait for completion (despite using _?)
+ DetailPrint "Removing files from previous version."
+ RMDir /r "$INSTDIR\\client"
+
SetOutPath $INSTDIR
File /r bin
File /r client
@@ -203,7 +210,8 @@ class PackWin extends core_1.Command {
async run() {
await this.checkForNSIS();
const { flags } = await this.parse(PackWin);
- const buildConfig = await Tarballs.buildConfig(flags.root);
+ const $targets = flags.targets ? flags.targets.split(',') : undefined;
+ const buildConfig = await Tarballs.buildConfig(flags.root, { targets: $targets });
const { config } = buildConfig;
await Tarballs.build(buildConfig, { platform: 'win32', pack: false, tarball: flags.tarball, parallel: true });
const arches = buildConfig.targets.filter(t => t.platform === 'win32').map(t => t.arch);
@@ -225,7 +233,8 @@ class PackWin extends core_1.Command {
fs.writeFile(path.join(installerBase, 'bin', `${flags['additional-cli']}`), scripts.sh({ bin: flags['additional-cli'] })),
] : []));
await fs.move(buildConfig.workspace({ platform: 'win32', arch }), path.join(installerBase, 'client'));
- await exec(`makensis ${installerBase}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
+ const { msysExec, toMsysPath } = require("../../util");
+ await msysExec(`makensis ${toMsysPath(installerBase)}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
const templateKey = (0, upload_util_1.templateShortKey)('win32', { bin: config.bin, version: config.version, sha: buildConfig.gitSha, arch });
const o = buildConfig.dist(`win32/${templateKey}`);
await fs.move(path.join(installerBase, 'installer.exe'), o);
@@ -263,6 +272,10 @@ PackWin.flags = {
default: '.',
required: true,
}),
+ targets: core_1.Flags.string({
+ char: 't',
+ description: 'comma-separated targets to pack (e.g.: win32-x86,win32-x64)'
+ }),
'additional-cli': core_1.Flags.string({
description: `an Oclif CLI other than the one listed in config.bin that should be made available to the user
the CLI should already exist in a directory named after the CLI that is the root of the tarball produced by "oclif pack:tarballs"`,
diff --git a/node_modules/oclif/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
index 384ea4b..40998f6 100644
--- a/node_modules/oclif/lib/tarballs/build.js
+++ b/node_modules/oclif/lib/tarballs/build.js
@@ -21,7 +21,8 @@ const pack = async (from, to) => {
await exec(`tar cfJ ${to} ${(path.basename(from))}`, { cwd }));
};
async function build(c, options = {}) {
- const { xz, config } = c;
+ const { xz, config, tmp } = c;
+ console.error(`[debug] oclif cwd="${prevCwd}"\n c.root="${c.root}" c.workspace()="${c.workspace()}"`);
const packCLI = async () => {
const { stdout } = await exec('npm pack --unsafe-perm', { cwd: c.root });
return path.join(c.root, stdout.trim().split('\n').pop());
@@ -30,7 +31,8 @@ async function build(c, options = {}) {
await fs.emptyDir(c.workspace());
const tarballNewLocation = path.join(c.workspace(), path.basename(tarball));
await fs.move(tarball, tarballNewLocation);
- await exec(`tar -xzf "${tarballNewLocation}"`, { cwd: c.workspace() });
+ const { msysExec, toMsysPath } = require("../util");
+ await msysExec(`tar -xzf ${toMsysPath(tarballNewLocation)}`);
await Promise.all((await fs.promises.readdir(path.join(c.workspace(), 'package'), { withFileTypes: true }))
.map(i => fs.move(path.join(c.workspace(), 'package', i.name), path.join(c.workspace(), i.name))));
await Promise.all([
@@ -38,6 +40,13 @@ async function build(c, options = {}) {
fs.promises.rm(path.join(c.workspace(), path.basename(tarball)), { recursive: true }),
fs.remove(path.join(c.workspace(), 'bin', 'run.cmd')),
]);
+ // rename the original balena-cli ./bin/balena entry point for oclif compatibility
+ await fs.move('bin/balena', 'bin/run');
+ // The oclif installers are a production installation, while the source
+ // `bin` folder may contain a `.fast-boot.json` file of a dev installation.
+ // This has previously led to issues preventing the CLI from starting, so
+ // delete `.fast-boot.json` (if any) from the destination folder.
+ await fs.promises.rm('bin/.fast-boot.json');
};
const updatePJSON = async () => {
const pjsonPath = path.join(c.workspace(), 'package.json');
@@ -49,34 +58,19 @@ async function build(c, options = {}) {
await fs.writeJSON(pjsonPath, pjson, { spaces: 2 });
};
const addDependencies = async () => {
- const yarnRoot = findYarnWorkspaceRoot(c.root) || c.root;
- if (fs.existsSync(path.join(yarnRoot, 'yarn.lock'))) {
- await fs.copy(path.join(yarnRoot, 'yarn.lock'), path.join(c.workspace(), 'yarn.lock'));
- const yarnVersion = (await exec('yarn -v')).stdout.charAt(0);
- if (yarnVersion === '1') {
- await exec('yarn --no-progress --production --non-interactive', { cwd: c.workspace() });
- }
- else if (yarnVersion === '2') {
- throw new Error('Yarn 2 is not supported yet. Try using Yarn 1, or Yarn 3');
- }
- else {
- try {
- await exec('yarn workspaces focus --production', { cwd: c.workspace() });
- }
- catch (error) {
- if (error instanceof Error && error.message.includes('Command not found')) {
- throw new Error('Missing workspace tools. Run `yarn plugin import workspace-tools`.');
- }
- throw error;
- }
- }
- }
- else {
- const lockpath = fs.existsSync(path.join(c.root, 'package-lock.json')) ?
- path.join(c.root, 'package-lock.json') :
- path.join(c.root, 'npm-shrinkwrap.json');
- await fs.copy(lockpath, path.join(c.workspace(), path.basename(lockpath)));
- await exec('npm install --production', { cwd: c.workspace() });
+ const ws = c.workspace();
+ exec(`cd ${ws}`);
+ console.error(`[debug] oclif copying node_modules to "${ws}"`)
+ const source = path.join(c.root, 'node_modules');
+ if (process.platform === 'win32') {
+ await exec(`xcopy "${source}" "${ws}\\node_modules" /S /E /B /I /K /Q /Y`);
+ } else {
+ // use the shell's `cp` on macOS in order to preserve extended
+ // file attributes containing `codesign` digital signatures
+ await exec(`cp -pR "${source}" "${ws}"`);
+ console.error(`[debug] oclif running "npm prune --production" in "${ws}"`);
+ await exec('npm prune --production');
+ console.error(`[debug] oclif done`);
}
};
const pretarball = async () => {
@@ -115,7 +109,8 @@ async function build(c, options = {}) {
output: path.join(workspace, 'bin', 'node'),
platform: target.platform,
arch: target.arch,
- tmp: path.join(config.root, 'tmp'),
+ tmp,
+ projectRootPath: c.root
});
if (options.pack === false)
return;
diff --git a/node_modules/oclif/lib/tarballs/config.js b/node_modules/oclif/lib/tarballs/config.js
index 3334d3f..a7348d9 100644
--- a/node_modules/oclif/lib/tarballs/config.js
+++ b/node_modules/oclif/lib/tarballs/config.js
@@ -24,7 +24,10 @@ async function gitSha(cwd, options = {}) {
}
exports.gitSha = gitSha;
async function Tmp(config) {
- const tmp = path.join(config.root, 'tmp');
+ const tmp = process.env.BUILD_TMP
+ ? path.join(process.env.BUILD_TMP, 'oclif')
+ : path.join(config.root, 'tmp');
+ console.error(`[debug] oclif tmp="${tmp}"`);
await fs.promises.mkdir(tmp, { recursive: true });
return tmp;
}
@@ -61,7 +64,7 @@ async function buildConfig(root, options = {}) {
s3Config: updateConfig.s3,
nodeVersion,
workspace(target) {
- const base = path.join(config.root, 'tmp');
+ const base = tmp;
if (target && target.platform)
return path.join(base, [target.platform, target.arch].join('-'), (0, upload_util_1.templateShortKey)('baseDir', { bin: config.bin }));
return path.join(base, (0, upload_util_1.templateShortKey)('baseDir', { bin: config.bin }));
diff --git a/node_modules/oclif/lib/tarballs/node.js b/node_modules/oclif/lib/tarballs/node.js
index 1a4e09b..bb56759 100644
--- a/node_modules/oclif/lib/tarballs/node.js
+++ b/node_modules/oclif/lib/tarballs/node.js
@@ -11,9 +11,10 @@ const node_util_1 = require("node:util");
const got_1 = require("got");
const pipeline = (0, node_util_1.promisify)(node_stream_1.pipeline);
const exec = (0, node_util_1.promisify)(node_child_process_1.exec);
+const { isMSYS2, msysExec, toMsysPath } = require("../util");
async function checkFor7Zip() {
try {
- await exec('7z');
+ await msysExec('7z', { stdio: [0, null, 2] });
}
catch (error) {
if (error.code === 127)
@@ -51,8 +52,10 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
const basedir = path.dirname(tarball);
await fs.promises.mkdir(basedir, { recursive: true });
await pipeline(got_1.default.stream(url), fs.createWriteStream(tarball));
- if (platform !== 'win32')
- await exec(`grep "${path.basename(tarball)}" "${shasums}" | shasum -a 256 -c -`, { cwd: basedir });
+ if (platform !== 'win32') {
+ const shaCmd = isMSYS2 ? 'sha256sum -c -' : 'shasum -a 256 -c -';
+ await msysExec(`grep ${path.basename(tarball)} ${toMsysPath(shasums)} | ${shaCmd}`, { cwd: basedir });
+ }
};
const extract = async () => {
(0, log_1.log)(`extracting ${nodeBase}`);
@@ -60,7 +63,7 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
await fs.promises.mkdir(nodeTmp, { recursive: true });
await fs.promises.mkdir(path.dirname(cache), { recursive: true });
if (platform === 'win32') {
- await exec(`7z x -bd -y "${tarball}"`, { cwd: nodeTmp });
+ await msysExec(`7z x -bd -y ${toMsysPath(tarball)} > /dev/null`);
await fs.move(path.join(nodeTmp, nodeBase, 'node.exe'), path.join(cache, 'node.exe'));
}
else {
diff --git a/node_modules/oclif/lib/upload-util.js b/node_modules/oclif/lib/upload-util.js
index 0d5f705..46e2445 100644
--- a/node_modules/oclif/lib/upload-util.js
+++ b/node_modules/oclif/lib/upload-util.js
@@ -31,10 +31,10 @@ options = { root: '.' }) {
const templates = {
baseDir: '<%- bin %>',
unversioned: '<%- bin %>-<%- platform %>-<%- arch %><%- ext %>',
- versioned: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %><%- ext %>',
- manifest: '<%- bin %>-v<%- version %>-<%- sha %>-<%- platform %>-<%- arch %>-buildmanifest',
- macos: '<%- bin %>-v<%- version %>-<%- sha %>-<%- arch %>.pkg',
- win32: '<%- bin %>-v<%- version %>-<%- sha %>-<%- arch %>.exe',
+ versioned: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %><%- ext %>',
+ manifest: '<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %>-buildmanifest',
+ macos: '<%- bin %>-v<%- version %>.pkg',
+ win32: '<%- bin %>-v<%- version %>-<%- arch %>.exe',
deb: '<%- bin %>_<%- versionShaRevision %>_<%- arch %>.deb',
};
return _.template(templates[type])(Object.assign({}, options));
diff --git a/node_modules/oclif/lib/util.js b/node_modules/oclif/lib/util.js
index 75bf3c6..ed5a92e 100644
--- a/node_modules/oclif/lib/util.js
+++ b/node_modules/oclif/lib/util.js
@@ -74,6 +74,50 @@ const sortVersionsObjectByKeysDesc = (input) => {
}
return result;
};
+
+// OSTYPE is 'msys' for MSYS 1.0 and for MSYS2, or 'cygwin' for Cygwin
+// but note that OSTYPE is not "exported" by default, so run: export OSTYPE=$OSTYPE
+// MSYSTEM is 'MINGW32' for MSYS 1.0, 'MSYS' for MSYS2, and undefined for Cygwin
+const isCygwin = process.env.OSTYPE === 'cygwin';
+const isMinGW = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MINGW');
+const isMSYS2 = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MSYS');
+const MSYSSHELLPATH = process.env.MSYSSHELLPATH ||
+ (isMSYS2 ? 'C:\\msys64\\usr\\bin\\bash.exe' :
+ (isMinGW ? 'C:\\MinGW\\msys\\1.0\\bin\\bash.exe' :
+ (isCygwin ? 'C:\\cygwin64\\bin\\bash.exe' : '/bin/sh')));
+
+exports.isCygwin = isCygwin;
+exports.isMinGW = isMinGW;
+exports.isMSYS2 = isMSYS2;
+console.error(`[debug] oclif MSYSSHELLPATH=${MSYSSHELLPATH} MSYSTEM=${process.env.MSYSTEM} OSTYPE=${process.env.OSTYPE} isMSYS2=${isMSYS2} isMingGW=${isMinGW} isCygwin=${isCygwin}`);
+
+const qq = require("qqjs");
+
+/* Convert a Windows path like 'C:\tmp' to a MSYS path like '/c/tmp' */
+function toMsysPath(windowsPath) {
+ // 'c:\myfolder' -> '/c/myfolder' or '/cygdrive/c/myfolder'
+ let msysPath = windowsPath.replace(/\\/g, '/');
+ if (isMSYS2 || isMinGW) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/$1');
+ } else if (isCygwin) {
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/cygdrive/$1');
+ }
+ console.error(`[debug] oclif toMsysPath before="${windowsPath}" after="${msysPath}"`);
+ return msysPath;
+}
+exports.toMsysPath = toMsysPath;
+
+/* Like qqjs qq.x(), but using MSYS bash on Windows instead of cmd.exe */
+async function msysExec(cmd, options = {}) {
+ if (process.platform !== 'win32') {
+ return qq.x(cmd, options);
+ }
+ const sh = MSYSSHELLPATH;
+ const args = ['-c', cmd];
+ console.error(`[debug] oclif msysExec sh="${sh}" args=${JSON.stringify(args)} options=${JSON.stringify(options)}`);
+ return qq.x(sh, args, options);
+}
+exports.msysExec = msysExec;
exports.sortVersionsObjectByKeysDesc = sortVersionsObjectByKeysDesc;
const homeRegexp = new RegExp(`\\B${os.homedir().replace('/', '\\/')}`, 'g');
const curRegexp = new RegExp(`\\B${process.cwd()}`, 'g');

View File

@ -1,23 +0,0 @@
declare module 'docker-toolbelt' {
import * as Docker from 'dockerode';
interface ImageSpec {
registry?: string;
imageName: string;
tagName: string;
digest?: string;
}
type ProgressCallback = (event: any) => void;
class DockerToolbelt extends Docker {
public getRegistryAndName(image: string): Promise<ImageSpec>;
public createDeltaAsync(
src: string,
dest: string,
onProgress?: ProgressCallback,
): Promise<string>;
}
export = DockerToolbelt;
}