Skip to content

Commit d706c70

Browse files
committed
code-web: read built-in marketplace extensions
1 parent 135e5d9 commit d706c70

1 file changed

Lines changed: 65 additions & 34 deletions

File tree

resources/serverless/code-web.js

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ const ansiColors = require('ansi-colors');
2020
const extensions = require('../../build/lib/extensions');
2121

2222
const APP_ROOT = path.join(__dirname, '..', '..');
23-
const EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
23+
const BUILTIN_EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
24+
const BUILTIN_MARKETPLACE_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInExtensions');
2425
const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');
2526

2627
const args = minimist(process.argv, {
2728
boolean: [
2829
'no-launch',
29-
'help'
30+
'help',
31+
'verbose'
3032
],
3133
string: [
3234
'scheme',
@@ -46,6 +48,7 @@ if (args.help) {
4648
' --port Remote/Local port\n' +
4749
' --local_port Local port override\n' +
4850
' --extension Path of an extension to include\n' +
51+
' --verbose Print out more information\n' +
4952
' --help\n' +
5053
'[Example]\n' +
5154
' yarn web --scheme https --host example.com --port 8080 --local_port 30000'
@@ -64,18 +67,27 @@ const readFile = (path) => util.promisify(fs.readFile)(path);
6467
const readdir = (path) => util.promisify(fs.readdir)(path);
6568
const readdirWithFileTypes = (path) => util.promisify(fs.readdir)(path, { withFileTypes: true });
6669

67-
async function getBuiltInExtensionInfos(extensionsRoot) {
68-
const builtinExtensions = [];
69-
const children = await readdirWithFileTypes(extensionsRoot);
70-
await Promise.all(children.map(async child => {
71-
if (child.isDirectory()) {
72-
const info = await getBuiltInExtensionInfo(path.join(extensionsRoot, child.name));
73-
if (info) {
74-
builtinExtensions.push(info);
75-
}
70+
async function getBuiltInExtensionInfos() {
71+
const extensions = [];
72+
/** @type {Object.<string, string>} */
73+
const locations = {};
74+
75+
for (const extensionsRoot of [BUILTIN_EXTENSIONS_ROOT, BUILTIN_MARKETPLACE_EXTENSIONS_ROOT]) {
76+
if (await exists(extensionsRoot)) {
77+
const children = await readdirWithFileTypes(extensionsRoot);
78+
await Promise.all(children.map(async child => {
79+
if (child.isDirectory()) {
80+
const extensionPath = path.join(extensionsRoot, child.name);
81+
const info = await getBuiltInExtensionInfo(extensionPath);
82+
if (info) {
83+
extensions.push(info);
84+
locations[path.basename(extensionPath)] = extensionPath;
85+
}
86+
}
87+
}));
7688
}
77-
}));
78-
return builtinExtensions;
89+
}
90+
return { extensions, locations };
7991
}
8092

8193
async function getBuiltInExtensionInfo(extensionPath) {
@@ -106,6 +118,8 @@ async function getBuiltInExtensionInfo(extensionPath) {
106118

107119
async function getDefaultExtensionInfos() {
108120
const extensions = [];
121+
122+
/** @type {Object.<string, string>} */
109123
const locations = {};
110124

111125
let extensionArg = args['extension'];
@@ -166,8 +180,7 @@ async function getExtensionPackageJSON(extensionPath) {
166180
return undefined;
167181
}
168182

169-
170-
const builtinExtensionsPromise = getBuiltInExtensionInfos(EXTENSIONS_ROOT);
183+
const builtInExtensionsPromise = getBuiltInExtensionInfos();
171184
const defaultExtensionsPromise = getDefaultExtensionInfos();
172185

173186
const mapCallbackUriToRequestId = new Map();
@@ -201,8 +214,8 @@ const server = http.createServer((req, res) => {
201214
return handleExtension(req, res, parsedUrl);
202215
}
203216
if (/^\/builtin-extension\//.test(pathname)) {
204-
// builtin extension requests
205-
return handleBuiltinExtension(req, res, parsedUrl);
217+
// built-in extension requests
218+
return handleBuiltInExtension(req, res, parsedUrl);
206219
}
207220
if (pathname === '/') {
208221
// main web
@@ -256,19 +269,10 @@ function handleStatic(req, res, parsedUrl) {
256269
async function handleExtension(req, res, parsedUrl) {
257270
// Strip `/extension/` from the path
258271
const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/extension/'.length));
259-
const firstSlash = relativePath.indexOf('/');
260-
if (firstSlash === -1) {
261-
return serveError(req, res, 400, `Bad request.`);
262-
}
263-
const extensionId = relativePath.substr(0, firstSlash);
264-
const { locations } = await defaultExtensionsPromise;
265-
266-
const extensionPath = locations[extensionId];
267-
if (!extensionPath) {
272+
const filePath = getExtensionFilePath(relativePath, (await defaultExtensionsPromise).locations);
273+
if (!filePath) {
268274
return serveError(req, res, 400, `Bad request.`);
269275
}
270-
271-
const filePath = path.join(extensionPath, relativePath.substr(firstSlash + 1));
272276
return serveFile(req, res, filePath);
273277
}
274278

@@ -277,10 +281,13 @@ async function handleExtension(req, res, parsedUrl) {
277281
* @param {import('http').ServerResponse} res
278282
* @param {import('url').UrlWithParsedQuery} parsedUrl
279283
*/
280-
async function handleBuiltinExtension(req, res, parsedUrl) {
284+
async function handleBuiltInExtension(req, res, parsedUrl) {
281285
// Strip `/builtin-extension/` from the path
282286
const relativePath = decodeURIComponent(parsedUrl.pathname.substr('/builtin-extension/'.length));
283-
const filePath = path.join(EXTENSIONS_ROOT, relativePath);
287+
const filePath = getExtensionFilePath(relativePath, (await builtInExtensionsPromise).locations);
288+
if (!filePath) {
289+
return serveError(req, res, 400, `Bad request.`);
290+
}
284291
return serveFile(req, res, filePath);
285292
}
286293

@@ -316,18 +323,23 @@ async function handleRoot(req, res) {
316323
}
317324
}
318325

319-
const builtinExtensions = await builtinExtensionsPromise;
320-
const { extensions } = await defaultExtensionsPromise;
326+
const { extensions: builtInExtensions } = await builtInExtensionsPromise;
327+
const { extensions: staticExtensions } = await defaultExtensionsPromise;
328+
329+
if (args.verbose) {
330+
fancyLog(`${ansiColors.magenta('BuiltIn extensions')}: ${builtInExtensions.map(e => path.basename(e.extensionPath)).join(', ')}`);
331+
fancyLog(`${ansiColors.magenta('Additional extensions')}: ${staticExtensions.map(e => path.basename(e.extensionLocation.path)).join(', ') || 'None'}`);
332+
}
321333

322334
const webConfigJSON = escapeAttribute(JSON.stringify({
323335
folderUri: folderUri,
324-
staticExtensions: extensions,
336+
staticExtensions,
325337
builtinExtensionsServiceUrl: `${SCHEME}://${AUTHORITY}/builtin-extension`
326338
}));
327339

328340
const data = (await readFile(WEB_MAIN)).toString()
329341
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => webConfigJSON) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied
330-
.replace('{{WORKBENCH_BUILTIN_EXTENSIONS}}', () => escapeAttribute(JSON.stringify(builtinExtensions)))
342+
.replace('{{WORKBENCH_BUILTIN_EXTENSIONS}}', () => escapeAttribute(JSON.stringify(builtInExtensions)))
331343
.replace('{{WEBVIEW_ENDPOINT}}', '')
332344
.replace('{{REMOTE_USER_DATA_URI}}', '');
333345

@@ -436,6 +448,25 @@ function escapeAttribute(value) {
436448
return value.replace(/"/g, '&quot;');
437449
}
438450

451+
/**
452+
* @param {string} relativePath
453+
* @param {Object.<string, string>} locations
454+
* @returns {string | undefined}
455+
*/
456+
function getExtensionFilePath(relativePath, locations) {
457+
const firstSlash = relativePath.indexOf('/');
458+
if (firstSlash === -1) {
459+
return undefined;
460+
}
461+
const extensionId = relativePath.substr(0, firstSlash);
462+
463+
const extensionPath = locations[extensionId];
464+
if (!extensionPath) {
465+
return undefined;
466+
}
467+
return path.join(extensionPath, relativePath.substr(firstSlash + 1));
468+
}
469+
439470
/**
440471
* @param {import('http').IncomingMessage} req
441472
* @param {import('http').ServerResponse} res

0 commit comments

Comments
 (0)