mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-01-18 02:39:49 +00:00
Add native installers for Windows and macOS
Change-type: minor Signed-off-by: Paulo Castro <paulo@balena.io>
This commit is contained in:
parent
c204dbd6cd
commit
dafbdd5f34
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,6 +40,7 @@ balenarc.yml
|
||||
build/
|
||||
build-bin/
|
||||
build-zip/
|
||||
dist/
|
||||
|
||||
# Ignore fast-boot cache file
|
||||
**/.fast-boot.json
|
||||
|
16
.travis.yml
16
.travis.yml
@ -3,15 +3,21 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
node_js:
|
||||
- "8"
|
||||
before_install:
|
||||
- npm -g install npm@4
|
||||
script: npm run ci
|
||||
- "10"
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm run ci
|
||||
notifications:
|
||||
email: false
|
||||
deploy:
|
||||
- provider: script
|
||||
script: npm run release
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm run build:standalone
|
||||
- npm run build:installer
|
||||
- npm run release
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
12
appveyor.yml
12
appveyor.yml
@ -1,6 +1,8 @@
|
||||
# appveyor file
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
image: Visual Studio 2017
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
@ -14,12 +16,12 @@ matrix:
|
||||
# what combinations to test
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: 8
|
||||
- nodejs_version: 10
|
||||
|
||||
install:
|
||||
- ps: Install-Product node $env:nodejs_version x64
|
||||
- npm install -g npm@4
|
||||
- set PATH=%APPDATA%\npm;%PATH%
|
||||
- npm config set python 'C:\Python27\python.exe'
|
||||
- npm install
|
||||
|
||||
build: off
|
||||
@ -27,8 +29,12 @@ build: off
|
||||
test_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- cmd: npm test
|
||||
- npm test
|
||||
|
||||
deploy_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm run build:standalone
|
||||
- npm run build:installer
|
||||
- IF "%APPVEYOR_REPO_TAG%" == "true" (npm run release)
|
||||
- IF NOT "%APPVEYOR_REPO_TAG%" == "true" (echo 'Not tagged, skipping deploy')
|
||||
|
128
automation/build-bin.ts
Executable file → Normal file
128
automation/build-bin.ts
Executable file → Normal file
@ -14,50 +14,106 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { run as oclifRun } from '@oclif/dev-cli';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import * as filehound from 'filehound';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { exec as execPkg } from 'pkg';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
export const ROOT = path.join(__dirname, '..');
|
||||
|
||||
console.log('Building package...\n');
|
||||
/**
|
||||
* Use the 'pkg' module to create a single large executable file with
|
||||
* the contents of 'node_modules' and the CLI's javascript code.
|
||||
* Also copy a number of native modules (binary '.node' files) that are
|
||||
* compiled during 'npm install' to the 'build-bin' folder, alongside
|
||||
* the single large executable file created by pkg. (This is necessary
|
||||
* because of a pkg limitation that does not allow binary executables
|
||||
* to be directly executed from inside another binary executable.)
|
||||
*/
|
||||
export async function buildPkg() {
|
||||
console.log('Building package...\n');
|
||||
|
||||
execPkg(['--target', 'host', '--output', 'build-bin/balena', 'package.json'])
|
||||
.then(() => {
|
||||
const xpaths: Array<[string, string[]]> = [
|
||||
// [platform, [path, to, file]]
|
||||
['*', ['opn', 'xdg-open']],
|
||||
['darwin', ['denymount', 'bin', 'denymount']],
|
||||
];
|
||||
return Bluebird.map(xpaths, ([platform, xpath]) => {
|
||||
if (platform === '*' || platform === process.platform) {
|
||||
// eg copy from node_modules/opn/xdg-open to build-bin/xdg-open
|
||||
return fs.copy(
|
||||
path.join(ROOT, 'node_modules', ...xpath),
|
||||
path.join(ROOT, 'build-bin', xpath.pop()!),
|
||||
);
|
||||
}
|
||||
}).return();
|
||||
})
|
||||
.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 => {
|
||||
await execPkg([
|
||||
'--target',
|
||||
'host',
|
||||
'--output',
|
||||
'build-bin/balena',
|
||||
'package.json',
|
||||
]);
|
||||
const xpaths: Array<[string, string[]]> = [
|
||||
// [platform, [path, to, file]]
|
||||
['*', ['opn', 'xdg-open']],
|
||||
['darwin', ['denymount', 'bin', 'denymount']],
|
||||
];
|
||||
await Bluebird.map(xpaths, ([platform, xpath]) => {
|
||||
if (platform === '*' || platform === process.platform) {
|
||||
// eg copy from node_modules/opn/xdg-open to build-bin/xdg-open
|
||||
return fs.copy(
|
||||
extPath,
|
||||
extPath.replace(
|
||||
path.join(ROOT, 'node_modules'),
|
||||
path.join(ROOT, 'build-bin'),
|
||||
),
|
||||
path.join(ROOT, 'node_modules', ...xpath),
|
||||
path.join(ROOT, 'build-bin', xpath.pop()!),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
const nativeExtensionPaths: string[] = await filehound
|
||||
.create()
|
||||
.paths(path.join(ROOT, 'node_modules'))
|
||||
.ext(['node', 'dll'])
|
||||
.find();
|
||||
|
||||
console.log(`\nCopying to build-bin:\n${nativeExtensionPaths.join('\n')}`);
|
||||
|
||||
await Bluebird.map(nativeExtensionPaths, extPath =>
|
||||
fs.copy(
|
||||
extPath,
|
||||
extPath.replace(
|
||||
path.join(ROOT, 'node_modules'),
|
||||
path.join(ROOT, 'build-bin'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the `oclif-dev pack:win` or `pack:macos` command (depending on the value
|
||||
* of process.platform) to generate the native installers (which end up under
|
||||
* the 'dist' folder). There are some harcoded options such as selecting only
|
||||
* 64-bit binaries under Windows.
|
||||
*/
|
||||
export async function buildOclifInstaller() {
|
||||
console.log(`buildOclifInstaller cwd="${process.cwd()}" ROOT="${ROOT}"`);
|
||||
let packOS = '';
|
||||
let packOpts = ['-r', ROOT];
|
||||
if (process.platform === 'darwin') {
|
||||
packOS = 'macos';
|
||||
} else if (process.platform === 'win32') {
|
||||
packOS = 'win';
|
||||
packOpts = packOpts.concat('-t', 'win32-x64');
|
||||
}
|
||||
if (packOS) {
|
||||
const packCmd = `pack:${packOS}`;
|
||||
const dirs = [path.join(ROOT, 'dist', packOS)];
|
||||
if (packOS === 'win') {
|
||||
dirs.push(path.join(ROOT, 'tmp', 'win*'));
|
||||
}
|
||||
for (const dir of dirs) {
|
||||
console.log(`rimraf(${dir})`);
|
||||
await Bluebird.fromCallback(cb => rimraf(dir, cb));
|
||||
}
|
||||
console.log('=======================================================');
|
||||
console.log(`oclif-dev "${packCmd}" [${packOpts}]`);
|
||||
console.log('=======================================================');
|
||||
oclifRun([packCmd].concat(...packOpts));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert e.g. 'C:\myfolder' -> '/C/myfolder' so that the path can be given
|
||||
* as argument to "unix tools" like 'tar' under MSYS or MSYS2 on Windows.
|
||||
*/
|
||||
export function fixPathForMsys(p: string): string {
|
||||
return p.replace(/\\/g, '/').replace(/^([a-zA-Z]):/, '/$1');
|
||||
}
|
||||
|
@ -15,70 +15,133 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import * as archiver from 'archiver';
|
||||
import * as Promise from 'bluebird';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as os from 'os';
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
import * as publishRelease from 'publish-release';
|
||||
|
||||
import * as packageJSON from '../package.json';
|
||||
|
||||
const publishReleaseAsync = Promise.promisify(publishRelease);
|
||||
const mkdirpAsync = Promise.promisify<string | null, string>(mkdirp);
|
||||
|
||||
const { GITHUB_TOKEN } = process.env;
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
|
||||
// Note: the following 'tslint disable' line was only required to
|
||||
// satisfy ts-node under Appveyor's MSYS2 on Windows -- oddly specific.
|
||||
// Maybe something to do with '/' vs '\' in paths in some tslint file.
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
const packageJSON = require(path.join(ROOT, 'package.json'));
|
||||
const version = 'v' + packageJSON.version;
|
||||
const outputFile = path.join(
|
||||
ROOT,
|
||||
'build-zip',
|
||||
`balena-cli-${version}-${os.platform()}-${os.arch()}.zip`,
|
||||
);
|
||||
const arch = process.arch;
|
||||
|
||||
mkdirpAsync(path.dirname(outputFile))
|
||||
.then(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
console.log('Zipping build...');
|
||||
function dPath(...paths: string[]) {
|
||||
return path.join(ROOT, 'dist', ...paths);
|
||||
}
|
||||
|
||||
const archive = archiver('zip', {
|
||||
zlib: { level: 7 },
|
||||
});
|
||||
archive.directory(path.join(ROOT, 'build-bin'), 'balena-cli');
|
||||
interface PathByPlatform {
|
||||
[platform: string]: string;
|
||||
}
|
||||
|
||||
const outputStream = fs.createWriteStream(outputFile);
|
||||
const standaloneZips: PathByPlatform = {
|
||||
linux: dPath(`balena-cli-${version}-linux-${arch}-standalone.zip`),
|
||||
darwin: dPath(`balena-cli-${version}-macOS-${arch}-standalone.zip`),
|
||||
win32: dPath(`balena-cli-${version}-windows-${arch}-standalone.zip`),
|
||||
};
|
||||
|
||||
outputStream.on('close', resolve);
|
||||
outputStream.on('error', reject);
|
||||
const oclifInstallers: PathByPlatform = {
|
||||
darwin: dPath('macos', `balena-${version}.pkg`),
|
||||
win32: dPath('win', `balena-${version}-${arch}.exe`),
|
||||
};
|
||||
|
||||
archive.on('error', reject);
|
||||
archive.on('warning', console.warn);
|
||||
const renamedOclifInstallers: PathByPlatform = {
|
||||
darwin: dPath(`balena-cli-${version}-macOS-${arch}-installer-BETA.pkg`),
|
||||
win32: dPath(`balena-cli-${version}-windows-${arch}-installer-BETA.exe`),
|
||||
};
|
||||
|
||||
archive.pipe(outputStream);
|
||||
archive.finalize();
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
console.log('Build zipped');
|
||||
console.log('Publishing build...');
|
||||
const finalReleaseAssets: { [platform: string]: string[] } = {
|
||||
win32: [standaloneZips['win32'], renamedOclifInstallers['win32']],
|
||||
darwin: [standaloneZips['darwin'], renamedOclifInstallers['darwin']],
|
||||
linux: [standaloneZips['linux']],
|
||||
};
|
||||
|
||||
return publishReleaseAsync({
|
||||
/**
|
||||
* Create the zip file for the standalone 'pkg' bundle previously created
|
||||
* by the buildPkg() function in 'build-bin.ts'.
|
||||
*/
|
||||
export async function zipStandaloneInstaller() {
|
||||
const outputFile = standaloneZips[process.platform];
|
||||
if (!outputFile) {
|
||||
throw new Error(
|
||||
`Standalone installer unavailable for platform "${process.platform}"`,
|
||||
);
|
||||
}
|
||||
await fs.mkdirp(path.dirname(outputFile));
|
||||
await new Bluebird((resolve, reject) => {
|
||||
console.log(`Zipping build to "${outputFile}"...`);
|
||||
|
||||
const archive = archiver('zip', {
|
||||
zlib: { level: 7 },
|
||||
});
|
||||
archive.directory(path.join(ROOT, 'build-bin'), 'balena-cli');
|
||||
|
||||
const 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();
|
||||
});
|
||||
console.log('Build zipped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a release in GitHub's releases page, uploading the
|
||||
* installer files (standalone zip + native oclif installers).
|
||||
*/
|
||||
export async function createGitHubRelease() {
|
||||
console.log(`Publishing release ${version} to GitHub`);
|
||||
const ghRelease = await Bluebird.fromCallback(
|
||||
publishRelease.bind(null, {
|
||||
token: GITHUB_TOKEN || '',
|
||||
owner: 'balena-io',
|
||||
repo: 'balena-cli',
|
||||
tag: version,
|
||||
name: `balena-CLI ${version}`,
|
||||
reuseRelease: true,
|
||||
assets: [outputFile],
|
||||
});
|
||||
})
|
||||
.then(release => {
|
||||
console.log(`Release ${version} successful: ${release.html_url}`);
|
||||
})
|
||||
.catch(err => {
|
||||
assets: finalReleaseAssets[process.platform],
|
||||
}),
|
||||
);
|
||||
console.log(`Release ${version} successful: ${ghRelease.html_url}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level function to create a CLI release in GitHub's releases page:
|
||||
* call zipStandaloneInstaller(), rename the files as we'd like them to
|
||||
* display on the releases page, and call createGitHubRelease() to upload
|
||||
* the files.
|
||||
*/
|
||||
export async function release() {
|
||||
console.log(`Creating release assets for CLI ${version}`);
|
||||
try {
|
||||
await zipStandaloneInstaller();
|
||||
} catch (error) {
|
||||
console.log(`Error creating standalone installer zip file: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (process.platform === 'win32' || process.platform === 'darwin') {
|
||||
if (await fs.pathExists(oclifInstallers[process.platform])) {
|
||||
await fs.rename(
|
||||
oclifInstallers[process.platform],
|
||||
renamedOclifInstallers[process.platform],
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await createGitHubRelease();
|
||||
} catch (err) {
|
||||
console.error('Release failed');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
112
automation/run.ts
Normal file
112
automation/run.ts
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 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 { spawn } from 'child_process';
|
||||
import * as _ from 'lodash';
|
||||
import * as shellEscape from 'shell-escape';
|
||||
|
||||
import {
|
||||
buildOclifInstaller,
|
||||
buildPkg,
|
||||
fixPathForMsys,
|
||||
ROOT,
|
||||
} from './build-bin';
|
||||
import { release } from './deploy-bin';
|
||||
|
||||
/**
|
||||
* Run the MSYS2 bash.exe shell in a child process (child_process.spawn()).
|
||||
* The given argv arguments are escaped using the 'shell-escape' package,
|
||||
* so that backslashes in Windows paths, and other bash-special characters,
|
||||
* are preserved. If argv is not provided, defaults to process.argv, to the
|
||||
* effect that this current (parent) process is re-executed under MSYS2 bash.
|
||||
* This is useful to change the default shell from cmd.exe to MSYS2 bash on
|
||||
* Windows.
|
||||
* @param argv Arguments to be shell-escaped and given to MSYS2 bash.exe.
|
||||
*/
|
||||
export async function runUnderMsys(argv?: string[]) {
|
||||
const newArgv = argv || process.argv;
|
||||
await new Promise((resolve, reject) => {
|
||||
const cmd = 'C:\\msys64\\usr\\bin\\bash.exe';
|
||||
const args = ['-lc', shellEscape(newArgv)];
|
||||
const child = spawn(cmd, args, { stdio: 'inherit' });
|
||||
child.on('close', code => {
|
||||
if (code) {
|
||||
console.log(`runUnderMsys: child process exited with code ${code}`);
|
||||
reject(code);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial command-line parser. Check whether the command-line argument is one
|
||||
* of the following strings, then call the appropriate functions:
|
||||
* 'build:installer' (to build a native oclif installer)
|
||||
* 'build:standalone' (to build a standalone pkg package)
|
||||
* 'release' (to create/update a GitHub release)
|
||||
*
|
||||
* In the case of 'build:installer', also call runUnderMsys() to switch the
|
||||
* shell from cmd.exe to MSYS2 bash.exe.
|
||||
*
|
||||
* @param args Arguments to parse (default is process.argv.slice(2))
|
||||
*/
|
||||
export async function run(args?: string[]) {
|
||||
args = args || process.argv.slice(2);
|
||||
console.log(`automation/run.ts process.argv=[${process.argv}]\n`);
|
||||
console.log(`automation/run.ts args=[${args}]`);
|
||||
if (_.isEmpty(args)) {
|
||||
console.error('Error: missing args');
|
||||
process.exit(1);
|
||||
}
|
||||
const commands: { [cmd: string]: () => void } = {
|
||||
'build:installer': buildOclifInstaller,
|
||||
'build:standalone': buildPkg,
|
||||
release,
|
||||
};
|
||||
for (const arg of args) {
|
||||
if (!commands.hasOwnProperty(arg)) {
|
||||
throw new Error(`Error: unknown build target: ${arg}`);
|
||||
}
|
||||
}
|
||||
|
||||
// If runUnderMsys() is called to re-execute this script under MSYS2,
|
||||
// the current working dir becomes the MSYS2 homedir, so we change back.
|
||||
process.chdir(ROOT);
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg === 'build:installer' && process.platform === 'win32') {
|
||||
// ensure running under MSYS2
|
||||
if (!process.env.MSYSTEM) {
|
||||
process.env.MSYS2_PATH_TYPE = 'inherit';
|
||||
await runUnderMsys([
|
||||
fixPathForMsys(process.argv[0]),
|
||||
fixPathForMsys(process.argv[1]),
|
||||
arg,
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
if (process.env.MSYS2_PATH_TYPE !== 'inherit') {
|
||||
throw new Error('the MSYS2_PATH_TYPE env var must be set to "inherit"');
|
||||
}
|
||||
}
|
||||
await commands[arg]();
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
@ -8,6 +8,7 @@
|
||||
"noUnusedParameters": true,
|
||||
"preserveConstEnums": true,
|
||||
"removeComments": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true,
|
||||
"typeRoots" : [
|
||||
|
29
package.json
29
package.json
@ -10,13 +10,13 @@
|
||||
},
|
||||
"preferGlobal": true,
|
||||
"files": [
|
||||
"bin/balena",
|
||||
"bin/run",
|
||||
"build/",
|
||||
"doc/",
|
||||
"lib/"
|
||||
],
|
||||
"bin": {
|
||||
"balena": "./bin/balena"
|
||||
"balena": "./bin/run"
|
||||
},
|
||||
"pkg": {
|
||||
"scripts": [
|
||||
@ -31,13 +31,15 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rimraf build/ build-bin/ build-zip/ && patch-package",
|
||||
"build": "npm run build:src && npm run build:bin",
|
||||
"postinstall": "patch-package",
|
||||
"prebuild": "rimraf build/ build-bin/",
|
||||
"build": "npm run build:src",
|
||||
"build:src": "npm run prettify && npm run lint && npm run build:fast && npm run build:doc",
|
||||
"build:fast": "gulp build && tsc",
|
||||
"build:doc": "mkdirp doc/ && ts-node --type-check -P automation/tsconfig.json automation/capitanodoc/index.ts > doc/cli.markdown",
|
||||
"build:bin": "ts-node --type-check -P automation/tsconfig.json automation/build-bin.ts",
|
||||
"release": "npm run build && ts-node --type-check -P automation/tsconfig.json automation/deploy-bin.ts",
|
||||
"build:standalone": "ts-node --type-check -P automation/tsconfig.json automation/run.ts build:standalone",
|
||||
"build:installer": "ts-node --type-check -P automation/tsconfig.json automation/run.ts build:installer",
|
||||
"release": "ts-node --type-check -P automation/tsconfig.json automation/run.ts release",
|
||||
"pretest": "npm run build",
|
||||
"test": "gulp test",
|
||||
"test:fast": "npm run build:fast && gulp test",
|
||||
@ -45,7 +47,6 @@
|
||||
"watch": "gulp watch",
|
||||
"prettify": "prettier --write \"{lib,tests,automation,typings}/**/*.ts\" --config ./node_modules/resin-lint/config/.prettierrc",
|
||||
"lint": "resin-lint lib/ tests/ && resin-lint --typescript automation/ lib/ typings/ tests/",
|
||||
"prepublish": "require-npm4-to-publish",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
@ -70,15 +71,15 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@oclif/dev-cli": "^1.22.0",
|
||||
"@oclif/config": "^1.12.12",
|
||||
"@oclif/dev-cli": "1.22.0",
|
||||
"@oclif/parser": "^3.7.3",
|
||||
"@types/archiver": "2.1.2",
|
||||
"@types/bluebird": "3.5.21",
|
||||
"@types/chokidar": "^1.7.5",
|
||||
"@types/common-tags": "1.4.0",
|
||||
"@types/dockerode": "2.5.5",
|
||||
"@types/fs-extra": "5.0.4",
|
||||
"@types/fs-extra": "7.0.0",
|
||||
"@types/is-root": "1.0.0",
|
||||
"@types/lodash": "4.14.112",
|
||||
"@types/mixpanel": "2.14.0",
|
||||
@ -89,13 +90,15 @@
|
||||
"@types/prettyjson": "0.0.28",
|
||||
"@types/raven": "2.5.1",
|
||||
"@types/request": "2.48.1",
|
||||
"@types/rimraf": "^2.0.2",
|
||||
"@types/shell-escape": "^0.2.0",
|
||||
"@types/stream-to-promise": "2.2.0",
|
||||
"@types/tar-stream": "1.6.0",
|
||||
"@types/through2": "2.0.33",
|
||||
"catch-uncommitted": "^1.3.0",
|
||||
"ent": "^2.2.0",
|
||||
"filehound": "^1.17.0",
|
||||
"fs-extra": "^5.0.0",
|
||||
"fs-extra": "^8.0.1",
|
||||
"gulp": "^4.0.1",
|
||||
"gulp-coffee": "^2.2.0",
|
||||
"gulp-inline-source": "^2.1.0",
|
||||
@ -105,10 +108,10 @@
|
||||
"patch-package": "^6.1.2",
|
||||
"pkg": "~4.3.8",
|
||||
"prettier": "^1.17.0",
|
||||
"publish-release": "^1.3.3",
|
||||
"require-npm4-to-publish": "^1.0.0",
|
||||
"publish-release": "^1.6.0",
|
||||
"resin-lint": "^3.0.1",
|
||||
"rewire": "^3.0.2",
|
||||
"shell-escape": "^0.2.0",
|
||||
"ts-node": "^8.1.0",
|
||||
"typescript": "3.4.3"
|
||||
},
|
||||
@ -165,7 +168,7 @@
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment": "^2.24.0",
|
||||
"moment-duration-format": "~2.2.2",
|
||||
"mz": "^2.6.0",
|
||||
"mz": "^2.7.0",
|
||||
"node-cleanup": "^2.1.2",
|
||||
"oclif": "^1.13.1",
|
||||
"opn": "^5.5.0",
|
||||
|
146
patches/@oclif+dev-cli+1.22.0.patch
Normal file
146
patches/@oclif+dev-cli+1.22.0.patch
Normal file
@ -0,0 +1,146 @@
|
||||
diff --git a/node_modules/@oclif/dev-cli/lib/commands/pack/win.js b/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
|
||||
index a9d4276..75c2f8b 100644
|
||||
--- a/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
|
||||
+++ b/node_modules/@oclif/dev-cli/lib/commands/pack/win.js
|
||||
@@ -3,11 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const command_1 = require("@oclif/command");
|
||||
const qq = require("qqjs");
|
||||
const Tarballs = require("../../tarballs");
|
||||
+const { fixPath } = require("../../util");
|
||||
+
|
||||
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 !== undefined ? flags.targets.split(',') : undefined;
|
||||
+ const buildConfig = await Tarballs.buildConfig(flags.root, {targets});
|
||||
const { config } = buildConfig;
|
||||
await Tarballs.build(buildConfig, { platform: 'win32', pack: false });
|
||||
const arches = buildConfig.targets.filter(t => t.platform === 'win32').map(t => t.arch);
|
||||
@@ -17,7 +20,7 @@ class PackWin extends command_1.Command {
|
||||
await qq.write([installerBase, `bin/${config.bin}`], scripts.sh(config));
|
||||
await qq.write([installerBase, `${config.bin}.nsi`], scripts.nsis(config, arch));
|
||||
await qq.mv(buildConfig.workspace({ platform: 'win32', arch }), [installerBase, 'client']);
|
||||
- await qq.x(`makensis ${installerBase}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
|
||||
+ await qq.x(`makensis ${fixPath(installerBase)}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`)
|
||||
const o = buildConfig.dist(`win/${config.bin}-v${buildConfig.version}-${arch}.exe`);
|
||||
await qq.mv([installerBase, 'installer.exe'], o);
|
||||
this.log(`built ${o}`);
|
||||
@@ -40,6 +43,7 @@ class PackWin extends command_1.Command {
|
||||
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)'}),
|
||||
};
|
||||
exports.default = PackWin;
|
||||
const scripts = {
|
||||
diff --git a/node_modules/@oclif/dev-cli/lib/tarballs/build.js b/node_modules/@oclif/dev-cli/lib/tarballs/build.js
|
||||
index 3e613e0..4ed799c 100644
|
||||
--- a/node_modules/@oclif/dev-cli/lib/tarballs/build.js
|
||||
+++ b/node_modules/@oclif/dev-cli/lib/tarballs/build.js
|
||||
@@ -19,6 +19,9 @@ const pack = async (from, to) => {
|
||||
async function build(c, options = {}) {
|
||||
const { xz, config } = c;
|
||||
const prevCwd = qq.cwd();
|
||||
+
|
||||
+ console.log(`[patched @oclif/dev-cli] 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());
|
||||
@@ -34,6 +37,21 @@ async function build(c, options = {}) {
|
||||
await qq.mv(f, '.');
|
||||
await qq.rm('package', tarball, 'bin/run.cmd');
|
||||
};
|
||||
+ const copyCLI = async() => {
|
||||
+ const ws = c.workspace();
|
||||
+ await qq.emptyDir(ws);
|
||||
+ qq.cd(ws);
|
||||
+ const sources = [
|
||||
+ 'bin', 'build', 'patches', 'typings', 'CHANGELOG.md', 'INSTALL.md',
|
||||
+ 'LICENSE', 'package.json', 'package-lock.json', 'README.md',
|
||||
+ 'TROUBLESHOOTING.md',
|
||||
+ ];
|
||||
+ for (const source of sources) {
|
||||
+ console.log(`cp "${source}" -> "${ws}"`);
|
||||
+ await qq.cp(path.join(c.root, source), ws);
|
||||
+ }
|
||||
+ await qq.rm('bin/run.cmd');
|
||||
+ }
|
||||
const updatePJSON = async () => {
|
||||
qq.cd(c.workspace());
|
||||
const pjson = await qq.readJSON('package.json');
|
||||
@@ -124,7 +142,8 @@ async function build(c, options = {}) {
|
||||
await qq.writeJSON(c.dist(config.s3Key('manifest')), manifest);
|
||||
};
|
||||
log_1.log(`gathering workspace for ${config.bin} to ${c.workspace()}`);
|
||||
- await extractCLI(await packCLI());
|
||||
+ // await extractCLI(await packCLI());
|
||||
+ await copyCLI();
|
||||
await updatePJSON();
|
||||
await addDependencies();
|
||||
await bin_1.writeBinScripts({ config, baseWorkspace: c.workspace(), nodeVersion: c.nodeVersion });
|
||||
diff --git a/node_modules/@oclif/dev-cli/lib/tarballs/node.js b/node_modules/@oclif/dev-cli/lib/tarballs/node.js
|
||||
index 343eb00..7df1815 100644
|
||||
--- a/node_modules/@oclif/dev-cli/lib/tarballs/node.js
|
||||
+++ b/node_modules/@oclif/dev-cli/lib/tarballs/node.js
|
||||
@@ -1,9 +1,11 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const errors_1 = require("@oclif/errors");
|
||||
+const { isMSYS2 } = require('execa');
|
||||
const path = require("path");
|
||||
const qq = require("qqjs");
|
||||
const log_1 = require("../log");
|
||||
+const { fixPath } = require("../util");
|
||||
async function checkFor7Zip() {
|
||||
try {
|
||||
await qq.x('7z', { stdio: [0, null, 2] });
|
||||
@@ -40,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 qq.x(`grep ${path.basename(tarball)} ${fixPath(shasums)} | ${shaCmd}`, { cwd: basedir });
|
||||
};
|
||||
const extract = async () => {
|
||||
log_1.log(`extracting ${nodeBase}`);
|
||||
@@ -50,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 qq.x(`7z x -bd -y ${fixPath(tarball)} > /dev/null`);
|
||||
await qq.mv([nodeBase, 'node.exe'], cache);
|
||||
qq.popd();
|
||||
}
|
||||
diff --git a/node_modules/@oclif/dev-cli/lib/util.js b/node_modules/@oclif/dev-cli/lib/util.js
|
||||
index 17368b4..7766d88 100644
|
||||
--- a/node_modules/@oclif/dev-cli/lib/util.js
|
||||
+++ b/node_modules/@oclif/dev-cli/lib/util.js
|
||||
@@ -1,5 +1,6 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
+const { isCygwin, isMinGW, isMSYS2 } = require('execa');
|
||||
const _ = require("lodash");
|
||||
function castArray(input) {
|
||||
if (input === undefined)
|
||||
@@ -40,3 +41,16 @@ function sortBy(arr, fn) {
|
||||
}
|
||||
exports.sortBy = sortBy;
|
||||
exports.template = (context) => (t) => _.template(t || '')(context);
|
||||
+
|
||||
+function fixPath(badPath) {
|
||||
+ // 'c:\myfolder' -> '/c/myfolder' or '/cygdrive/c/myfolder'
|
||||
+ let fixed = badPath.replace(/\\/g, '/');
|
||||
+ if (isMSYS2 || isMinGW) {
|
||||
+ fixed = fixed.replace(/^([a-zA-Z]):/, '/$1');
|
||||
+ } else if (isCygwin) {
|
||||
+ fixed = fixed.replace(/^([a-zA-Z]):/, '/cygdrive/$1');
|
||||
+ }
|
||||
+ console.log(`[patched @oclif/dev-cli] fixPath before="${badPath}" after="${fixed}"`);
|
||||
+ return fixed;
|
||||
+}
|
||||
+exports.fixPath = fixPath;
|
49
patches/qqjs++execa+0.10.0.patch
Normal file
49
patches/qqjs++execa+0.10.0.patch
Normal file
@ -0,0 +1,49 @@
|
||||
diff --git a/node_modules/qqjs/node_modules/execa/index.js b/node_modules/qqjs/node_modules/execa/index.js
|
||||
index 06f3969..6251e17 100644
|
||||
--- a/node_modules/qqjs/node_modules/execa/index.js
|
||||
+++ b/node_modules/qqjs/node_modules/execa/index.js
|
||||
@@ -14,6 +14,21 @@ const stdio = require('./lib/stdio');
|
||||
|
||||
const TEN_MEGABYTES = 1000 * 1000 * 10;
|
||||
|
||||
+// 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')
|
||||
+
|
||||
+exports.isCygwin = isCygwin
|
||||
+exports.isMinGW = isMinGW
|
||||
+exports.isMSYS2 = isMSYS2
|
||||
+
|
||||
+console.log(`[patched execa] detected "${
|
||||
+ isCygwin ? 'Cygwin' : isMinGW ? 'MinGW' : isMSYS2 ? 'MSYS2' : 'standard'
|
||||
+}" environment (MSYSTEM="${process.env.MSYSTEM}")`)
|
||||
+
|
||||
function handleArgs(cmd, args, opts) {
|
||||
let parsed;
|
||||
|
||||
@@ -104,13 +119,21 @@ function handleShell(fn, cmd, opts) {
|
||||
|
||||
opts = Object.assign({}, opts);
|
||||
|
||||
- if (process.platform === 'win32') {
|
||||
+ if (isMSYS2 || isMinGW || isCygwin) {
|
||||
+ file = 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' : file)));
|
||||
+ }
|
||||
+ else if (process.platform === 'win32') {
|
||||
opts.__winShell = true;
|
||||
file = process.env.comspec || 'cmd.exe';
|
||||
args = ['/s', '/c', `"${cmd}"`];
|
||||
opts.windowsVerbatimArguments = true;
|
||||
}
|
||||
|
||||
+ console.log(`[patched execa] handleShell file="${file}" args="[${args}]"`);
|
||||
+
|
||||
if (opts.shell) {
|
||||
file = opts.shell;
|
||||
delete opts.shell;
|
Loading…
Reference in New Issue
Block a user