vscode/build/gulpfile.vscode.linux.js

278 lines
13 KiB
JavaScript
Raw Normal View History

2016-07-20 11:00:43 +02:00
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const gulp = require('gulp');
const replace = require('gulp-replace');
const rename = require('gulp-rename');
const shell = require('gulp-shell');
const es = require('event-stream');
2016-09-05 12:38:25 +02:00
const vfs = require('vinyl-fs');
2016-07-20 11:00:43 +02:00
const util = require('./lib/util');
2019-02-12 15:13:43 +01:00
const task = require('./lib/task');
2016-07-20 11:00:43 +02:00
const packageJson = require('../package.json');
const product = require('../product.json');
2018-02-01 14:39:12 +01:00
const rpmDependencies = require('../resources/linux/rpm/dependencies.json');
2018-12-19 15:02:19 +01:00
const path = require('path');
const root = path.dirname(__dirname);
const commit = util.getVersion(root);
2016-07-20 11:00:43 +02:00
Support building Flatpak bundles This adds support for building Flatpak application bundles, which should be runnable on any Linux distribution with Flatpak support. See the page at http://flatpak.org/getting.html New Gulp tasks are added to prepare a directory with the needed files (vscode-linux-${arch}-prepare-flatpak), assembling the Flatpak bundles (vscode-linux-${arch}-flatpak), and for cleaning the build directories (clean-vscode-linux-${arch}-flatpak). This mimics how the Debian and RPM package creation works. Hence, building an application bundle is done with: $ gulp vscode-linux-x64-flatpak [...] $ ls *.flatpak com.visualstudio.code.oss-x86_64.flatpak Installing and running the application is achieved with: $ flatpak --user install --bundle com.visualstudio.code.oss-x86_64.flatpak $ flatpak run com.visualstudio.code.oss (Removing "--user" would install the application system-wide. Also note that the "org.freedesktop.Platform" runtime needs to be installeed, check the Flatpak website for instructions.) The "flatpak-bundler" development dependency provides an asynchronous API to invoke "flatpak-builder". The "gulp-image-resize" module is used to incorporate scaling of the application icon to multiple sizes, and uses ImageMagick (or GraphicsMagick) under the hood, which is commonly available on most GNU/Linux distributions. Instead of building the Electron dependencies ourselves, this uses the io.atom.electron.BaseApp bundle as base application. Instead of building the Electron dependencies, this reuses the "io.atom.electron.BaseApp" bundle as base application. The contents of the base application are imported at build time, and then Electron and the prepared files added on top. The prebuilt base application will be fetched automatically using the URL specified in the "baseFlatpakref" attribute of the manifest, and it is kindly hosted at Amazon S3 by Endless Computers (https://endlessm.com). The sources for the base application can be found at: https://github.com/endlessm/electron-flatpak-base-app/
2016-11-25 01:21:57 +01:00
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
2016-07-20 11:00:43 +02:00
function getDebPackageArch(arch) {
2020-09-08 09:41:28 +02:00
return { x64: 'amd64', armhf: 'armhf', arm64: 'arm64' }[arch];
2016-07-20 11:00:43 +02:00
}
function prepareDebPackage(arch) {
const binaryDir = '../VSCode-linux-' + arch;
const debArch = getDebPackageArch(arch);
const destination = '.build/linux/deb/' + debArch + '/' + product.applicationName + '-' + debArch;
return function () {
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
.pipe(rename('usr/share/applications/' + product.applicationName + '.desktop'));
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
2018-09-13 11:14:33 +02:00
.pipe(rename('usr/share/applications/' + product.applicationName + '-url-handler.desktop'));
const desktops = es.merge(desktop, desktopUrlHandler)
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`))
.pipe(replace('@@ICON@@', product.linuxIconName))
2018-09-13 11:14:33 +02:00
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' })
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@LICENSE@@', product.licenseName))
.pipe(rename('usr/share/appdata/' + product.applicationName + '.appdata.xml'));
2020-09-10 15:02:48 +02:00
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
2020-04-19 13:57:06 +02:00
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(rename('usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
const icon = gulp.src('resources/linux/code.png', { base: '.' })
2019-03-08 20:17:38 +01:00
.pipe(rename('usr/share/pixmaps/' + product.linuxIconName + '.png'));
2016-07-20 11:00:43 +02:00
const bash_completion = gulp.src('resources/completions/bash/code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('usr/share/bash-completion/completions/' + product.applicationName));
const zsh_completion = gulp.src('resources/completions/zsh/_code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('usr/share/zsh/vendor-completions/_' + product.applicationName));
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
2016-07-20 11:00:43 +02:00
.pipe(rename(function (p) { p.dirname = 'usr/share/' + product.applicationName + '/' + p.dirname; }));
let size = 0;
const control = code.pipe(es.through(
function (f) { size += f.isDirectory() ? 4096 : f.contents.length; },
function () {
const that = this;
gulp.src('resources/linux/debian/control.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@VERSION@@', packageJson.version + '-' + linuxPackageRevision))
.pipe(replace('@@ARCHITECTURE@@', debArch))
.pipe(replace('@@INSTALLEDSIZE@@', Math.ceil(size / 1024)))
.pipe(rename('DEBIAN/control'))
.pipe(es.through(function (f) { that.emit('data', f); }, function () { that.emit('end'); }));
}));
const prerm = gulp.src('resources/linux/debian/prerm.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
2016-09-05 12:38:25 +02:00
.pipe(rename('DEBIAN/prerm'));
2016-07-20 11:00:43 +02:00
const postrm = gulp.src('resources/linux/debian/postrm.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
2016-09-05 12:38:25 +02:00
.pipe(rename('DEBIAN/postrm'));
2016-07-20 11:00:43 +02:00
const postinst = gulp.src('resources/linux/debian/postinst.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
2016-09-05 12:38:25 +02:00
.pipe(rename('DEBIAN/postinst'));
2016-07-20 11:00:43 +02:00
2020-04-19 13:57:06 +02:00
const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code);
2016-07-20 11:00:43 +02:00
2016-09-05 12:38:25 +02:00
return all.pipe(vfs.dest(destination));
2016-07-20 11:00:43 +02:00
};
}
function buildDebPackage(arch) {
const debArch = getDebPackageArch(arch);
return shell.task([
'chmod 755 ' + product.applicationName + '-' + debArch + '/DEBIAN/postinst ' + product.applicationName + '-' + debArch + '/DEBIAN/prerm ' + product.applicationName + '-' + debArch + '/DEBIAN/postrm',
2016-07-20 11:00:43 +02:00
'mkdir -p deb',
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb'
], { cwd: '.build/linux/deb/' + debArch });
2016-07-20 11:00:43 +02:00
}
function getRpmBuildPath(rpmArch) {
return '.build/linux/rpm/' + rpmArch + '/rpmbuild';
}
function getRpmPackageArch(arch) {
2020-09-08 20:57:07 +02:00
return { x64: 'x86_64', armhf: 'armv7hl', arm64: 'aarch64' }[arch];
2016-07-20 11:00:43 +02:00
}
function prepareRpmPackage(arch) {
const binaryDir = '../VSCode-linux-' + arch;
const rpmArch = getRpmPackageArch(arch);
return function () {
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
.pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '.desktop'));
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
.pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '-url-handler.desktop'));
2018-11-06 16:08:02 +01:00
const desktops = es.merge(desktop, desktopUrlHandler)
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@EXEC@@', `/usr/share/${product.applicationName}/${product.applicationName}`))
2019-03-08 20:17:38 +01:00
.pipe(replace('@@ICON@@', product.linuxIconName))
2018-11-06 16:08:02 +01:00
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
2018-09-13 11:14:33 +02:00
const appdata = gulp.src('resources/linux/code.appdata.xml', { base: '.' })
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@LICENSE@@', product.licenseName))
.pipe(rename('usr/share/appdata/' + product.applicationName + '.appdata.xml'));
const workspaceMime = gulp.src('resources/linux/code-workspace.xml', { base: '.' })
2020-04-19 13:57:06 +02:00
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(rename('BUILD/usr/share/mime/packages/' + product.applicationName + '-workspace.xml'));
const icon = gulp.src('resources/linux/code.png', { base: '.' })
2019-03-08 20:17:38 +01:00
.pipe(rename('BUILD/usr/share/pixmaps/' + product.linuxIconName + '.png'));
2016-07-20 11:00:43 +02:00
const bash_completion = gulp.src('resources/completions/bash/code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('BUILD/usr/share/bash-completion/completions/' + product.applicationName));
const zsh_completion = gulp.src('resources/completions/zsh/_code')
.pipe(replace('@@APPNAME@@', product.applicationName))
.pipe(rename('BUILD/usr/share/zsh/site-functions/_' + product.applicationName));
2016-07-20 11:00:43 +02:00
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
.pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; }));
const spec = gulp.src('resources/linux/rpm/code.spec.template', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
.pipe(replace('@@NAME_LONG@@', product.nameLong))
2019-03-11 18:34:17 +01:00
.pipe(replace('@@ICON@@', product.linuxIconName))
2016-07-20 11:00:43 +02:00
.pipe(replace('@@VERSION@@', packageJson.version))
.pipe(replace('@@RELEASE@@', linuxPackageRevision))
.pipe(replace('@@ARCHITECTURE@@', rpmArch))
.pipe(replace('@@LICENSE@@', product.licenseName))
2016-07-20 11:00:43 +02:00
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
2016-12-14 04:58:38 +01:00
.pipe(replace('@@DEPENDENCIES@@', rpmDependencies[rpmArch].join(', ')))
2016-07-20 11:00:43 +02:00
.pipe(rename('SPECS/' + product.applicationName + '.spec'));
const specIcon = gulp.src('resources/linux/rpm/code.xpm', { base: '.' })
.pipe(rename('SOURCES/' + product.applicationName + '.xpm'));
2020-04-19 13:57:06 +02:00
const all = es.merge(code, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, spec, specIcon);
2016-07-20 11:00:43 +02:00
2016-09-05 12:38:25 +02:00
return all.pipe(vfs.dest(getRpmBuildPath(rpmArch)));
};
2016-07-20 11:00:43 +02:00
}
function buildRpmPackage(arch) {
const rpmArch = getRpmPackageArch(arch);
const rpmBuildPath = getRpmBuildPath(rpmArch);
const rpmOut = rpmBuildPath + '/RPMS/' + rpmArch;
2016-07-20 11:00:43 +02:00
const destination = '.build/linux/rpm/' + rpmArch;
2016-09-05 12:38:25 +02:00
2016-07-20 11:00:43 +02:00
return shell.task([
'mkdir -p ' + destination,
'HOME="$(pwd)/' + destination + '" fakeroot rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch,
'cp "' + rpmOut + '/$(ls ' + rpmOut + ')" ' + destination + '/'
2016-07-20 11:00:43 +02:00
]);
}
2018-11-06 13:02:08 +01:00
function getSnapBuildPath(arch) {
return `.build/linux/snap/${arch}/${product.applicationName}-${arch}`;
}
function prepareSnapPackage(arch) {
const binaryDir = '../VSCode-linux-' + arch;
const destination = getSnapBuildPath(arch);
return function () {
// A desktop file that is placed in snap/gui will be placed into meta/gui verbatim.
const desktop = gulp.src('resources/linux/code.desktop', { base: '.' })
.pipe(rename(`snap/gui/${product.applicationName}.desktop`));
2019-03-22 11:12:57 +01:00
// A desktop file that is placed in snap/gui will be placed into meta/gui verbatim.
2019-03-22 11:12:57 +01:00
const desktopUrlHandler = gulp.src('resources/linux/code-url-handler.desktop', { base: '.' })
.pipe(rename(`snap/gui/${product.applicationName}-url-handler.desktop`));
2019-03-22 11:12:57 +01:00
const desktops = es.merge(desktop, desktopUrlHandler)
.pipe(replace('@@NAME_LONG@@', product.nameLong))
.pipe(replace('@@NAME_SHORT@@', product.nameShort))
.pipe(replace('@@NAME@@', product.applicationName))
2019-09-11 13:31:42 +02:00
.pipe(replace('@@EXEC@@', `${product.applicationName} --force-user-env`))
.pipe(replace('@@ICON@@', `\${SNAP}/meta/gui/${product.linuxIconName}.png`))
2019-03-22 11:12:57 +01:00
.pipe(replace('@@URLPROTOCOL@@', product.urlProtocol));
// An icon that is placed in snap/gui will be placed into meta/gui verbatim.
const icon = gulp.src('resources/linux/code.png', { base: '.' })
.pipe(rename(`snap/gui/${product.linuxIconName}.png`));
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
2018-02-08 18:09:12 +01:00
.pipe(rename(function (p) { p.dirname = `usr/share/${product.applicationName}/${p.dirname}`; }));
const snapcraft = gulp.src('resources/linux/snap/snapcraft.yaml', { base: '.' })
.pipe(replace('@@NAME@@', product.applicationName))
2018-12-19 15:06:16 +01:00
.pipe(replace('@@VERSION@@', commit.substr(0, 8)))
// Possible run-on values https://snapcraft.io/docs/architectures
.pipe(replace('@@ARCHITECTURE@@', arch === 'x64' ? 'amd64' : arch))
.pipe(rename('snap/snapcraft.yaml'));
const electronLaunch = gulp.src('resources/linux/snap/electron-launch', { base: '.' })
.pipe(rename('electron-launch'));
2019-03-22 11:12:57 +01:00
const all = es.merge(desktops, icon, code, snapcraft, electronLaunch);
return all.pipe(vfs.dest(destination));
};
}
function buildSnapPackage(arch) {
const snapBuildPath = getSnapBuildPath(arch);
// Default target for snapcraft runs: pull, build, stage and prime, and finally assembles the snap.
return shell.task(`cd ${snapBuildPath} && snapcraft`);
}
2016-07-20 11:00:43 +02:00
2019-02-05 21:23:25 +01:00
const BUILD_TARGETS = [
{ arch: 'x64' },
2020-09-08 09:41:28 +02:00
{ arch: 'armhf' },
2019-02-05 21:23:25 +01:00
{ arch: 'arm64' },
];
2020-09-08 16:24:51 +02:00
BUILD_TARGETS.forEach(({ arch }) => {
const debArch = getDebPackageArch(arch);
const prepareDebTask = task.define(`vscode-linux-${arch}-prepare-deb`, task.series(util.rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)));
const buildDebTask = task.define(`vscode-linux-${arch}-build-deb`, task.series(prepareDebTask, buildDebPackage(arch)));
gulp.task(buildDebTask);
const rpmArch = getRpmPackageArch(arch);
const prepareRpmTask = task.define(`vscode-linux-${arch}-prepare-rpm`, task.series(util.rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)));
const buildRpmTask = task.define(`vscode-linux-${arch}-build-rpm`, task.series(prepareRpmTask, buildRpmPackage(arch)));
gulp.task(buildRpmTask);
const prepareSnapTask = task.define(`vscode-linux-${arch}-prepare-snap`, task.series(util.rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)));
gulp.task(prepareSnapTask);
const buildSnapTask = task.define(`vscode-linux-${arch}-build-snap`, task.series(prepareSnapTask, buildSnapPackage(arch)));
gulp.task(buildSnapTask);
2019-02-05 21:23:25 +01:00
});