adopt built-in extensions
This commit is contained in:
parent
ec805db5ed
commit
38db1778aa
3 changed files with 228 additions and 194 deletions
308
build/ext.js
308
build/ext.js
|
@ -1,207 +1,127 @@
|
|||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const cp = require('child_process');
|
||||
const os = require('os');
|
||||
const mkdirp = require('mkdirp');
|
||||
const product = require('../product.json');
|
||||
const root = path.resolve(path.join(__dirname, '..', '..'));
|
||||
const exists = (path) => fs.stat(path).then(() => true, () => false);
|
||||
|
||||
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
|
||||
async function readControlFile() {
|
||||
try {
|
||||
return JSON.parse(await fs.readFile(controlFilePath, 'utf8'));
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function writeControlFile(control) {
|
||||
await mkdirp(path.dirname(controlFilePath));
|
||||
await fs.writeFile(controlFilePath, JSON.stringify(control, null, ' '));
|
||||
}
|
||||
|
||||
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
||||
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
||||
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
||||
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
||||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
||||
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
||||
function fulfill(value) { resume("next", value); }
|
||||
function reject(value) { resume("throw", value); }
|
||||
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
||||
};
|
||||
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
||||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
||||
var m = o[Symbol.asyncIterator], i;
|
||||
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
||||
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
||||
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const path = require("path");
|
||||
const cp = require("child_process");
|
||||
const commander_1 = require("commander");
|
||||
const root = path.resolve(path.join(__dirname, '..'));
|
||||
var ExtensionType;
|
||||
(function (ExtensionType) {
|
||||
ExtensionType["Grammar"] = "grammar";
|
||||
ExtensionType["Theme"] = "theme";
|
||||
ExtensionType["Misc"] = "misc";
|
||||
})(ExtensionType || (ExtensionType = {}));
|
||||
// const exists = (path) => fs.stat(path).then(() => true, () => false);
|
||||
// const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
// async function readControlFile() {
|
||||
// try {
|
||||
// return JSON.parse(await fs.readFile(controlFilePath, 'utf8'));
|
||||
// } catch (err) {
|
||||
// return {};
|
||||
// }
|
||||
// }
|
||||
// async function writeControlFile(control) {
|
||||
// await mkdirp(path.dirname(controlFilePath));
|
||||
// await fs.writeFile(controlFilePath, JSON.stringify(control, null, ' '));
|
||||
// }
|
||||
async function exec(cmd, args, opts = {}) {
|
||||
return new Promise((c, e) => {
|
||||
const child = cp.spawn(cmd, args, { stdio: 'inherit', env: process.env, ...opts });
|
||||
child.on('close', code => code === 0 ? c() : e(`Returned ${code}`));
|
||||
});
|
||||
return new Promise((c, e) => {
|
||||
const child = cp.spawn(cmd, args, Object.assign({ stdio: 'inherit', env: process.env }, opts));
|
||||
child.on('close', code => code === 0 ? c() : e(`Returned ${code}`));
|
||||
});
|
||||
}
|
||||
|
||||
function getFolderPath(extDesc) {
|
||||
const folder = extDesc.repo.replace(/.*\//, '');
|
||||
return folderPath = path.join(root, folder);
|
||||
function getExtensionType(packageJson) {
|
||||
var _a, _b, _c;
|
||||
if (((_a = packageJson.contributes) === null || _a === void 0 ? void 0 : _a.themes) || ((_b = packageJson.contributes) === null || _b === void 0 ? void 0 : _b.iconThemes)) {
|
||||
return "theme" /* Theme */;
|
||||
}
|
||||
else if ((_c = packageJson.contributes) === null || _c === void 0 ? void 0 : _c.grammars) {
|
||||
return "grammar" /* Grammar */;
|
||||
}
|
||||
else {
|
||||
return "misc" /* Misc */;
|
||||
}
|
||||
}
|
||||
|
||||
async function getExtensionType(folderPath) {
|
||||
const pkg = JSON.parse(await fs.readFile(path.join(folderPath, 'package.json'), 'utf8'));
|
||||
|
||||
if (pkg['contributes']['themes'] || pkg['contributes']['iconThemes']) {
|
||||
return 'theme';
|
||||
} else if (pkg['contributes']['grammars']) {
|
||||
return 'grammar';
|
||||
} else {
|
||||
return 'misc';
|
||||
}
|
||||
async function getExtension(extensionPath) {
|
||||
const packageJsonPath = path.join(extensionPath, 'package.json');
|
||||
const packageJson = JSON.parse(await fs_1.promises.readFile(packageJsonPath, 'utf8'));
|
||||
const type = getExtensionType(packageJson);
|
||||
return {
|
||||
name: packageJson.name,
|
||||
path: extensionPath,
|
||||
type
|
||||
};
|
||||
}
|
||||
|
||||
async function initExtension(extDesc) {
|
||||
const folderPath = getFolderPath(extDesc);
|
||||
|
||||
if (!await exists(folderPath)) {
|
||||
console.log(`⏳ git clone: ${extDesc.name}`);
|
||||
await exec('git', ['clone', `${extDesc.repo}.git`], { cwd: root });
|
||||
}
|
||||
|
||||
const type = await getExtensionType(folderPath);
|
||||
return { path: folderPath, type, ...extDesc };
|
||||
function getExtensions() {
|
||||
return __asyncGenerator(this, arguments, function* getExtensions_1() {
|
||||
const extensionsPath = path.join(root, 'extensions');
|
||||
const children = yield __await(fs_1.promises.readdir(extensionsPath));
|
||||
for (const child of children) {
|
||||
try {
|
||||
yield yield __await(yield __await(getExtension(path.join(extensionsPath, child))));
|
||||
}
|
||||
catch (err) {
|
||||
if (/ENOENT|ENOTDIR/.test(err.message)) {
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function createWorkspace(type, extensions) {
|
||||
const workspaceName = `vscode-${type}-extensions.code-workspace`;
|
||||
const workspacePath = path.join(root, workspaceName);
|
||||
const workspace = { folders: extensions.map(ext => ({ path: path.basename(ext.path) })) };
|
||||
|
||||
if (!await exists(workspacePath)) {
|
||||
console.log(`✅ create workspace: ${workspaceName}`);
|
||||
}
|
||||
|
||||
await fs.writeFile(workspacePath, JSON.stringify(workspace, undefined, ' '));
|
||||
}
|
||||
|
||||
async function init() {
|
||||
const extensions = [];
|
||||
|
||||
for (const extDesc of product.builtInExtensions) {
|
||||
extensions.push(await initExtension(extDesc));
|
||||
}
|
||||
|
||||
await createWorkspace('all', extensions);
|
||||
|
||||
const byType = extensions
|
||||
.reduce((m, e) => m.set(e.type, [...(m.get(e.type) || []), e]), new Map());
|
||||
|
||||
for (const [type, extensions] of byType) {
|
||||
await createWorkspace(type, extensions);
|
||||
}
|
||||
|
||||
return byType;
|
||||
}
|
||||
|
||||
async function status() {
|
||||
const byType = await init();
|
||||
const control = await readControlFile();
|
||||
|
||||
for (const [type, extensions] of byType) {
|
||||
console.log(`${type} (${extensions.length} extensions):`);
|
||||
|
||||
const maxWidth = Math.max(...extensions.map(e => e.name.length));
|
||||
for (const ext of extensions) {
|
||||
console.log(` ${ext.name.padEnd(maxWidth, ' ')} ➡ ${control[ext.name]}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`total: ${product.builtInExtensions.length} extensions`);
|
||||
}
|
||||
|
||||
async function each([cmd, ...args], opts) {
|
||||
await init();
|
||||
|
||||
for (const extDesc of product.builtInExtensions) {
|
||||
const folderPath = getFolderPath(extDesc);
|
||||
|
||||
if (opts.type) {
|
||||
const type = await getExtensionType(folderPath);
|
||||
|
||||
if (type !== opts.type) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`👉 ${extDesc.name}`);
|
||||
await exec(cmd, args, { cwd: folderPath });
|
||||
}
|
||||
var e_1, _a;
|
||||
try {
|
||||
for (var _b = __asyncValues(getExtensions()), _c; _c = await _b.next(), !_c.done;) {
|
||||
const extension = _c.value;
|
||||
if (opts.type && extension.type !== opts.type) {
|
||||
continue;
|
||||
}
|
||||
console.log(`👉 ${extension.name}`);
|
||||
await exec(cmd, args, { cwd: extension.path });
|
||||
}
|
||||
}
|
||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_c && !_c.done && (_a = _b.return)) await _a.call(_b);
|
||||
}
|
||||
finally { if (e_1) throw e_1.error; }
|
||||
}
|
||||
}
|
||||
|
||||
async function _link(extensions, opts, fn) {
|
||||
await init();
|
||||
|
||||
const control = await readControlFile();
|
||||
|
||||
for (const extDesc of product.builtInExtensions) {
|
||||
if (extensions.length > 0 && extensions.indexOf(extDesc.name) === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opts.type) {
|
||||
const folderPath = getFolderPath(extDesc);
|
||||
const type = await getExtensionType(folderPath);
|
||||
|
||||
if (type !== opts.type) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await fn(control, extDesc);
|
||||
}
|
||||
|
||||
await writeControlFile(control);
|
||||
}
|
||||
|
||||
async function link(extensions, opts) {
|
||||
await _link(extensions, opts, async (control, extDesc) => {
|
||||
const ext = await initExtension(extDesc);
|
||||
control[extDesc.name] = ext.path;
|
||||
console.log(`👉 link: ${extDesc.name} ➡ ${ext.path}`);
|
||||
});
|
||||
}
|
||||
|
||||
async function unlink(extensions, opts) {
|
||||
await _link(extensions, opts, async (control, extDesc) => {
|
||||
control[extDesc.name] = 'marketplace';
|
||||
console.log(`👉 unlink: ${extDesc.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
const { program } = require('commander');
|
||||
|
||||
program.version('0.0.1');
|
||||
|
||||
program
|
||||
.command('init')
|
||||
.description('Initialize workspace with built-in extensions')
|
||||
.action(init);
|
||||
|
||||
program
|
||||
.command('status')
|
||||
.description('Print extension status')
|
||||
.action(status);
|
||||
|
||||
program
|
||||
.command('each <command...>')
|
||||
.option('-t, --type <type>', 'Specific type only')
|
||||
.description('Run a command in each extension repository')
|
||||
.allowUnknownOption()
|
||||
.action(each);
|
||||
|
||||
program
|
||||
.command('link [extensions...]')
|
||||
.option('-t, --type <type>', 'Specific type only')
|
||||
.description('Link with code-oss')
|
||||
.action(link);
|
||||
|
||||
program
|
||||
.command('unlink [extensions...]')
|
||||
.option('-t, --type <type>', 'Specific type only')
|
||||
.description('Unlink from code-oss')
|
||||
.action(unlink);
|
||||
|
||||
program.parseAsync(process.argv);
|
||||
commander_1.program.version('0.0.1');
|
||||
commander_1.program
|
||||
.command('each <command...>')
|
||||
.option('-t, --type <type>', 'Specific type only')
|
||||
.description('Run a command in each extension repository')
|
||||
.allowUnknownOption()
|
||||
.action(each);
|
||||
commander_1.program.parseAsync(process.argv).catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
|
113
build/ext.ts
Normal file
113
build/ext.ts
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { promises as fs } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
import { program } from 'commander';
|
||||
|
||||
const root = path.resolve(path.join(__dirname, '..'));
|
||||
|
||||
const enum ExtensionType {
|
||||
Grammar = 'grammar',
|
||||
Theme = 'theme',
|
||||
Misc = 'misc'
|
||||
}
|
||||
|
||||
interface IExtension {
|
||||
readonly name: string;
|
||||
readonly path: string;
|
||||
readonly type: ExtensionType;
|
||||
}
|
||||
|
||||
// const exists = (path) => fs.stat(path).then(() => true, () => false);
|
||||
|
||||
// const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
|
||||
// async function readControlFile() {
|
||||
// try {
|
||||
// return JSON.parse(await fs.readFile(controlFilePath, 'utf8'));
|
||||
// } catch (err) {
|
||||
// return {};
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function writeControlFile(control) {
|
||||
// await mkdirp(path.dirname(controlFilePath));
|
||||
// await fs.writeFile(controlFilePath, JSON.stringify(control, null, ' '));
|
||||
// }
|
||||
|
||||
async function exec(cmd: string, args: string[], opts: cp.SpawnOptions = {}): Promise<void> {
|
||||
return new Promise((c, e) => {
|
||||
const child = cp.spawn(cmd, args, { stdio: 'inherit', env: process.env, ...opts });
|
||||
child.on('close', code => code === 0 ? c() : e(`Returned ${code}`));
|
||||
});
|
||||
}
|
||||
|
||||
function getExtensionType(packageJson: any): ExtensionType {
|
||||
if (packageJson.contributes?.themes || packageJson.contributes?.iconThemes) {
|
||||
return ExtensionType.Theme;
|
||||
} else if (packageJson.contributes?.grammars) {
|
||||
return ExtensionType.Grammar;
|
||||
} else {
|
||||
return ExtensionType.Misc;
|
||||
}
|
||||
}
|
||||
|
||||
async function getExtension(extensionPath: string): Promise<IExtension> {
|
||||
const packageJsonPath = path.join(extensionPath, 'package.json');
|
||||
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
||||
const type = getExtensionType(packageJson);
|
||||
|
||||
return {
|
||||
name: packageJson.name,
|
||||
path: extensionPath,
|
||||
type
|
||||
};
|
||||
}
|
||||
|
||||
async function* getExtensions(): AsyncGenerator<IExtension, void, any> {
|
||||
const extensionsPath = path.join(root, 'extensions');
|
||||
const children = await fs.readdir(extensionsPath);
|
||||
|
||||
for (const child of children) {
|
||||
try {
|
||||
yield await getExtension(path.join(extensionsPath, child));
|
||||
} catch (err) {
|
||||
if (/ENOENT|ENOTDIR/.test(err.message)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function each([cmd, ...args]: string[], opts: { type?: string }) {
|
||||
for await (const extension of getExtensions()) {
|
||||
if (opts.type && extension.type !== opts.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`👉 ${extension.name}`);
|
||||
await exec(cmd, args, { cwd: extension.path });
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
program.version('0.0.1');
|
||||
|
||||
program
|
||||
.command('each <command...>')
|
||||
.option('-t, --type <type>', 'Specific type only')
|
||||
.description('Run a command in each extension repository')
|
||||
.allowUnknownOption()
|
||||
.action(each);
|
||||
|
||||
program.parseAsync(process.argv).catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
|
@ -44,6 +44,7 @@ module.exports.indentationFilter = [
|
|||
'!src/vs/base/node/cpuUsage.sh',
|
||||
'!test/unit/assert.js',
|
||||
'!resources/linux/snap/electron-launch',
|
||||
'!build/ext.js',
|
||||
|
||||
// except specific folders
|
||||
'!test/automation/out/**',
|
||||
|
|
Loading…
Reference in a new issue