Merge pull request #1 from vector-im/dbkr/make_it_work

Build electron app from pre-built tarball
This commit is contained in:
David Baker 2019-12-09 14:50:01 +00:00 committed by GitHub
commit 4cad44a54f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 3211 additions and 21 deletions

8
.buildkite/pipeline.yaml Normal file
View file

@ -0,0 +1,8 @@
steps:
- label: ":eslint: Lint"
command:
- "yarn install"
- "yarn lint"
plugins:
- docker#v3.0.1:
image: "node:10"

19
.eslintrc.js Normal file
View file

@ -0,0 +1,19 @@
const jsSdkEslintCfg = require('matrix-js-sdk/.eslintrc');
module.exports = {
parserOptions: {
ecmaVersion: 8,
},
env: {
node: true,
// we also have some browser code (ie. the preload script)
browser: true,
},
extends: ["eslint:recommended", "google"],
rules: jsSdkEslintCfg.rules,
}
// js-sdk uses a babel rule which we can't use because we
// don't use babel, so remove it & put the original back
delete module.exports.rules["babel/no-invalid-this"];
module.exports.rules["no-invalid-this"] = "error";

7
README Normal file
View file

@ -0,0 +1,7 @@
Riot Desktop
============
This is *not* where the source for Riot desktop lives... yet. As of now,
it still lives in the main riot-web repo: https://github.com/vector-im/riot-web
This is an experimental split-out of the Riot desktop code from the main repo.

87
package.json Normal file
View file

@ -0,0 +1,87 @@
{
"name": "riot-desktop",
"productName": "Riot",
"main": "src/electron-main.js",
"version": "1.5.5",
"description": "A feature-rich client for Matrix.org",
"author": "New Vector Ltd.",
"repository": {
"type": "git",
"url": "https://github.com/vector-im/riot-desktop"
},
"license": "Apache-2.0",
"files": [],
"scripts": {
"mkdirs": "mkdir -p packages && mkdir -p deploys",
"fetch": "yarn run mkdirs && scripts/fetch-package.js",
"check": "scripts/check-webapp.js",
"start": "yarn run check && yarn install:electron && electron .",
"install:electron": "electron-builder install-app-deps",
"lint": "eslint src/",
"build:electron": "yarn check && electron-builder",
"clean": "rimraf webapp dist packages deploys"
},
"dependencies": {
"auto-launch": "^5.0.1",
"electron-store": "^2.0.0",
"electron-window-state": "^4.1.0",
"minimist": "^1.2.0",
"png-to-ico": "^1.0.2"
},
"devDependencies": {
"electron-builder": "^21.2.0",
"electron-builder-squirrel-windows": "^21.2.0",
"electron-devtools-installer": "^2.2.4",
"electron-notarize": "^0.2.0",
"eslint": "^5.8.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-babel": "^4.1.2",
"follow-redirects": "^1.9.0",
"matrix-js-sdk": "^2.4.6-rc.1",
"tar": "^5.0.5"
},
"build": {
"appId": "im.riot.app",
"electronVersion": "7.1.3",
"files": [
"node_modules/**",
"src/**"
],
"extraResources": [
{
"from": "res/img",
"to": "img"
},
"webapp/**/*"
],
"linux": {
"target": "deb",
"category": "Network;InstantMessaging;Chat",
"maintainer": "support@riot.im",
"desktop": {
"StartupWMClass": "riot"
}
},
"deb": {
"afterInstall": "build/linux/after-install.tpl"
},
"mac": {
"category": "public.app-category.social-networking",
"darkModeSupport": true
},
"win": {
"target": {
"target": "squirrel",
"arch": [
"x64",
"ia32"
]
},
"sign": "scripts/electron_winSign"
},
"directories": {
"output": "dist"
},
"afterSign": "scripts/electron_afterSign.js"
}
}

15
scripts/check-webapp.js Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env node
const fs = require('fs').promises;
async function main() {
try {
const webappDir = await fs.opendir('webapp');
return 0;
} catch (e) {
console.log("No 'webapp' directory found. Run 'yarn run fetch' or symlink manually");
return 1;
}
}
main().then((ret) => process.exit(ret));

184
scripts/fetch-package.js Executable file
View file

@ -0,0 +1,184 @@
#!/usr/bin/env node
const process = require('process');
const path = require('path');
const fs = require('fs');
const fsPromises = require('fs').promises;
const { https } = require('follow-redirects');
const child_process = require('child_process');
const tar = require('tar');
const riotDesktopPackageJson = require('../package.json');
const PUB_KEY_URL = "https://packages.riot.im/riot-release-key.asc";
const PACKAGE_URL_PREFIX = "https://github.com/vector-im/riot-web/releases/download/";
async function downloadToFile(url, filename) {
console.log("Downloading " + url + "...");
const outStream = await fs.createWriteStream(filename);
return new Promise((resolve, reject) => {
https.get(url, (resp) => {
if (resp.statusCode / 100 !== 2) {
reject("Download failed: " + resp.statusCode);
return;
}
resp.on('data', (chunk) => {
outStream.write(chunk);
});
resp.on('end', (chunk) => {
outStream.end();
resolve();
});
});
}).catch(async (e) => {
outStream.end();
await fsPromises.unlink(filename);
throw e;
});
}
async function verifyFile(filename) {
return new Promise((resolve, reject) => {
const gpgProc = child_process.execFile('gpg', ['--verify', filename + '.asc', filename], (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
async function main() {
let verify = true;
let importkey = false;
let pkgDir = 'packages';
let deployDir = 'deploys';
let targetVersion;
while (process.argv.length > 2) {
switch (process.argv[2]) {
case '--noverify':
verify = false;
break;
case '--importkey':
importkey = true;
break;
case '--packages':
process.argv.shift();
pkgDir = process.argv[2];
break;
case '--deploys':
process.argv.shift();
deployDir = process.argv[2];
break;
default:
targetVersion = process.argv[2];
}
process.argv.shift();
}
if (targetVersion === undefined) {
targetVersion = 'v' + riotDesktopPackageJson.version;
}
const haveGpg = await new Promise((resolve) => {
child_process.execFile('gpg', ['--version'], (error) => {
resolve(!error);
});
});
if (importkey) {
if (!haveGpg) {
console.log("Can't import key without working GPG binary: install GPG and try again");
return 1;
}
await new Promise((resolve) => {
const gpgProc = child_process.execFile('gpg', ['--import'], (error) => {
if (error) {
console.log("Failed to import key", error);
} else {
console.log("Key imported!");
}
resolve(!error);
});
https.get(PUB_KEY_URL, (resp) => {
resp.on('data', (chunk) => {
gpgProc.stdin.write(chunk);
});
resp.on('end', (chunk) => {
gpgProc.stdin.end();
});
});
});
}
if (verify && !haveGpg) {
console.log("No working GPG binary: install GPG or pass --noverify to skip verification");
return 1;
}
const haveDeploy = false;
const expectedDeployDir = path.join(deployDir, 'riot-' + targetVersion);
try {
const webappDir = await fs.opendir(expectedDeployDir);
console.log(expectedDeployDir + "already exists");
haveDeploy = true;
} catch (e) {
}
if (!haveDeploy) {
const filename = 'riot-' + targetVersion + '.tar.gz';
const outPath = path.join(pkgDir, filename);
const url = PACKAGE_URL_PREFIX + targetVersion + '/' + filename;
try {
await fsPromises.stat(outPath);
console.log("Already have " + filename + ": not redownloading");
} catch (e) {
try {
await downloadToFile(url, outPath);
} catch (e) {
console.log("Failed to download " + url, e);
return 1;
}
}
if (verify) {
try {
await fsPromises.stat(outPath+'.asc');
console.log("Already have " + filename + ".asc: not redownloading");
} catch (e) {
try {
await downloadToFile(url + '.asc', outPath + '.asc');
} catch (e) {
console.log("Failed to download " + url, e);
return 1;
}
}
try {
await verifyFile(outPath);
console.log(outPath + " downloaded and verified");
} catch (e) {
console.log("Signature verification failed!", e);
return 1;
}
} else {
console.log(outPath + " downloaded but NOT verified");
}
await tar.x({
file: outPath,
cwd: deployDir,
});
}
console.log("Symlink " + expectedDeployDir + " -> webapp");
// Does this do a sensible thing on Windows?
await fsPromises.symlink(expectedDeployDir, 'webapp');
}
main().then((ret) => process.exit(ret));

View file

@ -35,7 +35,6 @@ const tray = require('./tray');
const vectorMenu = require('./vectormenu');
const webContentsHandler = require('./webcontents-handler');
const updater = require('./updater');
const { migrateFromOldOrigin } = require('./originMigrator');
const windowStateKeeper = require('electron-window-state');
const Store = require('electron-store');
@ -64,11 +63,6 @@ if (argv["help"]) {
app.exit();
}
// boolean flag set whilst we are doing one-time origin migration
// We only serve the origin migration script while we're actually
// migrating to mitigate any risk of it being used maliciously.
let migratingOrigin = false;
if (argv['profile-dir']) {
app.setPath('userData', argv['profile-dir']);
} else if (argv['profile']) {
@ -77,7 +71,7 @@ if (argv['profile-dir']) {
let vectorConfig = {};
try {
vectorConfig = require('../../webapp/config.json');
vectorConfig = require('../webapp/config.json');
} catch (e) {
// it would be nice to check the error code here and bail if the config
// is unparseable, but we get MODULE_NOT_FOUND in the case of a missing
@ -231,11 +225,6 @@ ipcMain.on('ipcCall', async function(ev, payload) {
mainWindow.focus();
}
break;
case 'origin_migrate':
migratingOrigin = true;
await migrateFromOldOrigin();
migratingOrigin = false;
break;
case 'getConfig':
ret = vectorConfig;
break;
@ -476,15 +465,8 @@ app.on('ready', () => {
}
let baseDir;
// first part of the path determines where we serve from
if (migratingOrigin && target[1] === 'origin_migrator_dest') {
// the origin migrator destination page
// (only the destination script needs to come from the
// custom protocol: the source part is loaded from a
// file:// as that's the origin we're migrating from).
baseDir = __dirname + "/../../origin_migrator/dest";
} else if (target[1] === 'webapp') {
baseDir = __dirname + "/../../webapp";
if (target[1] === 'webapp') {
baseDir = path.join(__dirname, "../webapp");
} else {
callback({error: -6}); // FILE_NOT_FOUND
return;

2888
yarn.lock Normal file

File diff suppressed because it is too large Load diff