gulpfile.vscode.js 26.1 KB
Newer Older
I
isidor 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

J
Joao Moreno 已提交
6 7 8 9
'use strict';

const gulp = require('gulp');
const fs = require('fs');
10 11
const os = require('os');
const cp = require('child_process');
J
Joao Moreno 已提交
12 13 14 15
const path = require('path');
const es = require('event-stream');
const azure = require('gulp-azure-storage');
const electron = require('gulp-atom-electron');
J
Joao Moreno 已提交
16
const vfs = require('vinyl-fs');
J
Joao Moreno 已提交
17 18 19 20 21 22
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const filter = require('gulp-filter');
const json = require('gulp-json-editor');
const _ = require('underscore');
const util = require('./lib/util');
J
Joao Moreno 已提交
23
const ext = require('./lib/extensions');
J
Joao Moreno 已提交
24
const buildfile = require('../src/buildfile');
25
const common = require('./lib/optimize');
J
Joao Moreno 已提交
26 27
const root = path.dirname(__dirname);
const commit = util.getVersion(root);
J
Joao Moreno 已提交
28 29
const packageJson = require('../package.json');
const product = require('../product.json');
A
Alex Dima 已提交
30
const crypto = require('crypto');
31
const i18n = require('./lib/i18n');
32
const deps = require('./dependencies');
J
Joao Moreno 已提交
33
const getElectronVersion = require('./lib/electron').getElectronVersion;
A
Alex Dima 已提交
34
const createAsar = require('./lib/asar').createAsar;
35
const minimist = require('minimist');
A
Alex Dima 已提交
36
const { compileBuildTask } = require('./gulpfile.compile');
J
Joao Moreno 已提交
37

38
const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
J
Joao Moreno 已提交
39
// @ts-ignore
J
Joao Moreno 已提交
40 41
const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n));
const nodeModules = ['electron', 'original-fs']
42
	// @ts-ignore JSON checking: dependencies property is optional
43 44
	.concat(Object.keys(product.dependencies || {}))
	.concat(_.uniq(productionDependencies.map(d => d.name)))
J
Joao Moreno 已提交
45
	.concat(baseModules);
I
isidor 已提交
46 47

// Build
J
Joao Moreno 已提交
48
const vscodeEntryPoints = _.flatten([
49
	buildfile.entrypoint('vs/workbench/workbench.main'),
I
isidor 已提交
50
	buildfile.base,
51 52
	buildfile.workbench,
	buildfile.code
I
isidor 已提交
53 54
]);

J
Joao Moreno 已提交
55
const vscodeResources = [
J
Joao Moreno 已提交
56
	'out-build/main.js',
J
Joao Moreno 已提交
57
	'out-build/cli.js',
J
Joao Moreno 已提交
58
	'out-build/driver.js',
I
isidor 已提交
59
	'out-build/bootstrap.js',
60
	'out-build/bootstrap-fork.js',
J
Joao Moreno 已提交
61
	'out-build/bootstrap-amd.js',
62
	'out-build/bootstrap-window.js',
J
Joao Moreno 已提交
63
	'out-build/paths.js',
J
Joao Moreno 已提交
64
	'out-build/vs/**/*.{svg,png,cur,html}',
65
	'out-build/vs/base/common/performance.js',
66
	'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
67
	'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
I
isidor 已提交
68 69 70
	'out-build/vs/workbench/browser/media/*-theme.css',
	'out-build/vs/workbench/parts/debug/**/*.json',
	'out-build/vs/workbench/parts/execution/**/*.scpt',
71
	'out-build/vs/workbench/parts/webview/electron-browser/webview-pre.js',
J
Joao Moreno 已提交
72
	'out-build/vs/**/markdown.css',
I
isidor 已提交
73
	'out-build/vs/workbench/parts/tasks/**/*.json',
74
	'out-build/vs/workbench/parts/welcome/walkThrough/**/*.md',
I
isidor 已提交
75 76
	'out-build/vs/workbench/services/files/**/*.exe',
	'out-build/vs/workbench/services/files/**/*.md',
77
	'out-build/vs/code/electron-browser/workbench/**',
78
	'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
79
	'out-build/vs/code/electron-browser/issue/issueReporter.js',
80
	'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
I
isidor 已提交
81 82 83
	'!**/test/**'
];

J
Joao Moreno 已提交
84
const BUNDLED_FILE_HEADER = [
I
isidor 已提交
85 86 87 88 89
	'/*!--------------------------------------------------------',
	' * Copyright (C) Microsoft Corporation. All rights reserved.',
	' *--------------------------------------------------------*/'
].join('\n');

A
Alex Dima 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
const optimizeVSCodeTask = util.task.series(
	util.task.parallel(
		util.rimraf('out-vscode'),
		compileBuildTask
	),
	common.optimizeTask({
		src: 'out-build',
		entryPoints: vscodeEntryPoints,
		otherSources: [],
		resources: vscodeResources,
		loaderConfig: common.loaderConfig(nodeModules),
		header: BUNDLED_FILE_HEADER,
		out: 'out-vscode',
		bundleInfo: undefined
	})
A
Alex Dima 已提交
105
);
A
Alex Dima 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118
optimizeVSCodeTask.displayName = 'optimize-vscode';


const optimizeIndexJSTask = util.task.series(
	optimizeVSCodeTask,
	() => {
		const fullpath = path.join(process.cwd(), 'out-vscode/bootstrap-window.js');
		const contents = fs.readFileSync(fullpath).toString();
		const newContents = contents.replace('[/*BUILD->INSERT_NODE_MODULES*/]', JSON.stringify(nodeModules));
		fs.writeFileSync(fullpath, newContents);
	}
);
optimizeIndexJSTask.displayName = 'optimize-index-js';
119

120
const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`;
A
Alex Dima 已提交
121 122 123 124 125 126 127 128
const minifyVSCodeTask = util.task.series(
	util.task.parallel(
		util.rimraf('out-vscode-min'),
		optimizeIndexJSTask
	),
	common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`)
);
minifyVSCodeTask.displayName = 'minify-vscode';
I
isidor 已提交
129 130

// Package
131 132

// @ts-ignore JSON checking: darwinCredits is optional
J
Joao Moreno 已提交
133
const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8'));
I
isidor 已提交
134

135 136 137 138 139 140 141 142 143 144
function darwinBundleDocumentType(extensions, icon) {
	return {
		name: product.nameLong + ' document',
		role: 'Editor',
		ostypes: ["TEXT", "utxt", "TUTX", "****"],
		extensions: extensions,
		iconFile: icon
	};
}

J
Joao Moreno 已提交
145
const config = {
J
Joao Moreno 已提交
146
	version: getElectronVersion(),
I
isidor 已提交
147
	productAppName: product.nameLong,
J
Joao Moreno 已提交
148
	companyName: 'Microsoft Corporation',
H
Henk Mollema 已提交
149
	copyright: 'Copyright (C) 2019 Microsoft. All rights reserved',
J
Joao Moreno 已提交
150
	darwinIcon: 'resources/darwin/code.icns',
I
isidor 已提交
151
	darwinBundleIdentifier: product.darwinBundleIdentifier,
J
Joao Moreno 已提交
152
	darwinApplicationCategoryType: 'public.app-category.developer-tools',
153 154
	darwinHelpBookFolder: 'VS Code HelpBook',
	darwinHelpBookName: 'VS Code HelpBook',
155 156 157 158 159 160 161 162 163
	darwinBundleDocumentTypes: [
		darwinBundleDocumentType(["bat", "cmd"], 'resources/darwin/bat.icns'),
		darwinBundleDocumentType(["bowerrc"], 'resources/darwin/bower.icns'),
		darwinBundleDocumentType(["c", "h"], 'resources/darwin/c.icns'),
		darwinBundleDocumentType(["config", "editorconfig", "gitattributes", "gitconfig", "gitignore", "ini"], 'resources/darwin/config.icns'),
		darwinBundleDocumentType(["cc", "cpp", "cxx", "hh", "hpp", "hxx"], 'resources/darwin/cpp.icns'),
		darwinBundleDocumentType(["cs", "csx"], 'resources/darwin/csharp.icns'),
		darwinBundleDocumentType(["css"], 'resources/darwin/css.icns'),
		darwinBundleDocumentType(["go"], 'resources/darwin/go.icns'),
B
Benjamin Pasero 已提交
164
		darwinBundleDocumentType(["asp", "aspx", "cshtml", "htm", "html", "jshtm", "jsp", "phtml", "shtml"], 'resources/darwin/html.icns'),
165 166
		darwinBundleDocumentType(["jade"], 'resources/darwin/jade.icns'),
		darwinBundleDocumentType(["jav", "java"], 'resources/darwin/java.icns'),
B
Benjamin Pasero 已提交
167
		darwinBundleDocumentType(["js", "jscsrc", "jshintrc", "mjs"], 'resources/darwin/javascript.icns'),
168 169 170 171 172 173 174
		darwinBundleDocumentType(["json"], 'resources/darwin/json.icns'),
		darwinBundleDocumentType(["less"], 'resources/darwin/less.icns'),
		darwinBundleDocumentType(["markdown", "md", "mdoc", "mdown", "mdtext", "mdtxt", "mdwn", "mkd", "mkdn"], 'resources/darwin/markdown.icns'),
		darwinBundleDocumentType(["php"], 'resources/darwin/php.icns'),
		darwinBundleDocumentType(["ps1", "psd1", "psm1"], 'resources/darwin/powershell.icns'),
		darwinBundleDocumentType(["py"], 'resources/darwin/python.icns'),
		darwinBundleDocumentType(["gemspec", "rb"], 'resources/darwin/ruby.icns'),
M
Miguel Solorio 已提交
175
		darwinBundleDocumentType(["scss"], 'resources/darwin/sass.icns'),
176 177 178 179 180 181 182
		darwinBundleDocumentType(["bash", "bash_login", "bash_logout", "bash_profile", "bashrc", "profile", "rhistory", "rprofile", "sh", "zlogin", "zlogout", "zprofile", "zsh", "zshenv", "zshrc"], 'resources/darwin/shell.icns'),
		darwinBundleDocumentType(["sql"], 'resources/darwin/sql.icns'),
		darwinBundleDocumentType(["ts"], 'resources/darwin/typescript.icns'),
		darwinBundleDocumentType(["tsx", "jsx"], 'resources/darwin/react.icns'),
		darwinBundleDocumentType(["vue"], 'resources/darwin/vue.icns'),
		darwinBundleDocumentType(["ascx", "csproj", "dtd", "wxi", "wxl", "wxs", "xml", "xaml"], 'resources/darwin/xml.icns'),
		darwinBundleDocumentType(["eyaml", "eyml", "yaml", "yml"], 'resources/darwin/yaml.icns'),
B
Benjamin Pasero 已提交
183
		darwinBundleDocumentType(["clj", "cljs", "cljx", "clojure", "code-workspace", "coffee", "ctp", "dockerfile", "dot", "edn", "fs", "fsi", "fsscript", "fsx", "handlebars", "hbs", "lua", "m", "makefile", "ml", "mli", "pl", "pl6", "pm", "pm6", "pod", "pp", "properties", "psgi", "pug", "r", "rs", "rt", "svg", "svgz", "t", "txt", "vb", "xcodeproj", "xcworkspace"], 'resources/darwin/default.icns')
184
	],
J
Joao Moreno 已提交
185 186 187
	darwinBundleURLTypes: [{
		role: 'Viewer',
		name: product.nameLong,
J
Joao Moreno 已提交
188
		urlSchemes: [product.urlProtocol]
J
Joao Moreno 已提交
189
	}],
190
	darwinForceDarkModeSupport: true,
R
Rob Lourens 已提交
191
	darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined,
192
	linuxExecutableName: product.applicationName,
J
Joao Moreno 已提交
193
	winIcon: 'resources/win32/code.ico',
R
Rob Lourens 已提交
194
	token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined,
195 196

	// @ts-ignore JSON checking: electronRepository is optional
R
Rob Lourens 已提交
197
	repo: product.electronRepository || undefined
I
isidor 已提交
198 199
};

J
fix es6  
Joao Moreno 已提交
200
function getElectron(arch) {
J
Joao Moreno 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
	return () => {
		const electronOpts = _.extend({}, config, {
			platform: process.platform,
			arch,
			ffmpegChromium: true,
			keepDefaultApp: true
		});

		return gulp.src('package.json')
			.pipe(json({ name: product.nameShort }))
			.pipe(electron(electronOpts))
			.pipe(filter(['**', '!**/app/package.json']))
			.pipe(vfs.dest('.build/electron'));
	};
}
216

A
Alex Dima 已提交
217 218 219 220 221
gulp.task('electron', util.task.series(util.rimraf('.build/electron'), getElectron(process.arch)));
gulp.task('electron-ia32', util.task.series(util.rimraf('.build/electron'), getElectron('ia32')));
gulp.task('electron-x64', util.task.series(util.rimraf('.build/electron'), getElectron('x64')));
gulp.task('electron-arm', util.task.series(util.rimraf('.build/electron'), getElectron('arm')));
gulp.task('electron-arm64', util.task.series(util.rimraf('.build/electron'), getElectron('arm64')));
I
isidor 已提交
222 223


A
Alex Dima 已提交
224 225 226 227 228 229 230 231 232
/**
 * Compute checksums for some files.
 *
 * @param {string} out The out folder to read the file from.
 * @param {string[]} filenames The paths to compute a checksum for.
 * @return {Object} A map of paths to checksums.
 */
function computeChecksums(out, filenames) {
	var result = {};
233
	filenames.forEach(function (filename) {
A
Alex Dima 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
		var fullPath = path.join(process.cwd(), out, filename);
		result[filename] = computeChecksum(fullPath);
	});
	return result;
}

/**
 * Compute checksum for a file.
 *
 * @param {string} filename The absolute path to a filename.
 * @return {string} The checksum for `filename`.
 */
function computeChecksum(filename) {
	var contents = fs.readFileSync(filename);

	var hash = crypto
		.createHash('md5')
		.update(contents)
		.digest('base64')
		.replace(/=+$/, '');

	return hash;
}

A
Alex Dima 已提交
258
function packageTask(platform, arch, sourceFolderName, destinationFolderName, opts) {
J
fix es6  
Joao Moreno 已提交
259 260
	opts = opts || {};

A
Alex Dima 已提交
261
	const destination = path.join(path.dirname(root), destinationFolderName);
I
isidor 已提交
262 263
	platform = platform || process.platform;

J
Joao Moreno 已提交
264
	return () => {
A
Alex Dima 已提交
265
		const out = sourceFolderName;
I
isidor 已提交
266

A
Alex Dima 已提交
267
		const checksums = computeChecksums(out, [
268 269
			'vs/workbench/workbench.main.js',
			'vs/workbench/workbench.main.css',
270 271
			'vs/code/electron-browser/workbench/workbench.html',
			'vs/code/electron-browser/workbench/workbench.js'
A
Alex Dima 已提交
272 273
		]);

J
Joao Moreno 已提交
274
		const src = gulp.src(out + '/**', { base: '.' })
275 276 277
			.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); }))
			.pipe(util.setExecutableBit(['**/*.sh']))
			.pipe(filter(['**', '!**/*.js.map']));
I
isidor 已提交
278

279 280
		const root = path.resolve(path.join(__dirname, '..'));

281 282
		const sources = es.merge(src, ext.packageExtensionsStream({
			sourceMappingURLBase: sourceMappingURLBase
283 284
		}));

J
Joao Moreno 已提交
285
		let version = packageJson.version;
286
		// @ts-ignore JSON checking: quality is optional
J
Joao Moreno 已提交
287
		const quality = product.quality;
J
Joao Moreno 已提交
288 289 290 291 292

		if (quality && quality !== 'stable') {
			version += '-' + quality;
		}

J
Joao Moreno 已提交
293
		const name = product.nameShort;
294 295 296 297 298 299 300
		const packageJsonUpdates = { name, version };

		// for linux url handling
		if (platform === 'linux') {
			packageJsonUpdates.desktopName = `${product.applicationName}-url-handler.desktop`;
		}

J
Joao Moreno 已提交
301
		const packageJsonStream = gulp.src(['package.json'], { base: '.' })
302
			.pipe(json(packageJsonUpdates));
J
Joao Moreno 已提交
303 304

		const date = new Date().toISOString();
305 306
		const productJsonUpdate = { commit, date, checksums };

307
		if (shouldSetupSettingsSearch()) {
308 309 310
			productJsonUpdate.settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
		}

J
Joao Moreno 已提交
311
		const productJsonStream = gulp.src(['product.json'], { base: '.' })
312
			.pipe(json(productJsonUpdate));
I
isidor 已提交
313

314
		const license = gulp.src(['LICENSES.chromium.html', 'LICENSE.txt', 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.' });
I
isidor 已提交
315

316 317
		const watermark = gulp.src(['resources/letterpress.svg', 'resources/letterpress-dark.svg', 'resources/letterpress-hc.svg'], { base: '.' });

J
Joao Moreno 已提交
318 319 320
		// TODO the API should be copied to `out` during compile, not here
		const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts'));

321 322
		const depsSrc = [
			..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])),
323
			// @ts-ignore JSON checking: dependencies is optional
324 325
			..._.flatten(Object.keys(product.dependencies || {}).map(d => [`node_modules/${d}/**`, `!node_modules/${d}/**/{test,tests}/**`]))
		];
I
isidor 已提交
326

J
Joao Moreno 已提交
327
		const deps = gulp.src(depsSrc, { base: '.', dot: true })
J
Joao Moreno 已提交
328
			.pipe(filter(['**', '!**/package-lock.json']))
J
Joao Moreno 已提交
329
			.pipe(util.cleanNodeModule('fsevents', ['binding.gyp', 'fsevents.cc', 'build/**', 'src/**', 'test/**'], ['**/*.node']))
330 331
			.pipe(util.cleanNodeModule('vscode-sqlite3', ['binding.gyp', 'benchmark/**', 'cloudformation/**', 'deps/**', 'test/**', 'build/**', 'src/**'], ['build/Release/*.node']))
			.pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/*.js']))
J
Joao Moreno 已提交
332
			.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
333 334 335 336
			.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node']))
			.pipe(util.cleanNodeModule('native-is-elevated', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node']))
			.pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['build/Release/*.node']))
			.pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['build/Release/*.node']))
B
Benjamin Pasero 已提交
337
			.pipe(util.cleanNodeModule('jschardet', ['dist/**']))
338
			.pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
A
Amy Qiu 已提交
339
			.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
340
			.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/index.js']))
C
Christof Marti 已提交
341
			.pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node']))
342
			.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node']))
343
			.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a']))
A
Alex Dima 已提交
344 345
			.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
			.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
I
isidor 已提交
346

J
Joao Moreno 已提交
347
		let all = es.merge(
J
Joao Moreno 已提交
348
			packageJsonStream,
J
Joao Moreno 已提交
349
			productJsonStream,
I
isidor 已提交
350
			license,
351
			watermark,
J
Joao Moreno 已提交
352
			api,
I
isidor 已提交
353
			sources,
J
Joao Moreno 已提交
354
			deps
J
Joao Moreno 已提交
355 356 357
		);

		if (platform === 'win32') {
J
Joao Moreno 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
			all = es.merge(all, gulp.src([
				'resources/win32/bower.ico',
				'resources/win32/c.ico',
				'resources/win32/config.ico',
				'resources/win32/cpp.ico',
				'resources/win32/csharp.ico',
				'resources/win32/css.ico',
				'resources/win32/default.ico',
				'resources/win32/go.ico',
				'resources/win32/html.ico',
				'resources/win32/jade.ico',
				'resources/win32/java.ico',
				'resources/win32/javascript.ico',
				'resources/win32/json.ico',
				'resources/win32/less.ico',
				'resources/win32/markdown.ico',
				'resources/win32/php.ico',
				'resources/win32/powershell.ico',
				'resources/win32/python.ico',
				'resources/win32/react.ico',
				'resources/win32/ruby.ico',
				'resources/win32/sass.ico',
				'resources/win32/shell.ico',
				'resources/win32/sql.ico',
				'resources/win32/typescript.ico',
				'resources/win32/vue.ico',
				'resources/win32/xml.ico',
				'resources/win32/yaml.ico',
				'resources/win32/code_70x70.png',
				'resources/win32/code_150x150.png'
			], { base: '.' }));
J
Joao Moreno 已提交
389 390
		} else if (platform === 'linux') {
			all = es.merge(all, gulp.src('resources/linux/code.png', { base: '.' }));
J
Joao Moreno 已提交
391
		} else if (platform === 'darwin') {
J
Joao Moreno 已提交
392
			const shortcut = gulp.src('resources/darwin/bin/code.sh')
J
Joao Moreno 已提交
393 394 395
				.pipe(rename('bin/code'));

			all = es.merge(all, shortcut);
J
Joao Moreno 已提交
396
		}
I
isidor 已提交
397

J
Joao Moreno 已提交
398
		let result = all
J
Joao Moreno 已提交
399
			.pipe(util.skipDirectories())
I
isidor 已提交
400
			.pipe(util.fixWin32DirectoryPermissions())
401
			.pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true })))
402
			.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version']));
I
isidor 已提交
403

J
Joao Moreno 已提交
404
		// result = es.merge(result, gulp.src('resources/completions/**', { base: '.' }));
405

I
isidor 已提交
406
		if (platform === 'win32') {
J
typo  
João Moreno 已提交
407
			result = es.merge(result, gulp.src('resources/win32/bin/code.js', { base: 'resources/win32' }));
J
Joao Moreno 已提交
408

J
typo  
João Moreno 已提交
409
			result = es.merge(result, gulp.src('resources/win32/bin/code.cmd', { base: 'resources/win32' })
J
Joao Moreno 已提交
410
				.pipe(replace('@@NAME@@', product.nameShort))
J
Joao Moreno 已提交
411 412
				.pipe(rename(function (f) { f.basename = product.applicationName; })));

J
typo  
João Moreno 已提交
413
			result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' })
J
Joao Moreno 已提交
414
				.pipe(replace('@@NAME@@', product.nameShort))
A
Alex Dima 已提交
415 416
				.pipe(replace('@@COMMIT@@', commit))
				.pipe(replace('@@APPNAME@@', product.applicationName))
J
Joao Moreno 已提交
417
				.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
418 419

			result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
420
				.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
421 422 423 424
		} else if (platform === 'linux') {
			result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' })
				.pipe(replace('@@NAME@@', product.applicationName))
				.pipe(rename('bin/' + product.applicationName)));
I
isidor 已提交
425 426
		}

J
Johannes Rieken 已提交
427 428 429 430 431
		// submit all stats that have been collected
		// during the build phase
		if (opts.stats) {
			result.on('end', () => {
				const { submitAllStats } = require('./lib/stats');
J
Johannes Rieken 已提交
432
				submitAllStats(product, commit).then(() => console.log('Submitted bundle stats!'));
J
Johannes Rieken 已提交
433 434 435
			});
		}

J
Joao Moreno 已提交
436
		return result.pipe(vfs.dest(destination));
I
isidor 已提交
437 438 439
	};
}

J
Joao Moreno 已提交
440 441
const buildRoot = path.dirname(root);

A
Alex Dima 已提交
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
const BUILD_TARGETS = [
	{ platform: 'win32', arch: 'ia32' },
	{ platform: 'win32', arch: 'x64' },
	{ platform: 'darwin', arch: null, opts: { stats: true } },
	{ platform: 'linux', arch: 'ia32' },
	{ platform: 'linux', arch: 'x64' },
	{ platform: 'linux', arch: 'arm' },
	{ platform: 'linux', arch: 'arm64' },
];
BUILD_TARGETS.forEach(buildTarget => {
	const dashed = (str) => (str ? `-${str}` : ``);
	const platform = buildTarget.platform;
	const arch = buildTarget.arch;
	const opts = buildTarget.opts;

	['', 'min'].forEach(minified => {
		const sourceFolderName = `out-vscode${dashed(minified)}`;
		const destinationFolderName = `VSCode${dashed(platform)}${dashed(arch)}`;

		const vscodeTask = util.task.series(
			util.task.parallel(
				minified ? minifyVSCodeTask : optimizeVSCodeTask,
				util.rimraf(path.join(buildRoot, destinationFolderName))
			),
			packageTask(platform, arch, sourceFolderName, destinationFolderName, opts)
		);
		vscodeTask.displayName = `vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`;
		gulp.task(vscodeTask.displayName, vscodeTask);
	});
});
I
isidor 已提交
472

473
// Transifex Localizations
D
Dirk Baeumer 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

const innoSetupConfig = {
	'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } },
	'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } },
	'ko': { codePage: 'CP949', defaultInfo: { name: 'Korean', id: '$0412' } },
	'ja': { codePage: 'CP932' },
	'de': { codePage: 'CP1252' },
	'fr': { codePage: 'CP1252' },
	'es': { codePage: 'CP1252' },
	'ru': { codePage: 'CP1251' },
	'it': { codePage: 'CP1252' },
	'pt-br': { codePage: 'CP1252' },
	'hu': { codePage: 'CP1250' },
	'tr': { codePage: 'CP1254' }
};
489

490
const apiHostname = process.env.TRANSIFEX_API_URL;
491 492 493
const apiName = process.env.TRANSIFEX_API_NAME;
const apiToken = process.env.TRANSIFEX_API_TOKEN;

A
Alex Dima 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
gulp.task('vscode-translations-push',
	util.task.series(
		optimizeVSCodeTask,
		function () {
			const pathToMetadata = './out-vscode/nls.metadata.json';
			const pathToExtensions = './extensions/*';
			const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';

			return es.merge(
				gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
				gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
				gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
			).pipe(i18n.findObsoleteResources(apiHostname, apiName, apiToken)
			).pipe(i18n.pushXlfFiles(apiHostname, apiName, apiToken));
		}
	)
);
D
Dirk Baeumer 已提交
511

A
Alex Dima 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
gulp.task('vscode-translations-export',
	util.task.series(
		optimizeVSCodeTask,
		function () {
			const pathToMetadata = './out-vscode/nls.metadata.json';
			const pathToExtensions = './extensions/*';
			const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}';

			return es.merge(
				gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()),
				gulp.src(pathToSetup).pipe(i18n.createXlfFilesForIsl()),
				gulp.src(pathToExtensions).pipe(i18n.createXlfFilesForExtensions())
			).pipe(vfs.dest('../vscode-translations-export'));
		}
	)
);
D
Dirk Baeumer 已提交
528 529

gulp.task('vscode-translations-pull', function () {
530
	return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => {
D
Dirk Baeumer 已提交
531
		let includeDefault = !!innoSetupConfig[language.id].defaultInfo;
532
		return i18n.pullSetupXlfFiles(apiHostname, apiName, apiToken, language, includeDefault).pipe(vfs.dest(`../vscode-translations-import/${language.id}/setup`));
533
	}));
534 535
});

536
gulp.task('vscode-translations-import', function () {
537 538 539 540 541 542
	var options = minimist(process.argv.slice(2), {
		string: 'location',
		default: {
			location: '../vscode-translations-import'
		}
	});
543
	return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => {
544 545
		let id = language.transifexId || language.id;
		return gulp.src(`${options.location}/${id}/setup/*/*.xlf`)
D
Dirk Baeumer 已提交
546 547
			.pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
			.pipe(vfs.dest(`./build/win32/i18n`));
548
	}));
549 550
});

I
isidor 已提交
551 552
// Sourcemaps

553
gulp.task('upload-vscode-sourcemaps', () => {
J
Joao Moreno 已提交
554 555
	const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' })
		.pipe(es.mapSync(f => {
556
			f.path = `${f.base}/core/${f.relative}`;
J
Joao Moreno 已提交
557 558 559
			return f;
		}));

560 561
	const extensionsOut = gulp.src('extensions/**/out/**/*.map', { base: '.' });
	const extensionsDist = gulp.src('extensions/**/dist/**/*.map', { base: '.' });
J
Joao Moreno 已提交
562

563
	return es.merge(vs, extensionsOut, extensionsDist)
J
Johannes Rieken 已提交
564 565 566 567 568
		.pipe(es.through(function (data) {
			// debug
			console.log('Uploading Sourcemap', data.relative);
			this.emit('data', data);
		}))
I
isidor 已提交
569 570 571 572
		.pipe(azure.upload({
			account: process.env.AZURE_STORAGE_ACCOUNT,
			key: process.env.AZURE_STORAGE_ACCESS_KEY,
			container: 'sourcemaps',
J
Joao Moreno 已提交
573
			prefix: commit + '/'
I
isidor 已提交
574
		}));
575
});
576

577
// This task is only run for the MacOS build
A
Alex Dima 已提交
578
const generateVSCodeConfigurationTask = () => {
579 580 581 582 583 584
	return new Promise((resolve, reject) => {
		const buildDir = process.env['AGENT_BUILDDIRECTORY'];
		if (!buildDir) {
			return reject(new Error('$AGENT_BUILDDIRECTORY not set'));
		}

J
Joao Moreno 已提交
585 586 587 588
		if (process.env.VSCODE_QUALITY !== 'insider' && process.env.VSCODE_QUALITY !== 'stable') {
			return resolve();
		}

589 590
		const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
		const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
591 592
		const appName = process.env.VSCODE_QUALITY === 'insider' ? 'Visual\\ Studio\\ Code\\ -\\ Insiders.app' : 'Visual\\ Studio\\ Code.app';
		const appPath = path.join(buildDir, `VSCode-darwin/${appName}/Contents/Resources/app/bin/code`);
593
		const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
594 595 596

		const timer = setTimeout(() => {
			codeProc.kill();
597
			reject(new Error('export-default-configuration process timed out'));
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
		}, 10 * 1000);

		codeProc.stdout.on('data', d => console.log(d.toString()));
		codeProc.stderr.on('data', d => console.log(d.toString()));

		codeProc.on('exit', () => {
			clearTimeout(timer);
			resolve();
		});

		codeProc.on('error', err => {
			clearTimeout(timer);
			reject(err);
		});
	});
A
Alex Dima 已提交
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
};
generateVSCodeConfigurationTask.displayName = 'generate-vscode-configuration';

const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
gulp.task('upload-vscode-configuration',
	util.task.series(
		generateVSCodeConfigurationTask,
		() => {
			if (!shouldSetupSettingsSearch()) {
				const branch = process.env.BUILD_SOURCEBRANCH;
				console.log(`Only runs on master and release branches, not ${branch}`);
				return;
			}

			if (!fs.existsSync(allConfigDetailsPath)) {
				throw new Error(`configuration file at ${allConfigDetailsPath} does not exist`);
			}

			const settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
			if (!settingsSearchBuildId) {
				throw new Error('Failed to compute build number');
			}

			return gulp.src(allConfigDetailsPath)
				.pipe(azure.upload({
					account: process.env.AZURE_STORAGE_ACCOUNT,
					key: process.env.AZURE_STORAGE_ACCESS_KEY,
					container: 'configuration',
					prefix: `${settingsSearchBuildId}/${commit}/`
				}));
		}
	)
);

function shouldSetupSettingsSearch() {
	const branch = process.env.BUILD_SOURCEBRANCH;
	return branch && (/\/master$/.test(branch) || branch.indexOf('/release/') >= 0);
}

function getSettingsSearchBuildId(packageJson) {
	try {
		const branch = process.env.BUILD_SOURCEBRANCH;
		const branchId = branch.indexOf('/release/') >= 0 ? 0 :
			/\/master$/.test(branch) ? 1 :
				2; // Some unexpected branch

		const out = cp.execSync(`git rev-list HEAD --count`);
		const count = parseInt(out.toString());

		// <version number><commit count><branchId (avoid unlikely conflicts)>
		// 1.25.1, 1,234,567 commits, master = 1250112345671
		return util.versionStringToNumber(packageJson.version) * 1e8 + count * 10 + branchId;
	} catch (e) {
		throw new Error('Could not determine build number: ' + e.toString());
	}
}