gulpfile.vscode.js 26.2 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}',
66
	'out-build/vs/base/common/performance.js',
67
	'out-build/vs/base/node/languagePacks.js',
68
	'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
69
	'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
I
isidor 已提交
70
	'out-build/vs/workbench/browser/media/*-theme.css',
71
	'out-build/vs/workbench/contrib/debug/**/*.json',
72
	'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt',
73 74
	'out-build/vs/workbench/contrib/webview/browser/pre/*.js',
	'out-build/vs/workbench/contrib/webview/electron-browser/pre/*.js',
J
Joao Moreno 已提交
75
	'out-build/vs/**/markdown.css',
76 77
	'out-build/vs/workbench/contrib/tasks/**/*.json',
	'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
I
isidor 已提交
78 79
	'out-build/vs/workbench/services/files/**/*.exe',
	'out-build/vs/workbench/services/files/**/*.md',
80
	'out-build/vs/code/electron-browser/workbench/**',
81
	'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
82
	'out-build/vs/code/electron-browser/issue/issueReporter.js',
83
	'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
I
isidor 已提交
84 85 86
	'!**/test/**'
];

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

93
const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
A
Alex Dima 已提交
94
	task.parallel(
A
Alex Dima 已提交
95 96 97 98 99 100 101 102 103 104 105 106
		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
	})
107
));
A
Alex Dima 已提交
108 109


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

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

// Package
130 131

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

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

J
Joao Moreno 已提交
144
const config = {
J
Joao Moreno 已提交
145
	version: getElectronVersion(),
I
isidor 已提交
146
	productAppName: product.nameLong,
J
Joao Moreno 已提交
147
	companyName: 'Microsoft Corporation',
H
Henk Mollema 已提交
148
	copyright: 'Copyright (C) 2019 Microsoft. All rights reserved',
J
Joao Moreno 已提交
149
	darwinIcon: 'resources/darwin/code.icns',
I
isidor 已提交
150
	darwinBundleIdentifier: product.darwinBundleIdentifier,
J
Joao Moreno 已提交
151
	darwinApplicationCategoryType: 'public.app-category.developer-tools',
152 153
	darwinHelpBookFolder: 'VS Code HelpBook',
	darwinHelpBookName: 'VS Code HelpBook',
154 155 156 157 158 159 160 161 162
	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 已提交
163
		darwinBundleDocumentType(["asp", "aspx", "cshtml", "htm", "html", "jshtm", "jsp", "phtml", "shtml"], 'resources/darwin/html.icns'),
164 165
		darwinBundleDocumentType(["jade"], 'resources/darwin/jade.icns'),
		darwinBundleDocumentType(["jav", "java"], 'resources/darwin/java.icns'),
B
Benjamin Pasero 已提交
166
		darwinBundleDocumentType(["js", "jscsrc", "jshintrc", "mjs"], 'resources/darwin/javascript.icns'),
167 168 169 170 171 172 173
		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 已提交
174
		darwinBundleDocumentType(["scss"], 'resources/darwin/sass.icns'),
175 176 177 178 179 180 181
		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 已提交
182
		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')
183
	],
J
Joao Moreno 已提交
184 185 186
	darwinBundleURLTypes: [{
		role: 'Viewer',
		name: product.nameLong,
J
Joao Moreno 已提交
187
		urlSchemes: [product.urlProtocol]
J
Joao Moreno 已提交
188
	}],
189
	darwinForceDarkModeSupport: true,
R
Rob Lourens 已提交
190
	darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined,
191
	linuxExecutableName: product.applicationName,
J
Joao Moreno 已提交
192
	winIcon: 'resources/win32/code.ico',
R
Rob Lourens 已提交
193
	token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined,
194 195

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

J
fix es6  
Joao Moreno 已提交
199
function getElectron(arch) {
J
Joao Moreno 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	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'));
	};
}
215

216 217 218
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 已提交
219
gulp.task(task.define('electron-arm', task.series(util.rimraf('.build/electron'), getElectron('armv7l'))));
220
gulp.task(task.define('electron-arm64', task.series(util.rimraf('.build/electron'), getElectron('arm64'))));
I
isidor 已提交
221

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

J
Joao Moreno 已提交
323
		const deps = gulp.src(depsSrc, { base: '.', dot: true })
J
Joao Moreno 已提交
324
			.pipe(filter(['**', '!**/package-lock.json']))
J
Joao Moreno 已提交
325
			.pipe(util.cleanNodeModule('fsevents', ['binding.gyp', 'fsevents.cc', 'build/**', 'src/**', 'test/**'], ['**/*.node']))
326 327
			.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 已提交
328
			.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
329 330 331 332
			.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 已提交
333
			.pipe(util.cleanNodeModule('jschardet', ['dist/**']))
334
			.pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
A
Amy Qiu 已提交
335
			.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
336
			.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/index.js']))
C
Christof Marti 已提交
337
			.pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node']))
338
			.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node']))
339
			.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a']))
A
Alex Dima 已提交
340
			.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
341
			.pipe(util.cleanNodeModule('vscode-windows-ca-certs', ['**/*'], ['package.json', '**/*.node']))
342
			.pipe(util.cleanNodeModule('node-addon-api', ['**/*']))
A
Alex Dima 已提交
343
			.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
I
isidor 已提交
344

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

		if (platform === 'win32') {
J
Joao Moreno 已提交
355 356 357 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
			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 已提交
386 387
		} else if (platform === 'linux') {
			all = es.merge(all, gulp.src('resources/linux/code.png', { base: '.' }));
J
Joao Moreno 已提交
388
		} else if (platform === 'darwin') {
J
Joao Moreno 已提交
389
			const shortcut = gulp.src('resources/darwin/bin/code.sh')
J
Joao Moreno 已提交
390 391 392
				.pipe(rename('bin/code'));

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

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

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

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

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

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

			result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
417
				.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
418 419 420 421
		} 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 已提交
422 423
		}

J
Johannes Rieken 已提交
424 425 426 427 428
		// 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 已提交
429
				submitAllStats(product, commit).then(() => console.log('Submitted bundle stats!'));
J
Johannes Rieken 已提交
430 431 432
			});
		}

J
Joao Moreno 已提交
433
		return result.pipe(vfs.dest(destination));
I
isidor 已提交
434 435 436
	};
}

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

A
Alex Dima 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
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)}`;

458
		const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
A
Alex Dima 已提交
459
			task.parallel(
A
Alex Dima 已提交
460 461 462 463
				minified ? minifyVSCodeTask : optimizeVSCodeTask,
				util.rimraf(path.join(buildRoot, destinationFolderName))
			),
			packageTask(platform, arch, sourceFolderName, destinationFolderName, opts)
464 465
		));
		gulp.task(vscodeTask);
A
Alex Dima 已提交
466 467
	});
});
I
isidor 已提交
468

469
// Transifex Localizations
D
Dirk Baeumer 已提交
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484

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

486
const apiHostname = process.env.TRANSIFEX_API_URL;
487 488 489
const apiName = process.env.TRANSIFEX_API_NAME;
const apiToken = process.env.TRANSIFEX_API_TOKEN;

490 491
gulp.task(task.define(
	'vscode-translations-push',
A
Alex Dima 已提交
492
	task.series(
A
Alex Dima 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505 506
		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));
		}
	)
507
));
D
Dirk Baeumer 已提交
508

509 510
gulp.task(task.define(
	'vscode-translations-export',
A
Alex Dima 已提交
511
	task.series(
A
Alex Dima 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524
		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'));
		}
	)
525
));
D
Dirk Baeumer 已提交
526 527

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

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

I
isidor 已提交
549 550
// Sourcemaps

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

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

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

575
// This task is only run for the MacOS build
576
const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => {
577 578 579 580 581 582
	return new Promise((resolve, reject) => {
		const buildDir = process.env['AGENT_BUILDDIRECTORY'];
		if (!buildDir) {
			return reject(new Error('$AGENT_BUILDDIRECTORY not set'));
		}

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

587 588
		const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
		const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
589 590
		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`);
591
		const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
592 593 594

		const timer = setTimeout(() => {
			codeProc.kill();
595
			reject(new Error('export-default-configuration process timed out'));
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
		}, 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);
		});
	});
611
});
A
Alex Dima 已提交
612 613

const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
614 615
gulp.task(task.define(
	'upload-vscode-configuration',
A
Alex Dima 已提交
616
	task.series(
A
Alex Dima 已提交
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
		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}/`
				}));
		}
	)
643
));
A
Alex Dima 已提交
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667

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