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');
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
	'out-build/vs/workbench/contrib/webview/electron-browser/webview-pre.js',
J
Joao Moreno 已提交
74
	'out-build/vs/**/markdown.css',
75 76
	'out-build/vs/workbench/contrib/tasks/**/*.json',
	'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
I
isidor 已提交
77 78
	'out-build/vs/workbench/services/files/**/*.exe',
	'out-build/vs/workbench/services/files/**/*.md',
79
	'out-build/vs/code/electron-browser/workbench/**',
80
	'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
81
	'out-build/vs/code/electron-browser/issue/issueReporter.js',
82
	'out-build/vs/code/electron-browser/processExplorer/processExplorer.js',
I
isidor 已提交
83 84 85
	'!**/test/**'
];

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

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


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

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

// Package
129 130

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
311
		const license = gulp.src(['LICENSES.chromium.html', 'LICENSE.txt', 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.', allowEmpty: true });
I
isidor 已提交
312

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

I
isidor 已提交
548 549
// Sourcemaps

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

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

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

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

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

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

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

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

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