Skip to content

Commit

Permalink
adopt built-in extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
joaomoreno committed Feb 1, 2021
1 parent ec805db commit 38db177
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 194 deletions.
308 changes: 114 additions & 194 deletions build/ext.js
Original file line number Diff line number Diff line change
@@ -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}`));
});
}

function getFolderPath(extDesc) {
const folder = extDesc.repo.replace(/.*\//, '');
return folderPath = path.join(root, folder);
}

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';
}
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}`));
});
}

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 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 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 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 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;
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 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 });
}
}

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}`);
});
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; }
}
}

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);
});
}
Loading

0 comments on commit 38db177

Please sign in to comment.