185 lines
4.9 KiB
JavaScript
185 lines
4.9 KiB
JavaScript
|
/*---------------------------------------------------------------------------------------------
|
||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||
|
*--------------------------------------------------------------------------------------------*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
const es = require('event-stream');
|
||
|
const gulp = require('gulp');
|
||
|
const path = require('path');
|
||
|
const fancyLog = require('fancy-log');
|
||
|
const ansiColors = require('ansi-colors');
|
||
|
const cp = require('child_process');
|
||
|
const { tmpdir } = require('os');
|
||
|
const { promises: fs, existsSync, mkdirSync, rmSync } = require('fs');
|
||
|
|
||
|
const task = require('./lib/task');
|
||
|
const watcher = require('./lib/watch');
|
||
|
const { debounce } = require('./lib/util');
|
||
|
const createReporter = require('./lib/reporter').createReporter;
|
||
|
|
||
|
const root = 'cli';
|
||
|
const rootAbs = path.resolve(__dirname, '..', root);
|
||
|
const src = `${root}/src`;
|
||
|
|
||
|
const platformOpensslDirName =
|
||
|
process.platform === 'win32' ? (
|
||
|
process.arch === 'arm64'
|
||
|
? 'arm64-windows-static-md'
|
||
|
: 'x64-windows-static-md')
|
||
|
: process.platform === 'darwin' ? (
|
||
|
process.arch === 'arm64'
|
||
|
? 'arm64-osx'
|
||
|
: 'x64-osx')
|
||
|
: (process.arch === 'arm64'
|
||
|
? 'arm64-linux'
|
||
|
: process.arch === 'arm'
|
||
|
? 'arm-linux'
|
||
|
: 'x64-linux');
|
||
|
const platformOpensslDir = path.join(rootAbs, 'openssl', 'package', 'out', platformOpensslDirName);
|
||
|
|
||
|
const hasLocalRust = (() => {
|
||
|
/** @type boolean | undefined */
|
||
|
let result = undefined;
|
||
|
return () => {
|
||
|
if (result !== undefined) {
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
const r = cp.spawnSync('cargo', ['--version']);
|
||
|
result = r.status === 0;
|
||
|
} catch (e) {
|
||
|
result = false;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
})();
|
||
|
|
||
|
const debounceEsStream = (fn, duration = 100) => {
|
||
|
let handle = undefined;
|
||
|
let pending = [];
|
||
|
const sendAll = (pending) => (event, ...args) => {
|
||
|
for (const stream of pending) {
|
||
|
pending.emit(event, ...args);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return es.map(function (_, callback) {
|
||
|
console.log('defer');
|
||
|
if (handle !== undefined) {
|
||
|
clearTimeout(handle);
|
||
|
}
|
||
|
|
||
|
handle = setTimeout(() => {
|
||
|
handle = undefined;
|
||
|
|
||
|
const previous = pending;
|
||
|
pending = [];
|
||
|
fn()
|
||
|
.on('error', sendAll('error'))
|
||
|
.on('data', sendAll('data'))
|
||
|
.on('end', sendAll('end'));
|
||
|
}, duration);
|
||
|
|
||
|
pending.push(this);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const compileFromSources = (callback) => {
|
||
|
const proc = cp.spawn('cargo', ['--color', 'always', 'build'], {
|
||
|
cwd: root,
|
||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||
|
env: existsSync(platformOpensslDir) ? { OPENSSL_DIR: platformOpensslDir, ...process.env } : process.env
|
||
|
});
|
||
|
|
||
|
/** @type Buffer[] */
|
||
|
const stdoutErr = [];
|
||
|
proc.stdout.on('data', d => stdoutErr.push(d));
|
||
|
proc.stderr.on('data', d => stdoutErr.push(d));
|
||
|
proc.on('error', callback);
|
||
|
proc.on('exit', code => {
|
||
|
if (code !== 0) {
|
||
|
callback(Buffer.concat(stdoutErr).toString());
|
||
|
} else {
|
||
|
callback();
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const acquireBuiltOpenSSL = (callback) => {
|
||
|
const untar = require('gulp-untar');
|
||
|
const gunzip = require('gulp-gunzip');
|
||
|
const dir = path.join(tmpdir(), 'vscode-openssl-download');
|
||
|
mkdirSync(dir, { recursive: true });
|
||
|
|
||
|
cp.spawnSync(
|
||
|
process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
||
|
['pack', '@vscode/openssl-prebuilt'],
|
||
|
{ stdio: ['ignore', 'ignore', 'inherit'], cwd: dir }
|
||
|
);
|
||
|
|
||
|
gulp.src('*.tgz', { cwd: dir })
|
||
|
.pipe(gunzip())
|
||
|
.pipe(untar())
|
||
|
.pipe(gulp.dest(`${root}/openssl`))
|
||
|
.on('error', callback)
|
||
|
.on('end', () => {
|
||
|
rmSync(dir, { recursive: true, force: true });
|
||
|
callback();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const compileWithOpenSSLCheck = (/** @type import('./lib/reporter').IReporter */ reporter) => es.map((_, callback) => {
|
||
|
compileFromSources(err => {
|
||
|
if (!err) {
|
||
|
// no-op
|
||
|
} else if (err.toString().includes('Could not find directory of OpenSSL installation') && !existsSync(platformOpensslDir)) {
|
||
|
fancyLog(ansiColors.yellow(`[cli]`), 'OpenSSL libraries not found, acquiring prebuilt bits...');
|
||
|
acquireBuiltOpenSSL(err => {
|
||
|
if (err) {
|
||
|
callback(err);
|
||
|
} else {
|
||
|
compileFromSources(err => {
|
||
|
if (err) {
|
||
|
reporter(err.toString());
|
||
|
}
|
||
|
callback(null, '');
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
reporter(err.toString());
|
||
|
}
|
||
|
|
||
|
callback(null, '');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
const warnIfRustNotInstalled = () => {
|
||
|
if (!hasLocalRust()) {
|
||
|
fancyLog(ansiColors.yellow(`[cli]`), 'No local Rust install detected, compilation may fail.');
|
||
|
fancyLog(ansiColors.yellow(`[cli]`), 'Get rust from: https://rustup.rs/');
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const compileCliTask = task.define('compile-cli', () => {
|
||
|
warnIfRustNotInstalled();
|
||
|
const reporter = createReporter('cli');
|
||
|
return gulp.src(`${root}/Cargo.toml`)
|
||
|
.pipe(compileWithOpenSSLCheck(reporter))
|
||
|
.pipe(reporter.end(true));
|
||
|
});
|
||
|
|
||
|
|
||
|
const watchCliTask = task.define('watch-cli', () => {
|
||
|
warnIfRustNotInstalled();
|
||
|
return watcher(`${src}/**`, { read: false })
|
||
|
.pipe(debounce(compileCliTask));
|
||
|
});
|
||
|
|
||
|
gulp.task(compileCliTask);
|
||
|
gulp.task(watchCliTask);
|