diff --git a/.editorconfig b/.editorconfig
index e3711b6b..b0b333da 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,5 +11,5 @@ indent_size = 4
[*.md]
trim_trailing_whitespace = false
-[package.json]
+[{package.json,package-lock.json,.travis.yml}]
indent_size = 2
diff --git a/.travis.yml b/.travis.yml
index 61349451..723c1101 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,40 @@
language: node_js
node_js:
-- stable
-
-branches:
- only:
- - master
+- 11
addons:
apt:
packages:
- libsecret-1-dev
+
+jobs:
+ include:
+ - stage: test
+ - stage: release
+ script:
+ - npm run update_release
+ - npm run package_release
+ - npm run build_debs
+ deploy:
+ provider: releases
+ api_key: "$GITHUB_OAUTH_TOKEN"
+ draft: true
+ file:
+ # BetterDiscord installer/updater
+ - release/releaseinfo.json
+ - release/core.tar.gz
+ - release/client.tar.gz
+ - release/editor.tar.gz
+
+ # dpkg
+ - release/betterdiscord_*.deb
+ - release/betterdiscord-ptb_*.deb
+ - release/betterdiscord-canary_*.deb
+ - release/betterdiscord-core_*.deb
+ - release/betterdiscord-client_*.deb
+ - release/betterdiscord-editor_*.deb
+ file_glob: true
+ skip_cleanup: true
+ on:
+ tags: true
diff --git a/client/src/modules/globals.js b/client/src/modules/globals.js
index 98618c72..220cf525 100644
--- a/client/src/modules/globals.js
+++ b/client/src/modules/globals.js
@@ -101,4 +101,8 @@ export default new class extends Module {
return this.config.versions.core;
}
+ get disableUpdater() {
+ return this.config.disableUpdater;
+ }
+
}
diff --git a/client/src/modules/updater.js b/client/src/modules/updater.js
index a48c32c8..41f41240 100644
--- a/client/src/modules/updater.js
+++ b/client/src/modules/updater.js
@@ -98,7 +98,7 @@ export default new class extends Module {
update.text = `${update.id.charAt(0).toUpperCase()}${update.id.slice(1)}`;
update.hint = `Current: ${update.currentVersion} | Latest: ${update.version}`;
update.status = {
- update: true,
+ update: !Globals.disableUpdater.includes(update.id),
updating: false,
updated: false,
error: null
@@ -164,7 +164,7 @@ export default new class extends Module {
}
toggleUpdate(update) {
- update.status.update = !update.status.update;
+ update.status.update = !update.status.update && !Globals.disableUpdater.includes(update.id);
}
async startUpdate() {
diff --git a/client/src/ui/components/bd/UpdaterStatus.vue b/client/src/ui/components/bd/UpdaterStatus.vue
index 76ef0b24..3439e59a 100644
--- a/client/src/ui/components/bd/UpdaterStatus.vue
+++ b/client/src/ui/components/bd/UpdaterStatus.vue
@@ -12,7 +12,8 @@
{{item.text}}
-
Update Failed!
+
Use your package manager to install
+
Update Failed!
Done
Unknown
@@ -23,6 +24,6 @@
diff --git a/client/src/ui/components/bd/UpdaterView.vue b/client/src/ui/components/bd/UpdaterView.vue
index e9457d9a..a0c63f21 100644
--- a/client/src/ui/components/bd/UpdaterView.vue
+++ b/client/src/ui/components/bd/UpdaterView.vue
@@ -18,15 +18,14 @@
-
- Update
-
+
+ Update
@@ -37,6 +36,7 @@
import SettingsWrapper from './SettingsWrapper.vue';
import UpdaterToggle from './UpdaterToggle.vue';
import UpdaterStatus from './UpdaterStatus.vue';
+ import FormButton from '../common/FormButton.vue';
export default {
data() {
@@ -49,7 +49,8 @@
components: {
SettingsWrapper,
UpdaterToggle,
- UpdaterStatus
+ UpdaterStatus,
+ FormButton
},
computed: {
updatesAvailable() {
@@ -66,11 +67,20 @@
},
bdUpdates() {
return this.updater.bdUpdates;
+ },
+ updatesSelected() {
+ return this.updater.updates.bd.find(update => update.status.update);
+ },
+ updating() {
+ return this.updater.updates.bd.find(update => update.status.updating);
}
},
methods: {
update() {
this.updater.startUpdate();
+ },
+ isDisabled(update) {
+ return Globals.disableUpdater.includes(update.id);
}
}
}
diff --git a/core/src/main.js b/core/src/main.js
index 85c6dd1a..2cb6e69c 100644
--- a/core/src/main.js
+++ b/core/src/main.js
@@ -38,7 +38,10 @@ const TEST_ARGS = () => {
'editor': path.resolve(_basePath, 'editor', 'dist'),
// tmp: path.join(_basePath, 'tmp')
tmp: path.join(os.tmpdir(), 'betterdiscord', `${process.getuid()}`)
- }
+ },
+ disableUpdater: [
+ 'core', 'client', 'editor'
+ ]
}
}
const TEST_EDITOR = TESTS && true;
diff --git a/core/src/modules/config.js b/core/src/modules/config.js
index 43559729..b38e4e95 100644
--- a/core/src/modules/config.js
+++ b/core/src/modules/config.js
@@ -66,7 +66,8 @@ export default class Config extends Module {
return {
version: this.version,
versions: this.versions,
- paths: this.paths
+ paths: this.paths,
+ disableUpdater: this.disableUpdater
};
}
@@ -74,4 +75,9 @@ export default class Config extends Module {
compatibility() {
this.args.paths = Object.entries(this.args.paths).map(([id, path]) => ({ id, path }));
}
+
+ get disableUpdater() {
+ return this.args.disableUpdater || (this.args.disableUpdater = []);
+ }
+
}
diff --git a/core/src/modules/updater.js b/core/src/modules/updater.js
index 786583d1..72ffc444 100644
--- a/core/src/modules/updater.js
+++ b/core/src/modules/updater.js
@@ -90,6 +90,10 @@ export default class Updater extends Module {
async updateBd(update) {
try {
+ if (this.bd.config.disableUpdater.includes(update.id)) {
+ throw {message: `Not installing ${update.id} as updates are disabled. Use your package manager to install updates instead.`};
+ }
+
console.log('[BetterDiscord:Updater] Updating', update.id);
await this.downloadTarGz(`https://github.com/JsSucks/BetterDiscordApp${update.remote}`, this.bd.config.getPath('base'));
this.updateFinished(update);
@@ -117,6 +121,12 @@ export default class Updater extends Module {
// TODO cleaner
if (bd.length) {
for (const update of bd) {
+ if (this.bd.config.disableUpdater.includes(update.id)) {
+ update.error = {message: `Not installing ${update.id} as updates are disabled. Use your package manager to install updates instead.`};
+ this.bd.sendToDiscord('updater-updateError', update);
+ continue;
+ }
+
try {
await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`);
// Try to rename dirs first
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index 1f1c3332..44ec5b1e 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -1,3 +1,5 @@
+import path from 'path';
+import fs from 'fs';
import gulp from 'gulp';
import pump from 'pump';
import del from 'del';
@@ -8,6 +10,7 @@ import replace from 'gulp-replace';
import copydeps from './scripts/copydeps';
import file from 'gulp-file';
import editjson from 'gulp-json-editor';
+import {mkdeb} from './scripts/dpkg';
import corepkg from './core/package';
import clientpkg from './client/package';
@@ -153,3 +156,50 @@ gulp.task('del-release', function() {
gulp.task('dependencies', gulp.series('node-modules', gulp.parallel('node-sass-bindings', 'keytar-bindings')));
gulp.task('build-release', gulp.parallel('core-release', 'client-release', 'editor-release', 'dependencies'));
gulp.task('release', gulp.series('del-release', 'build-release'));
+
+// Debian packages
+
+gulp.task('build-inject-deb', function () {
+ const control = fs.readFileSync(path.join(__dirname, 'other', 'deb', 'control', 'control'), 'utf-8');
+ const version = (control.match(/^Version:\s*(.*)$/m) || [, '1.0.0'])[1];
+ const arch = (control.match(/^Architecture:\s*(.*)$/m) || [, 'all'])[1];
+
+ return mkdeb(`betterdiscord_${version}-${arch}`, 'other/deb/injector/**/*', '/usr/share/discord/resources/app', 'other/deb/control/**/*');
+});
+
+gulp.task('build-inject-deb-ptb', function () {
+ const control = fs.readFileSync(path.join(__dirname, 'other', 'deb', 'control-ptb', 'control'), 'utf-8');
+ const version = (control.match(/^Version:\s*(.*)$/m) || [, '1.0.0'])[1];
+ const arch = (control.match(/^Architecture:\s*(.*)$/m) || [, 'all'])[1];
+
+ return mkdeb(`betterdiscord-ptb_${version}-${arch}`, 'other/deb/injector/**/*', '/usr/share/discord-ptb/resources/app', 'other/deb/control-ptb/**/*');
+});
+
+gulp.task('build-inject-deb-canary', function () {
+ const control = fs.readFileSync(path.join(__dirname, 'other', 'deb', 'control-canary', 'control'), 'utf-8');
+ const version = (control.match(/^Version:\s*(.*)$/m) || [, '1.0.0'])[1];
+ const arch = (control.match(/^Architecture:\s*(.*)$/m) || [, 'all'])[1];
+
+ return mkdeb(`betterdiscord-canary_${version}-${arch}`, 'other/deb/injector/**/*', '/usr/share/discord-canary/resources/app', 'other/deb/control-canary/**/*');
+});
+
+gulp.task('build-inject-debs', gulp.series('build-inject-deb', 'build-inject-deb-ptb', 'build-inject-deb-canary'));
+
+gulp.task('build-core-deb', function () {
+ return mkdeb(`betterdiscord-core_${corepkg.version}-all`, 'release/core/**/*', '/usr/lib/betterdiscord/core', 'other/deb/control-core/**/*', {
+ VERSION: corepkg.version
+ });
+});
+
+gulp.task('build-client-deb', function () {
+ return mkdeb(`betterdiscord-client_${clientpkg.version}-all`, 'release/client/**/*', '/usr/lib/betterdiscord/client', 'other/deb/control-client/**/*', {
+ VERSION: clientpkg.version
+ });
+});
+
+gulp.task('build-editor-deb', function () {
+ return mkdeb(`betterdiscord-editor_${editorpkg.version}-all`, 'release/editor/**/*', '/usr/lib/betterdiscord/editor', 'other/deb/control-editor/**/*', {
+ VERSION: editorpkg.version
+ });
+});
+gulp.task('build-debs', gulp.series('build-inject-debs', 'build-core-deb', 'build-client-deb', 'build-editor-deb'));
diff --git a/other/deb/control-canary/conffiles b/other/deb/control-canary/conffiles
new file mode 100644
index 00000000..85690f30
--- /dev/null
+++ b/other/deb/control-canary/conffiles
@@ -0,0 +1 @@
+/usr/share/discord-canary/resources/app/bd.json
diff --git a/other/deb/control-canary/control b/other/deb/control-canary/control
new file mode 100644
index 00000000..1d9d8e91
--- /dev/null
+++ b/other/deb/control-canary/control
@@ -0,0 +1,6 @@
+Package: betterdiscord-canary
+Version: 1.0.0
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2 for Discord Canary
+Depends: discord-canary, betterdiscord-core, betterdiscord-client, betterdiscord-editor
diff --git a/other/deb/control-client/control b/other/deb/control-client/control
new file mode 100644
index 00000000..0f99bbcf
--- /dev/null
+++ b/other/deb/control-client/control
@@ -0,0 +1,5 @@
+Package: betterdiscord-client
+Version: ${VERSION}
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2 client bundle
diff --git a/other/deb/control-core/control b/other/deb/control-core/control
new file mode 100644
index 00000000..3f24ef1d
--- /dev/null
+++ b/other/deb/control-core/control
@@ -0,0 +1,6 @@
+Package: betterdiscord-core
+Version: ${VERSION}
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2 core files
+Depends: libsecret-1-0
diff --git a/other/deb/control-editor/control b/other/deb/control-editor/control
new file mode 100644
index 00000000..8e709644
--- /dev/null
+++ b/other/deb/control-editor/control
@@ -0,0 +1,5 @@
+Package: betterdiscord-editor
+Version: ${VERSION}
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2 editor bundle
diff --git a/other/deb/control-ptb/conffiles b/other/deb/control-ptb/conffiles
new file mode 100644
index 00000000..bc6d142a
--- /dev/null
+++ b/other/deb/control-ptb/conffiles
@@ -0,0 +1 @@
+/usr/share/discord-ptb/resources/app/bd.json
diff --git a/other/deb/control-ptb/control b/other/deb/control-ptb/control
new file mode 100644
index 00000000..3197c345
--- /dev/null
+++ b/other/deb/control-ptb/control
@@ -0,0 +1,6 @@
+Package: betterdiscord-ptb
+Version: 1.0.0
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2 for Discord PTB
+Depends: discord-ptb, betterdiscord-core, betterdiscord-client, betterdiscord-editor
diff --git a/other/deb/control/conffiles b/other/deb/control/conffiles
new file mode 100644
index 00000000..ba51c5b5
--- /dev/null
+++ b/other/deb/control/conffiles
@@ -0,0 +1 @@
+/usr/share/discord/resources/app/bd.json
diff --git a/other/deb/control/control b/other/deb/control/control
new file mode 100644
index 00000000..aa4c66b8
--- /dev/null
+++ b/other/deb/control/control
@@ -0,0 +1,6 @@
+Package: betterdiscord
+Version: 1.0.0
+Architecture: all
+Maintainer: -
+Description: BetterDiscord v2
+Depends: discord, betterdiscord-core, betterdiscord-client, betterdiscord-editor
diff --git a/other/deb/injector/bd.json b/other/deb/injector/bd.json
new file mode 100644
index 00000000..2cd85c2a
--- /dev/null
+++ b/other/deb/injector/bd.json
@@ -0,0 +1,19 @@
+{
+ "options": {
+ "autoInject": true,
+ "commonCore": true,
+ "commonData": true
+ },
+ "paths": {
+ "core": "/usr/lib/betterdiscord/core",
+ "client": "/usr/lib/betterdiscord/client",
+ "editor": "/usr/lib/betterdiscord/editor",
+ "data": ".config/betterdiscord/data",
+ "userconfig": ".config/betterdiscord/bd"
+ },
+ "disableUpdater": [
+ "core",
+ "client",
+ "editor"
+ ]
+}
diff --git a/other/deb/injector/index.js b/other/deb/injector/index.js
new file mode 100644
index 00000000..b0e0c530
--- /dev/null
+++ b/other/deb/injector/index.js
@@ -0,0 +1,23 @@
+const bdinfo = require('./bd');
+const { app } = require('electron');
+const path = require('path');
+const os = require('os');
+const Module = require('module');
+
+const packagePath = path.join(__dirname, '..', 'app.asar');
+app.getAppPath = () => packagePath;
+
+function loadBd() {
+ const userconfig = (() => {
+ try {
+ return require(path.resolve(os.homedir(), bdinfo.paths.userconfig));
+ } catch (err) {}
+ })() || {};
+
+ const { BetterDiscord } = require(path.resolve(os.homedir(), (userconfig.paths || {}).core || bdinfo.paths.core));
+ const instance = new BetterDiscord(bdinfo, userconfig);
+}
+
+app.on('ready', loadBd);
+
+Module._load(app.getAppPath(), null, true);
diff --git a/other/deb/injector/package.json b/other/deb/injector/package.json
new file mode 100644
index 00000000..8ff69de1
--- /dev/null
+++ b/other/deb/injector/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "discord",
+ "description": "Discord Client for Desktop - Bootstrapper",
+ "main": "index.js",
+ "private": true
+}
diff --git a/package-lock.json b/package-lock.json
index e198080c..4cbd03c5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "betterdiscord",
- "version": "2.0.0-beta.4",
+ "version": "2.0.0-beta.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1216,6 +1216,12 @@
"integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
"dev": true
},
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
+ "dev": true
+ },
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
@@ -2008,6 +2014,12 @@
"integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
"dev": true
},
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true
+ },
"cacache": {
"version": "11.3.2",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
@@ -5359,6 +5371,32 @@
}
}
},
+ "gulp-gzip": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz",
+ "integrity": "sha512-ZIxfkUwk2XmZPTT9pPHrHUQlZMyp9nPhg2sfoeN27mBGpi7OaHnOD+WCN41NXjfJQ69lV1nQ9LLm1hYxx4h3UQ==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^1.0.1",
+ "bytes": "^3.0.0",
+ "fancy-log": "^1.3.2",
+ "plugin-error": "^1.0.0",
+ "stream-to-array": "^2.3.0",
+ "through2": "^2.0.3"
+ },
+ "dependencies": {
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ }
+ }
+ },
"gulp-inject-string": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/gulp-inject-string/-/gulp-inject-string-1.1.2.tgz",
@@ -5410,6 +5448,141 @@
"replacestream": "^4.0.0"
}
},
+ "gulp-tar": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/gulp-tar/-/gulp-tar-2.1.0.tgz",
+ "integrity": "sha512-Yp/57bpiZPDVajUJix6QRCpL+XCNNFuaEcDVJ33LzenbGUkpJrH8j+8xJoMNlyi902uXV7rBy5sihwBnu5OfFw==",
+ "dev": true,
+ "requires": {
+ "archiver": "^1.0.0",
+ "plugin-error": "^0.1.2",
+ "through2": "^2.0.0",
+ "vinyl": "^2.1.0"
+ },
+ "dependencies": {
+ "archiver": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz",
+ "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^1.3.0",
+ "async": "^2.0.0",
+ "buffer-crc32": "^0.2.1",
+ "glob": "^7.0.0",
+ "lodash": "^4.8.0",
+ "readable-stream": "^2.0.0",
+ "tar-stream": "^1.5.0",
+ "walkdir": "^0.0.11",
+ "zip-stream": "^1.1.0"
+ }
+ },
+ "archiver-utils": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz",
+ "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=",
+ "dev": true,
+ "requires": {
+ "glob": "^7.0.0",
+ "graceful-fs": "^4.1.0",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.8.0",
+ "normalize-path": "^2.0.0",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "arr-diff": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
+ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1",
+ "array-slice": "^0.2.3"
+ }
+ },
+ "arr-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
+ "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
+ "dev": true
+ },
+ "array-slice": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+ "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
+ "dev": true
+ },
+ "async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+ "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "extend-shallow": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
+ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^1.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
+ "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "plugin-error": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
+ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
+ "dev": true,
+ "requires": {
+ "ansi-cyan": "^0.1.1",
+ "ansi-red": "^0.1.1",
+ "arr-diff": "^1.0.1",
+ "arr-union": "^2.0.1",
+ "extend-shallow": "^1.1.2"
+ }
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "zip-stream": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
+ "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^1.3.0",
+ "compress-commons": "^1.2.0",
+ "lodash": "^4.8.0",
+ "readable-stream": "^2.0.0"
+ }
+ }
+ }
+ },
"gulp-watch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz",
@@ -7162,6 +7335,12 @@
}
}
},
+ "merge2": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz",
+ "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==",
+ "dev": true
+ },
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
@@ -8610,6 +8789,57 @@
"requires": {
"speedometer": "~0.1.2",
"through2": "~0.2.3"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "object-keys": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
+ "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "through2": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
+ "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~1.1.9",
+ "xtend": "~2.1.1"
+ }
+ },
+ "xtend": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
+ "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
+ "dev": true,
+ "requires": {
+ "object-keys": "~0.4.0"
+ }
+ }
}
},
"promise-inflight": {
@@ -10150,6 +10380,15 @@
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
"dev": true
},
+ "stream-to-array": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz",
+ "integrity": "sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.1.0"
+ }
+ },
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@@ -10499,54 +10738,12 @@
"dev": true
},
"through2": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
- "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+ "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
"dev": true,
"requires": {
- "readable-stream": "~1.1.9",
- "xtend": "~2.1.1"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "object-keys": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
- "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
- "dev": true
- },
- "readable-stream": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
- "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- },
- "xtend": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
- "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
- "dev": true,
- "requires": {
- "object-keys": "~0.4.0"
- }
- }
+ "readable-stream": "2 || 3"
}
},
"through2-filter": {
@@ -11388,6 +11585,12 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
+ "walkdir": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz",
+ "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=",
+ "dev": true
+ },
"watchpack": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
diff --git a/package.json b/package.json
index 6c3584c7..65386fff 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"fs-extra": "^7.0.1",
"keytar": "4.4.1",
"nedb": "^1.8.0",
- "node-sass": "^4.11.0",
+ "node-sass": "4.11.0",
"original-fs": "^1.0.0",
"semver": "^5.6.0",
"tar-fs": "^2.0.0"
@@ -51,15 +51,18 @@
"gulp-babel": "^8.0.0",
"gulp-copy": "^4.0.1",
"gulp-file": "^0.4.0",
+ "gulp-gzip": "^1.4.2",
"gulp-inject-string": "^1.1.2",
"gulp-json-editor": "^2.5.1",
"gulp-rename": "^1.4.0",
"gulp-replace": "^1.0.0",
+ "gulp-tar": "^2.1.0",
"gulp-watch": "^5.0.1",
"hash-files": "^1.1.1",
"html-webpack-plugin": "^3.2.0",
"jquery": "^3.3.1",
"lodash": "^4.17.11",
+ "merge2": "^1.2.3",
"mkdirp": "^0.5.1",
"node-gyp": "^3.8.0",
"parallel-webpack": "^2.3.0",
@@ -67,6 +70,7 @@
"request-promise-native": "1.0.5",
"sass-lint": "^1.12.1",
"sass-loader": "^7.1.0",
+ "through2": "^3.0.1",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.6.8",
"vue-color": "^2.7.0",
@@ -100,6 +104,14 @@
"release": "npm run lint && npm run build_release && gulp release && npm run package_release",
"release_test": "npm run build_release && gulp release",
"update_release": "npm run build_release && gulp release",
+ "build_inject_deb": "gulp build-inject-deb",
+ "build_inject-ptb_deb": "gulp build-inject-deb-ptb",
+ "build_inject-canary_deb": "gulp build-inject-deb-canary",
+ "build_inject_debs": "gulp build-inject-debs",
+ "build_core_deb": "gulp build-core-deb",
+ "build_client_deb": "gulp build-client-deb",
+ "build_editor_deb": "gulp build-editor-deb",
+ "build_debs": "gulp build-debs",
"inject": "node scripts/inject.js"
}
}
diff --git a/scripts/dpkg.js b/scripts/dpkg.js
new file mode 100644
index 00000000..d29f6d77
--- /dev/null
+++ b/scripts/dpkg.js
@@ -0,0 +1,155 @@
+const path = require('path');
+const stream = require('stream');
+const through2 = require('through2');
+const gulp = require('gulp');
+const Vinyl = require('vinyl');
+const pump = require('pump');
+const merge = require('merge2');
+const tar = require('gulp-tar');
+const gzip = require('gulp-gzip');
+const file = require('gulp-file');
+const replace = require('gulp-replace');
+const rename = require('gulp-rename');
+
+/**
+ * Return a transform stream that create a Debian package from debian-binary, control.tar and data.tar files.
+ * @param {string} name The name of the .deb file to create
+ * @return {stream.TransformStream}
+ */
+function deb(name) {
+ const files = [];
+
+ return through2({objectMode: true}, (file, enc, callback) => {
+ files.push(file);
+ callback(null, file);
+ }, function (callback) { (async () => {
+ const orderedfiles = [new Vinyl({path: '/debian-binary', contents: Buffer.from('2.0\n')})];
+ orderedfiles.push(files.find(f => f.path.match(/\/control\.tar(\.gz)?$/)));
+ orderedfiles.push(files.find(f => f.path.match(/\/data\.tar(\.gz)?$/)));
+ if (orderedfiles.length !== 3) throw new Error('Must have three files');
+
+ const contents = new stream.Readable();
+ contents._read = () => {};
+
+ const debfile = new Vinyl({
+ cwd: '/',
+ base: '/',
+ path: '/' + name,
+ contents
+ });
+
+ contents.push('!' + String.fromCharCode(0x0A)); // Signature
+
+ for (const [index, file] of orderedfiles.entries()) {
+ const size = file.stat && file.stat.size ? file.stat.size : file.contents && file.contents.length ? file.contents.length : 0;
+
+ contents.push(rightPaddedWithSpaces(16, path.basename(file.path))); // Filename (ASCII, 16 bytes long)
+ contents.push(rightPaddedWithSpaces(12, (Math.floor(file.stat ? file.stat.mtime / 1000 : 0)).toString())); // File modification timestamp (Decimal, 12 bytes long)
+ contents.push(rightPaddedWithSpaces(6, '0')); // Owner ID (Decimal, 6 bytes long)
+ contents.push(rightPaddedWithSpaces(6, '0')); // Group ID (Decimal, 6 bytes long)
+ contents.push(rightPaddedWithSpaces(8, '100644')); // File mode (Octal, 8 bytes long)
+ contents.push(rightPaddedWithSpaces(10, size.toString())); // File size in bytes (Decimal, 10 bytes long)
+ contents.push(String.fromCharCode(0x60) + String.fromCharCode(0x0A)); // Ending characters ("0x60 0x0A")
+
+ if (file.isStream()) await new Promise((resolve, reject) => {
+ file.contents.on('data', data => contents.push(data));
+ file.contents.on('end', resolve);
+ file.contents.on('error', reject);
+ }); else contents.push(file.contents);
+
+ // If the data for an archive member ends at an odd byte offset, then a padding byte with value 0x0A is
+ // used to position the next archive header on an even byte offset.
+ if (size % 2 === 1 && index !== 2) {
+ contents.push(String.fromCharCode(0x0A));
+ }
+ }
+
+ contents.push(null);
+
+ this.push(debfile);
+ callback();
+ })().catch(err => {
+ console.error(err);
+ callback(err);
+ }); });
+}
+
+function rightPaddedWithSpaces(n, string) {
+ if (!string) string = '';
+ if (string.length > n) throw new Error('string is longer than n padding');
+ return string + (new Array(n - string.length + 1)).join(String.fromCharCode(0x20));
+}
+
+function ensuredirectories() {
+ const directories = [];
+
+ return through2.obj(function (file, enc, callback) {
+ const name = file.relative;
+ const nameparts = name.split('/');
+
+ if (file.isDirectory()) {
+ if (!directories.includes(file.name)) directories.push(file.name);
+ } else {
+ for (let [index, part] of nameparts.slice(0, nameparts.length - 1).entries()) {
+ let partpath = part;
+ while (index > 0) {
+ index--;
+ partpath = nameparts[index] + '/' + partpath;
+ }
+
+ if (directories.includes(partpath)) continue;
+
+ const directory = new Vinyl({
+ cwd: file.cwd,
+ base: file.base,
+ path: path.join(file.base, partpath),
+ stat: {
+ isDirectory: () => true
+ }
+ });
+
+ this.push(directory);
+ directories.push(partpath);
+ }
+ }
+
+ callback(null, file);
+ });
+}
+
+/**
+ * Creates a Debian package.
+ * @param {string} name
+ * @param {string} datafiles Path to the data directory
+ * @param {string} dataprefix The directory the files in the data directory should be unpacked to when installing
+ * @param {string} controlfiles Path to the control directory
+ * @param {Object} [controlvars] Variables to replace in the control files
+ * @return {stream.TransformStream}
+ */
+function mkdeb(name, datafiles, dataprefix, controlfiles, controlvars) {
+ return pump([
+ merge([
+ pump([
+ gulp.src(controlfiles),
+ ...Object.keys(controlvars || {}).map(k => replace(`\${${k}}`, controlvars[k])),
+ tar('control.tar'),
+ gzip()
+ ]),
+ pump([
+ gulp.src(datafiles),
+ rename(p => p.dirname = dataprefix + '/' + p.dirname),
+ ensuredirectories(),
+ tar(name + '.tar'),
+ gzip(),
+ gulp.dest('release'),
+ rename(p => p.basename = 'data.tar')
+ ])
+ ]),
+
+ deb(name + '.deb'),
+ gulp.dest('release')
+ ]);
+}
+
+exports.deb = deb;
+exports.mkdeb = mkdeb;