Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/gulpfile.vscode.linux.js
3520 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
'use strict';
7
8
const gulp = require('gulp');
9
const replace = require('gulp-replace');
10
const rename = require('gulp-rename');
11
const es = require('event-stream');
12
const vfs = require('vinyl-fs');
13
const { rimraf } = require('./lib/util');
14
const { getVersion } = require('./lib/getVersion');
15
const task = require('./lib/task');
16
const packageJson = require('../package.json');
17
const product = require('../product.json');
18
const dependenciesGenerator = require('./linux/dependencies-generator');
19
const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps;
20
const path = require('path');
21
const cp = require('child_process');
22
const util = require('util');
23
24
const exec = util.promisify(cp.exec);
25
const root = path.dirname(__dirname);
26
const commit = getVersion(root);
27
28
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
29
30
/**
31
* @param {string} arch
32
*/
33
function getDebPackageArch(arch) {
34
return { x64: 'amd64', armhf: 'armhf', arm64: 'arm64' }[arch];
35
}
36
37
function prepareDebPackage(arch) {
38
const binaryDir = '../VSCode-linux-' + arch;
39
const debArch = getDebPackageArch(arch);
40
const destination = '.build/linux/deb/' + debArch + '/' + product.applicationName + '-' + debArch;
41
42
return async function () {
43
const dependencies = await dependenciesGenerator.getDependencies('deb', binaryDir, product.applicationName, debArch);
44
45
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
46
.pipe(rename('usr/share/applications/' + product.applicationName + '.desktop'));
47
48
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
49
.pipe(rename('usr/share/applications/' + product.applicationName + '-url-handler.desktop'));
50
51
const desktops = es.merge(desktop, desktopUrlHandler)
52
.pipe(replace('@@NAME_LONG@@', product.nameLong))
53
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
54
.pipe(replace('@@NAME@@', product.applicationName))
55
.pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`))
56
.pipe(replace('@@ICON@@', product.linuxIconName))
57
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
58
59
const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' })
60
.pipe(replace('@@NAME_LONG@@', product.nameLong))
61
.pipe(replace('@@NAME@@', product.applicationName))
62
.pipe(replace('@@LICENSE@@', product.licenseName))
63
.pipe(rename('usr/share/appdata/' + product.applicationName + '.appdata.xml'));
64
65
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
66
.pipe(replace('@@NAME_LONG@@', product.nameLong))
67
.pipe(replace('@@NAME@@', product.applicationName))
68
.pipe(rename('usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
69
70
const icon = gulp.src('resources/linux/code.png', { base: '.' })
71
.pipe(rename('usr/share/pixmaps/' + product.linuxIconName + '.png'));
72
73
const bash_completion = gulp.src('resources/completions/bash/code')
74
.pipe(replace('@@APPNAME@@', product.applicationName))
75
.pipe(rename('usr/share/bash-completion/completions/' + product.applicationName));
76
77
const zsh_completion = gulp.src('resources/completions/zsh/_code')
78
.pipe(replace('@@APPNAME@@', product.applicationName))
79
.pipe(rename('usr/share/zsh/vendor-completions/_' + product.applicationName));
80
81
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
82
.pipe(rename(function (p) { p.dirname = 'usr/share/' + product.applicationName + '/' + p.dirname; }));
83
84
let size = 0;
85
const control = code.pipe(es.through(
86
function (f) { size += f.isDirectory() ? 4096 : f.contents.length; },
87
function () {
88
const that = this;
89
gulp.src('resources/linux/debian/control.template', { base: '.' })
90
.pipe(replace('@@NAME@@', product.applicationName))
91
.pipe(replace('@@VERSION@@', packageJson.version + '-' + linuxPackageRevision))
92
.pipe(replace('@@ARCHITECTURE@@', debArch))
93
.pipe(replace('@@DEPENDS@@', dependencies.join(', ')))
94
.pipe(replace('@@RECOMMENDS@@', debianRecommendedDependencies.join(', ')))
95
.pipe(replace('@@INSTALLEDSIZE@@', Math.ceil(size / 1024)))
96
.pipe(rename('DEBIAN/control'))
97
.pipe(es.through(function (f) { that.emit('data', f); }, function () { that.emit('end'); }));
98
}));
99
100
const prerm = gulp.src('resources/linux/debian/prerm.template', { base: '.' })
101
.pipe(replace('@@NAME@@', product.applicationName))
102
.pipe(rename('DEBIAN/prerm'));
103
104
const postrm = gulp.src('resources/linux/debian/postrm.template', { base: '.' })
105
.pipe(replace('@@NAME@@', product.applicationName))
106
.pipe(rename('DEBIAN/postrm'));
107
108
const postinst = gulp.src('resources/linux/debian/postinst.template', { base: '.' })
109
.pipe(replace('@@NAME@@', product.applicationName))
110
.pipe(replace('@@ARCHITECTURE@@', debArch))
111
.pipe(rename('DEBIAN/postinst'));
112
113
const templates = gulp.src('resources/linux/debian/templates.template', { base: '.' })
114
.pipe(replace('@@NAME@@', product.applicationName))
115
.pipe(rename('DEBIAN/templates'));
116
117
const all = es.merge(control, templates, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code);
118
119
return all.pipe(vfs.dest(destination));
120
};
121
}
122
123
/**
124
* @param {string} arch
125
*/
126
function buildDebPackage(arch) {
127
const debArch = getDebPackageArch(arch);
128
const cwd = `.build/linux/deb/${debArch}`;
129
130
return async () => {
131
await exec(`chmod 755 ${product.applicationName}-${debArch}/DEBIAN/postinst ${product.applicationName}-${debArch}/DEBIAN/prerm ${product.applicationName}-${debArch}/DEBIAN/postrm`, { cwd });
132
await exec('mkdir -p deb', { cwd });
133
await exec(`fakeroot dpkg-deb -Zxz -b ${product.applicationName}-${debArch} deb`, { cwd });
134
};
135
}
136
137
/**
138
* @param {string} rpmArch
139
*/
140
function getRpmBuildPath(rpmArch) {
141
return '.build/linux/rpm/' + rpmArch + '/rpmbuild';
142
}
143
144
/**
145
* @param {string} arch
146
*/
147
function getRpmPackageArch(arch) {
148
return { x64: 'x86_64', armhf: 'armv7hl', arm64: 'aarch64' }[arch];
149
}
150
151
/**
152
* @param {string} arch
153
*/
154
function prepareRpmPackage(arch) {
155
const binaryDir = '../VSCode-linux-' + arch;
156
const rpmArch = getRpmPackageArch(arch);
157
const stripBinary = process.env['STRIP'] ?? '/usr/bin/strip';
158
159
return async function () {
160
const dependencies = await dependenciesGenerator.getDependencies('rpm', binaryDir, product.applicationName, rpmArch);
161
162
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
163
.pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '.desktop'));
164
165
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
166
.pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '-url-handler.desktop'));
167
168
const desktops = es.merge(desktop, desktopUrlHandler)
169
.pipe(replace('@@NAME_LONG@@', product.nameLong))
170
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
171
.pipe(replace('@@NAME@@', product.applicationName))
172
.pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`))
173
.pipe(replace('@@ICON@@', product.linuxIconName))
174
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
175
176
const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' })
177
.pipe(replace('@@NAME_LONG@@', product.nameLong))
178
.pipe(replace('@@NAME@@', product.applicationName))
179
.pipe(replace('@@LICENSE@@', product.licenseName))
180
.pipe(rename('BUILD/usr/share/appdata/' + product.applicationName + '.appdata.xml'));
181
182
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
183
.pipe(replace('@@NAME_LONG@@', product.nameLong))
184
.pipe(replace('@@NAME@@', product.applicationName))
185
.pipe(rename('BUILD/usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
186
187
const icon = gulp.src('resources/linux/code.png', { base: '.' })
188
.pipe(rename('BUILD/usr/share/pixmaps/' + product.linuxIconName + '.png'));
189
190
const bash_completion = gulp.src('resources/completions/bash/code')
191
.pipe(replace('@@APPNAME@@', product.applicationName))
192
.pipe(rename('BUILD/usr/share/bash-completion/completions/' + product.applicationName));
193
194
const zsh_completion = gulp.src('resources/completions/zsh/_code')
195
.pipe(replace('@@APPNAME@@', product.applicationName))
196
.pipe(rename('BUILD/usr/share/zsh/site-functions/_' + product.applicationName));
197
198
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
199
.pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; }));
200
201
const spec = gulp.src('resources/linux/rpm/code.spec.template', { base: '.' })
202
.pipe(replace('@@NAME@@', product.applicationName))
203
.pipe(replace('@@NAME_LONG@@', product.nameLong))
204
.pipe(replace('@@ICON@@', product.linuxIconName))
205
.pipe(replace('@@VERSION@@', packageJson.version))
206
.pipe(replace('@@RELEASE@@', linuxPackageRevision))
207
.pipe(replace('@@ARCHITECTURE@@', rpmArch))
208
.pipe(replace('@@LICENSE@@', product.licenseName))
209
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
210
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
211
.pipe(replace('@@DEPENDENCIES@@', dependencies.join(', ')))
212
.pipe(replace('@@STRIP@@', stripBinary))
213
.pipe(rename('SPECS/' + product.applicationName + '.spec'));
214
215
const specIcon = gulp.src('resources/linux/rpm/code.xpm', { base: '.' })
216
.pipe(rename('SOURCES/' + product.applicationName + '.xpm'));
217
218
const all = es.merge(code, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, spec, specIcon);
219
220
return all.pipe(vfs.dest(getRpmBuildPath(rpmArch)));
221
};
222
}
223
224
/**
225
* @param {string} arch
226
*/
227
function buildRpmPackage(arch) {
228
const rpmArch = getRpmPackageArch(arch);
229
const rpmBuildPath = getRpmBuildPath(rpmArch);
230
const rpmOut = `${rpmBuildPath}/RPMS/${rpmArch}`;
231
const destination = `.build/linux/rpm/${rpmArch}`;
232
233
return async () => {
234
await exec(`mkdir -p ${destination}`);
235
await exec(`HOME="$(pwd)/${destination}" rpmbuild -bb ${rpmBuildPath}/SPECS/${product.applicationName}.spec --target=${rpmArch}`);
236
await exec(`cp "${rpmOut}/$(ls ${rpmOut})" ${destination}/`);
237
};
238
}
239
240
/**
241
* @param {string} arch
242
*/
243
function getSnapBuildPath(arch) {
244
return `.build/linux/snap/${arch}/${product.applicationName}-${arch}`;
245
}
246
247
/**
248
* @param {string} arch
249
*/
250
function prepareSnapPackage(arch) {
251
const binaryDir = '../VSCode-linux-' + arch;
252
const destination = getSnapBuildPath(arch);
253
254
return function () {
255
// A desktop file that is placed in snap/gui will be placed into meta/gui verbatim.
256
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
257
.pipe(rename(`snap/gui/${product.applicationName}.desktop`));
258
259
// A desktop file that is placed in snap/gui will be placed into meta/gui verbatim.
260
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
261
.pipe(rename(`snap/gui/${product.applicationName}-url-handler.desktop`));
262
263
const desktops = es.merge(desktop, desktopUrlHandler)
264
.pipe(replace('@@NAME_LONG@@', product.nameLong))
265
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
266
.pipe(replace('@@NAME@@', product.applicationName))
267
.pipe(replace('@@EXEC@@', `${product.applicationName} --force-user-env`))
268
.pipe(replace('@@ICON@@', `\${SNAP}/meta/gui/${product.linuxIconName}.png`))
269
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
270
271
// An icon that is placed in snap/gui will be placed into meta/gui verbatim.
272
const icon = gulp.src('resources/linux/code.png', { base: '.' })
273
.pipe(rename(`snap/gui/${product.linuxIconName}.png`));
274
275
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
276
.pipe(rename(function (p) { p.dirname = `usr/share/${product.applicationName}/${p.dirname}`; }));
277
278
const snapcraft = gulp.src('resources/linux/snap/snapcraft.yaml', { base: '.' })
279
.pipe(replace('@@NAME@@', product.applicationName))
280
.pipe(replace('@@VERSION@@', commit.substr(0, 8)))
281
// Possible run-on values https://snapcraft.io/docs/architectures
282
.pipe(replace('@@ARCHITECTURE@@', arch === 'x64' ? 'amd64' : arch))
283
.pipe(rename('snap/snapcraft.yaml'));
284
285
const electronLaunch = gulp.src('resources/linux/snap/electron-launch', { base: '.' })
286
.pipe(rename('electron-launch'));
287
288
const all = es.merge(desktops, icon, code, snapcraft, electronLaunch);
289
290
return all.pipe(vfs.dest(destination));
291
};
292
}
293
294
/**
295
* @param {string} arch
296
*/
297
function buildSnapPackage(arch) {
298
const cwd = getSnapBuildPath(arch);
299
return () => exec('snapcraft', { cwd });
300
}
301
302
const BUILD_TARGETS = [
303
{ arch: 'x64' },
304
{ arch: 'armhf' },
305
{ arch: 'arm64' },
306
];
307
308
BUILD_TARGETS.forEach(({ arch }) => {
309
const debArch = getDebPackageArch(arch);
310
const prepareDebTask = task.define(`vscode-linux-${arch}-prepare-deb`, task.series(rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)));
311
gulp.task(prepareDebTask);
312
const buildDebTask = task.define(`vscode-linux-${arch}-build-deb`, buildDebPackage(arch));
313
gulp.task(buildDebTask);
314
315
const rpmArch = getRpmPackageArch(arch);
316
const prepareRpmTask = task.define(`vscode-linux-${arch}-prepare-rpm`, task.series(rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)));
317
gulp.task(prepareRpmTask);
318
const buildRpmTask = task.define(`vscode-linux-${arch}-build-rpm`, buildRpmPackage(arch));
319
gulp.task(buildRpmTask);
320
321
const prepareSnapTask = task.define(`vscode-linux-${arch}-prepare-snap`, task.series(rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)));
322
gulp.task(prepareSnapTask);
323
const buildSnapTask = task.define(`vscode-linux-${arch}-build-snap`, task.series(prepareSnapTask, buildSnapPackage(arch)));
324
gulp.task(buildSnapTask);
325
});
326
327