gulpfile.vscode.js 24.6 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');
A
Alex Dima 已提交
23
const task = require('./lib/task');
J
Joao Moreno 已提交
24
const ext = require('./lib/extensions');
J
Joao Moreno 已提交
25
const buildfile = require('../src/buildfile');
26
const common = require('./lib/optimize');
J
Joao Moreno 已提交
27 28
const root = path.dirname(__dirname);
const commit = util.getVersion(root);
J
Joao Moreno 已提交
29 30
const packageJson = require('../package.json');
const product = require('../product.json');
A
Alex Dima 已提交
31
const crypto = require('crypto');
32
const i18n = require('./lib/i18n');
33
const deps = require('./dependencies');
J
Joao Moreno 已提交
34
const getElectronVersion = require('./lib/electron').getElectronVersion;
A
Alex Dima 已提交
35
const createAsar = require('./lib/asar').createAsar;
36
const minimist = require('minimist');
A
Alex Dima 已提交
37
const { compileBuildTask } = require('./gulpfile.compile');
J
Joao Moreno 已提交
38

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

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

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

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

94
const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
A
Alex Dima 已提交
95
	task.parallel(
A
Alex Dima 已提交
96 97 98 99 100 101 102 103 104 105 106 107
		util.rimraf('out-vscode'),
		compileBuildTask
	),
	common.optimizeTask({
		src: 'out-build',
		entryPoints: vscodeEntryPoints,
		resources: vscodeResources,
		loaderConfig: common.loaderConfig(nodeModules),
		header: BUNDLED_FILE_HEADER,
		out: 'out-vscode',
		bundleInfo: undefined
	})
108
));
A
Alex Dima 已提交
109 110


111
const optimizeIndexJSTask = task.define('optimize-index-js', task.series(
A
Alex Dima 已提交
112 113 114 115 116 117 118
	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);
	}
119
));
120

121
const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`;
122
const minifyVSCodeTask = task.define('minify-vscode', task.series(
A
Alex Dima 已提交
123
	task.parallel(
A
Alex Dima 已提交
124 125 126 127
		util.rimraf('out-vscode-min'),
		optimizeIndexJSTask
	),
	common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`)
128
));
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

217 218 219
gulp.task(task.define('electron', task.series(util.rimraf('.build/electron'), getElectron(process.arch))));
gulp.task(task.define('electron-ia32', task.series(util.rimraf('.build/electron'), getElectron('ia32'))));
gulp.task(task.define('electron-x64', task.series(util.rimraf('.build/electron'), getElectron('x64'))));
J
João Moreno 已提交
220
gulp.task(task.define('electron-arm', task.series(util.rimraf('.build/electron'), getElectron('armv7l'))));
221
gulp.task(task.define('electron-arm64', task.series(util.rimraf('.build/electron'), getElectron('arm64'))));
I
isidor 已提交
222

A
Alex Dima 已提交
223 224 225 226 227 228 229 230 231
/**
 * 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 = {};
232
	filenames.forEach(function (filename) {
A
Alex Dima 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		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 已提交
257
function packageTask(platform, arch, sourceFolderName, destinationFolderName, opts) {
J
fix es6  
Joao Moreno 已提交
258 259
	opts = opts || {};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

J
Joao Moreno 已提交
313
		const license = gulp.src(['LICENSES.chromium.html', product.licenseFileName, 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.', allowEmpty: true });
I
isidor 已提交
314

J
Joao Moreno 已提交
315 316 317
		// 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'));

318 319
		const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true });

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

J
Joao Moreno 已提交
326
		const deps = gulp.src(depsSrc, { base: '.', dot: true })
J
Joao Moreno 已提交
327
			.pipe(filter(['**', '!**/package-lock.json']))
328
			.pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore')))
A
Alex Dima 已提交
329
			.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
I
isidor 已提交
330

J
Joao Moreno 已提交
331
		let all = es.merge(
L
Logan Ramos 已提交
332
			packageJsonStream,
J
Joao Moreno 已提交
333
			productJsonStream,
I
isidor 已提交
334
			license,
J
Joao Moreno 已提交
335
			api,
336
			telemetry,
I
isidor 已提交
337
			sources,
J
Joao Moreno 已提交
338
			deps
J
Joao Moreno 已提交
339 340 341
		);

		if (platform === 'win32') {
J
Joao Moreno 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
			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 已提交
373 374
		} else if (platform === 'linux') {
			all = es.merge(all, gulp.src('resources/linux/code.png', { base: '.' }));
J
Joao Moreno 已提交
375
		} else if (platform === 'darwin') {
J
Joao Moreno 已提交
376
			const shortcut = gulp.src('resources/darwin/bin/code.sh')
J
Joao Moreno 已提交
377 378 379
				.pipe(rename('bin/code'));

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

J
Joao Moreno 已提交
382
		let result = all
J
Joao Moreno 已提交
383
			.pipe(util.skipDirectories())
I
isidor 已提交
384
			.pipe(util.fixWin32DirectoryPermissions())
385
			.pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true })))
386
			.pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version']));
I
isidor 已提交
387

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

I
isidor 已提交
390
		if (platform === 'win32') {
A
Alex Dima 已提交
391
			result = es.merge(result, gulp.src('resources/win32/bin/code.js', { base: 'resources/win32', allowEmpty: true }));
J
Joao Moreno 已提交
392

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

J
typo  
João Moreno 已提交
397
			result = es.merge(result, gulp.src('resources/win32/bin/code.sh', { base: 'resources/win32' })
J
Joao Moreno 已提交
398
				.pipe(replace('@@NAME@@', product.nameShort))
M
Martin Aeschlimann 已提交
399 400
				.pipe(replace('@@PRODNAME@@', product.nameLong))
				.pipe(replace('@@VERSION@@', version))
A
Alex Dima 已提交
401 402
				.pipe(replace('@@COMMIT@@', commit))
				.pipe(replace('@@APPNAME@@', product.applicationName))
M
Martin Aeschlimann 已提交
403
				.pipe(replace('@@DATAFOLDER@@', product.dataFolderName))
M
Martin Aeschlimann 已提交
404
				.pipe(replace('@@QUALITY@@', quality))
J
Joao Moreno 已提交
405
				.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
406 407

			result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
408
				.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
409 410
		} else if (platform === 'linux') {
			result = es.merge(result, gulp.src('resources/linux/bin/code.sh', { base: '.' })
M
Martin Aeschlimann 已提交
411
				.pipe(replace('@@PRODNAME@@', product.nameLong))
412 413
				.pipe(replace('@@NAME@@', product.applicationName))
				.pipe(rename('bin/' + product.applicationName)));
I
isidor 已提交
414 415
		}

J
Johannes Rieken 已提交
416 417 418 419 420
		// 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 已提交
421
				submitAllStats(product, commit).then(() => console.log('Submitted bundle stats!'));
J
Johannes Rieken 已提交
422 423 424
			});
		}

J
Joao Moreno 已提交
425
		return result.pipe(vfs.dest(destination));
I
isidor 已提交
426 427 428
	};
}

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

A
Alex Dima 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
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)}`;

450
		const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
A
Alex Dima 已提交
451
			task.parallel(
A
Alex Dima 已提交
452 453 454 455
				minified ? minifyVSCodeTask : optimizeVSCodeTask,
				util.rimraf(path.join(buildRoot, destinationFolderName))
			),
			packageTask(platform, arch, sourceFolderName, destinationFolderName, opts)
456 457
		));
		gulp.task(vscodeTask);
A
Alex Dima 已提交
458 459
	});
});
I
isidor 已提交
460

461
// Transifex Localizations
D
Dirk Baeumer 已提交
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

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' }
};
477

478
const apiHostname = process.env.TRANSIFEX_API_URL;
479 480 481
const apiName = process.env.TRANSIFEX_API_NAME;
const apiToken = process.env.TRANSIFEX_API_TOKEN;

482 483
gulp.task(task.define(
	'vscode-translations-push',
A
Alex Dima 已提交
484
	task.series(
A
Alex Dima 已提交
485 486 487 488 489 490 491 492 493 494 495 496 497 498
		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));
		}
	)
499
));
D
Dirk Baeumer 已提交
500

501 502
gulp.task(task.define(
	'vscode-translations-export',
A
Alex Dima 已提交
503
	task.series(
A
Alex Dima 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516
		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'));
		}
	)
517
));
D
Dirk Baeumer 已提交
518 519

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

526
gulp.task('vscode-translations-import', function () {
527 528 529 530 531 532
	var options = minimist(process.argv.slice(2), {
		string: 'location',
		default: {
			location: '../vscode-translations-import'
		}
	});
533
	return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => {
534 535
		let id = language.transifexId || language.id;
		return gulp.src(`${options.location}/${id}/setup/*/*.xlf`)
D
Dirk Baeumer 已提交
536 537
			.pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id]))
			.pipe(vfs.dest(`./build/win32/i18n`));
538
	}));
539 540
});

I
isidor 已提交
541 542
// Sourcemaps

543
gulp.task('upload-vscode-sourcemaps', () => {
M
Martin Aeschlimann 已提交
544
	const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only
J
Joao Moreno 已提交
545
		.pipe(es.mapSync(f => {
546
			f.path = `${f.base}/core/${f.relative}`;
J
Joao Moreno 已提交
547 548 549
			return f;
		}));

550 551
	const extensionsOut = gulp.src(['extensions/**/out/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
	const extensionsDist = gulp.src(['extensions/**/dist/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
J
Joao Moreno 已提交
552

553
	return es.merge(vs, extensionsOut, extensionsDist)
J
Johannes Rieken 已提交
554 555 556 557 558
		.pipe(es.through(function (data) {
			// debug
			console.log('Uploading Sourcemap', data.relative);
			this.emit('data', data);
		}))
I
isidor 已提交
559 560 561 562
		.pipe(azure.upload({
			account: process.env.AZURE_STORAGE_ACCOUNT,
			key: process.env.AZURE_STORAGE_ACCESS_KEY,
			container: 'sourcemaps',
J
Joao Moreno 已提交
563
			prefix: commit + '/'
I
isidor 已提交
564
		}));
565
});
566

567
// This task is only run for the MacOS build
568
const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => {
569 570 571 572 573 574
	return new Promise((resolve, reject) => {
		const buildDir = process.env['AGENT_BUILDDIRECTORY'];
		if (!buildDir) {
			return reject(new Error('$AGENT_BUILDDIRECTORY not set'));
		}

J
Joao Moreno 已提交
575 576 577 578
		if (process.env.VSCODE_QUALITY !== 'insider' && process.env.VSCODE_QUALITY !== 'stable') {
			return resolve();
		}

579 580
		const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
		const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
581 582
		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`);
583
		const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
584 585 586

		const timer = setTimeout(() => {
			codeProc.kill();
587
			reject(new Error('export-default-configuration process timed out'));
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
		}, 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);
		});
	});
603
});
A
Alex Dima 已提交
604 605

const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
606 607
gulp.task(task.define(
	'upload-vscode-configuration',
A
Alex Dima 已提交
608
	task.series(
A
Alex Dima 已提交
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
		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}/`
				}));
		}
	)
635
));
A
Alex Dima 已提交
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659

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