eae5d8c807
These conflicts will be resolved in the following commits. We do it this way so that PR review is possible.
164 lines
5.2 KiB
TypeScript
164 lines
5.2 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as os from 'os';
|
|
import * as rimraf from 'rimraf';
|
|
import * as es from 'event-stream';
|
|
import * as rename from 'gulp-rename';
|
|
import * as vfs from 'vinyl-fs';
|
|
import * as ext from './extensions';
|
|
import * as fancyLog from 'fancy-log';
|
|
import * as ansiColors from 'ansi-colors';
|
|
import { Stream } from 'stream';
|
|
|
|
const mkdirp = require('mkdirp');
|
|
|
|
interface IExtensionDefinition {
|
|
name: string;
|
|
version: string;
|
|
repo: string;
|
|
platforms?: string[];
|
|
metadata: {
|
|
id: string;
|
|
publisherId: {
|
|
publisherId: string;
|
|
publisherName: string;
|
|
displayName: string;
|
|
flags: string;
|
|
};
|
|
publisherDisplayName: string;
|
|
}
|
|
}
|
|
|
|
const root = path.dirname(path.dirname(__dirname));
|
|
const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8'));
|
|
const builtInExtensions = <IExtensionDefinition[]>productjson.builtInExtensions;
|
|
const webBuiltInExtensions = <IExtensionDefinition[]>productjson.webBuiltInExtensions;
|
|
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
|
const ENABLE_LOGGING = !process.env['VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE'];
|
|
|
|
function log(...messages: string[]): void {
|
|
if (ENABLE_LOGGING) {
|
|
fancyLog(...messages);
|
|
}
|
|
}
|
|
|
|
function getExtensionPath(extension: IExtensionDefinition): string {
|
|
return path.join(root, '.build', 'builtInExtensions', extension.name);
|
|
}
|
|
|
|
function isUpToDate(extension: IExtensionDefinition): boolean {
|
|
const packagePath = path.join(getExtensionPath(extension), 'package.json');
|
|
|
|
if (!fs.existsSync(packagePath)) {
|
|
return false;
|
|
}
|
|
|
|
const packageContents = fs.readFileSync(packagePath, { encoding: 'utf8' });
|
|
|
|
try {
|
|
const diskVersion = JSON.parse(packageContents).version;
|
|
return (diskVersion === extension.version);
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function syncMarketplaceExtension(extension: IExtensionDefinition): Stream {
|
|
if (isUpToDate(extension)) {
|
|
log(ansiColors.blue('[marketplace]'), `${extension.name}@${extension.version}`, ansiColors.green('✔︎'));
|
|
return es.readArray([]);
|
|
}
|
|
|
|
rimraf.sync(getExtensionPath(extension));
|
|
|
|
return ext.fromMarketplace(extension.name, extension.version, extension.metadata)
|
|
.pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`))
|
|
.pipe(vfs.dest('.build/builtInExtensions'))
|
|
.on('end', () => log(ansiColors.blue('[marketplace]'), extension.name, ansiColors.green('✔︎')));
|
|
}
|
|
|
|
function syncExtension(extension: IExtensionDefinition, controlState: 'disabled' | 'marketplace'): Stream {
|
|
if (extension.platforms) {
|
|
const platforms = new Set(extension.platforms);
|
|
|
|
if (!platforms.has(process.platform)) {
|
|
log(ansiColors.gray('[skip]'), `${extension.name}@${extension.version}: Platform '${process.platform}' not supported: [${extension.platforms}]`, ansiColors.green('✔︎'));
|
|
return es.readArray([]);
|
|
}
|
|
}
|
|
|
|
switch (controlState) {
|
|
case 'disabled':
|
|
log(ansiColors.blue('[disabled]'), ansiColors.gray(extension.name));
|
|
return es.readArray([]);
|
|
|
|
case 'marketplace':
|
|
return syncMarketplaceExtension(extension);
|
|
|
|
default:
|
|
if (!fs.existsSync(controlState)) {
|
|
log(ansiColors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but that path does not exist.`));
|
|
return es.readArray([]);
|
|
|
|
} else if (!fs.existsSync(path.join(controlState, 'package.json'))) {
|
|
log(ansiColors.red(`Error: Built-in extension '${extension.name}' is configured to run from '${controlState}' but there is no 'package.json' file in that directory.`));
|
|
return es.readArray([]);
|
|
}
|
|
|
|
log(ansiColors.blue('[local]'), `${extension.name}: ${ansiColors.cyan(controlState)}`, ansiColors.green('✔︎'));
|
|
return es.readArray([]);
|
|
}
|
|
}
|
|
|
|
interface IControlFile {
|
|
[name: string]: 'disabled' | 'marketplace';
|
|
}
|
|
|
|
function readControlFile(): IControlFile {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(controlFilePath, 'utf8'));
|
|
} catch (err) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function writeControlFile(control: IControlFile): void {
|
|
mkdirp.sync(path.dirname(controlFilePath));
|
|
fs.writeFileSync(controlFilePath, JSON.stringify(control, null, 2));
|
|
}
|
|
|
|
export function getBuiltInExtensions(): Promise<void> {
|
|
log('Syncronizing built-in extensions...');
|
|
log(`You can manage built-in extensions with the ${ansiColors.cyan('--builtin')} flag`);
|
|
|
|
const control = readControlFile();
|
|
const streams: Stream[] = [];
|
|
|
|
for (const extension of [...builtInExtensions, ...webBuiltInExtensions]) {
|
|
let controlState = control[extension.name] || 'marketplace';
|
|
control[extension.name] = controlState;
|
|
|
|
streams.push(syncExtension(extension, controlState));
|
|
}
|
|
|
|
writeControlFile(control);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
es.merge(streams)
|
|
.on('error', reject)
|
|
.on('end', resolve);
|
|
});
|
|
}
|
|
|
|
if (require.main === module) {
|
|
getBuiltInExtensions().then(() => process.exit(0)).catch(err => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|
|
}
|