mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-12 20:18:41 -09:00
Use same hazel endpoint to notify update to Linux users (#2497)
Add a pseudo auto-updater for Linux Fixes #2476
This commit is contained in:
parent
59273ddb2a
commit
1fbc85760b
8 changed files with 114 additions and 33 deletions
50
app/auto-updater-linux.js
Normal file
50
app/auto-updater-linux.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const {EventEmitter} = require('events');
|
||||||
|
|
||||||
|
class AutoUpdater extends EventEmitter {
|
||||||
|
quitAndInstall() {
|
||||||
|
this.emitError('QuitAndInstall unimplemented');
|
||||||
|
}
|
||||||
|
getFeedURL() {
|
||||||
|
return this.updateURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFeedURL(updateURL) {
|
||||||
|
this.updateURL = updateURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdates() {
|
||||||
|
if (!this.updateURL) {
|
||||||
|
return this.emitError('Update URL is not set');
|
||||||
|
}
|
||||||
|
this.emit('checking-for-update');
|
||||||
|
|
||||||
|
fetch(this.updateURL)
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 204) {
|
||||||
|
return this.emit('update-not-available');
|
||||||
|
}
|
||||||
|
return res.json().then(({name, notes, pub_date}) => {
|
||||||
|
// Only name is mandatory, needed to construct release URL.
|
||||||
|
if (!name) {
|
||||||
|
throw new Error('Malformed server response: release name is missing.');
|
||||||
|
}
|
||||||
|
// If `null` is passed to Date constructor, current time will be used. This doesn't work with `undefined`
|
||||||
|
const date = new Date(pub_date || null);
|
||||||
|
this.emit('update-available', {}, notes, name, date);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(this.emitError.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
emitError(error) {
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
error = new Error(error);
|
||||||
|
}
|
||||||
|
this.emit('error', error, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new AutoUpdater();
|
||||||
|
|
@ -4,7 +4,7 @@ const {parse: parseUrl} = require('url');
|
||||||
const uuid = require('uuid');
|
const uuid = require('uuid');
|
||||||
const fileUriToPath = require('file-uri-to-path');
|
const fileUriToPath = require('file-uri-to-path');
|
||||||
const isDev = require('electron-is-dev');
|
const isDev = require('electron-is-dev');
|
||||||
const AutoUpdater = require('../auto-updater');
|
const updater = require('../updater');
|
||||||
const toElectronBackgroundColor = require('../utils/to-electron-background-color');
|
const toElectronBackgroundColor = require('../utils/to-electron-background-color');
|
||||||
const {icon, cfgDir} = require('../config/paths');
|
const {icon, cfgDir} = require('../config/paths');
|
||||||
const createRPC = require('../rpc');
|
const createRPC = require('../rpc');
|
||||||
|
|
@ -76,8 +76,8 @@ module.exports = class Window {
|
||||||
delete app.windowCallback;
|
delete app.windowCallback;
|
||||||
fetchNotifications(window);
|
fetchNotifications(window);
|
||||||
// auto updates
|
// auto updates
|
||||||
if (!isDev && process.platform !== 'linux') {
|
if (!isDev) {
|
||||||
AutoUpdater(window);
|
updater(window);
|
||||||
} else {
|
} else {
|
||||||
//eslint-disable-next-line no-console
|
//eslint-disable-next-line no-console
|
||||||
console.log('ignoring auto updates during dev');
|
console.log('ignoring auto updates during dev');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// Packages
|
// Packages
|
||||||
const {autoUpdater, app} = require('electron');
|
const electron = require('electron');
|
||||||
|
const {app} = electron;
|
||||||
const ms = require('ms');
|
const ms = require('ms');
|
||||||
const retry = require('async-retry');
|
const retry = require('async-retry');
|
||||||
|
|
||||||
|
|
@ -7,17 +8,20 @@ const retry = require('async-retry');
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const notify = require('./notify');
|
const notify = require('./notify');
|
||||||
const {version} = require('./package');
|
const {version} = require('./package');
|
||||||
const {getConfig} = require('./config');
|
const {getDecoratedConfig} = require('./plugins');
|
||||||
|
|
||||||
const {platform} = process;
|
const {platform} = process;
|
||||||
|
const isLinux = platform === 'linux';
|
||||||
|
|
||||||
|
const autoUpdater = isLinux ? require('./auto-updater-linux') : electron.autoUpdater;
|
||||||
|
|
||||||
let isInit = false;
|
let isInit = false;
|
||||||
// Default to the "stable" update channel
|
// Default to the "stable" update channel
|
||||||
let canaryUpdates = false;
|
let canaryUpdates = false;
|
||||||
|
|
||||||
const buildFeedUrl = canary => {
|
const buildFeedUrl = (canary, currentVersion) => {
|
||||||
const updatePrefix = canary ? 'releases-canary' : 'releases';
|
const updatePrefix = canary ? 'releases-canary' : 'releases';
|
||||||
return `https://${updatePrefix}.hyper.is/update/${platform}`;
|
return `https://${updatePrefix}.hyper.is/update/${isLinux ? 'deb' : platform}/${currentVersion}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCanary = updateChannel => updateChannel === 'canary';
|
const isCanary = updateChannel => updateChannel === 'canary';
|
||||||
|
|
@ -29,7 +33,7 @@ async function init() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const config = await retry(async () => {
|
const config = await retry(async () => {
|
||||||
const content = await getConfig();
|
const content = await getDecoratedConfig();
|
||||||
|
|
||||||
if (!content) {
|
if (!content) {
|
||||||
throw new Error('No config content loaded');
|
throw new Error('No config content loaded');
|
||||||
|
|
@ -43,9 +47,9 @@ async function init() {
|
||||||
canaryUpdates = true;
|
canaryUpdates = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const feedURL = buildFeedUrl(canaryUpdates);
|
const feedURL = buildFeedUrl(canaryUpdates, version);
|
||||||
|
|
||||||
autoUpdater.setFeedURL(`${feedURL}/${version}`);
|
autoUpdater.setFeedURL(feedURL);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
autoUpdater.checkForUpdates();
|
autoUpdater.checkForUpdates();
|
||||||
|
|
@ -65,11 +69,14 @@ module.exports = win => {
|
||||||
|
|
||||||
const {rpc} = win;
|
const {rpc} = win;
|
||||||
|
|
||||||
const onupdate = (ev, releaseNotes, releaseName) => {
|
const onupdate = (ev, releaseNotes, releaseName, date, updateUrl, onQuitAndInstall) => {
|
||||||
rpc.emit('update available', {releaseNotes, releaseName});
|
const releaseUrl = updateUrl || `https://github.com/zeit/hyper/releases/tag/${releaseName}`;
|
||||||
|
rpc.emit('update available', {releaseNotes, releaseName, releaseUrl, canInstall: !!onQuitAndInstall});
|
||||||
};
|
};
|
||||||
|
|
||||||
autoUpdater.on('update-downloaded', onupdate);
|
const eventName = isLinux ? 'update-available' : 'update-downloaded';
|
||||||
|
|
||||||
|
autoUpdater.on(eventName, onupdate);
|
||||||
|
|
||||||
rpc.once('quit and install', () => {
|
rpc.once('quit and install', () => {
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
|
|
@ -80,9 +87,9 @@ module.exports = win => {
|
||||||
const newUpdateIsCanary = isCanary(updateChannel);
|
const newUpdateIsCanary = isCanary(updateChannel);
|
||||||
|
|
||||||
if (newUpdateIsCanary !== canaryUpdates) {
|
if (newUpdateIsCanary !== canaryUpdates) {
|
||||||
const feedURL = buildFeedUrl(newUpdateIsCanary);
|
const feedURL = buildFeedUrl(newUpdateIsCanary, version);
|
||||||
|
|
||||||
autoUpdater.setFeedURL(`${feedURL}/${version}`);
|
autoUpdater.setFeedURL(feedURL);
|
||||||
autoUpdater.checkForUpdates();
|
autoUpdater.checkForUpdates();
|
||||||
|
|
||||||
canaryUpdates = newUpdateIsCanary;
|
canaryUpdates = newUpdateIsCanary;
|
||||||
|
|
@ -90,6 +97,6 @@ module.exports = win => {
|
||||||
});
|
});
|
||||||
|
|
||||||
win.on('close', () => {
|
win.on('close', () => {
|
||||||
autoUpdater.removeListener('update-downloaded', onupdate);
|
autoUpdater.removeListener(eventName, onupdate);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -10,10 +10,12 @@ export function installUpdate() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateAvailable(version, notes) {
|
export function updateAvailable(version, notes, releaseUrl, canInstall) {
|
||||||
return {
|
return {
|
||||||
type: UPDATE_AVAILABLE,
|
type: UPDATE_AVAILABLE,
|
||||||
version,
|
version,
|
||||||
notes
|
notes,
|
||||||
|
releaseUrl,
|
||||||
|
canInstall
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,20 +79,38 @@ export default class Notifications extends PureComponent {
|
||||||
window.require('electron').shell.openExternal(ev.target.href);
|
window.require('electron').shell.openExternal(ev.target.href);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}}
|
}}
|
||||||
href={`https://github.com/zeit/hyper/releases/tag/${this.props.updateVersion}`}
|
href={this.props.updateReleaseUrl}
|
||||||
>
|
>
|
||||||
notes
|
notes
|
||||||
</a>).{' '}
|
</a>).{' '}
|
||||||
<a
|
{this.props.updateCanInstall ? (
|
||||||
style={{
|
<a
|
||||||
cursor: 'pointer',
|
style={{
|
||||||
textDecoration: 'underline',
|
cursor: 'pointer',
|
||||||
fontWeight: 'bold'
|
textDecoration: 'underline',
|
||||||
}}
|
fontWeight: 'bold'
|
||||||
onClick={this.props.onUpdateInstall}
|
}}
|
||||||
>
|
onClick={this.props.onUpdateInstall}
|
||||||
Restart
|
>
|
||||||
</a>.{' '}
|
Restart
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<a
|
||||||
|
style={{
|
||||||
|
color: '#fff',
|
||||||
|
cursor: 'pointer',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}
|
||||||
|
onClick={ev => {
|
||||||
|
window.require('electron').shell.openExternal(ev.target.href);
|
||||||
|
ev.preventDefault();
|
||||||
|
}}
|
||||||
|
href={this.props.updateReleaseUrl}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
)}.{' '}
|
||||||
</Notification>
|
</Notification>
|
||||||
)}
|
)}
|
||||||
{this.props.customChildren}
|
{this.props.customChildren}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,9 @@ const NotificationsContainer = connect(
|
||||||
Object.assign(state_, {
|
Object.assign(state_, {
|
||||||
updateShowing: true,
|
updateShowing: true,
|
||||||
updateVersion: ui.updateVersion,
|
updateVersion: ui.updateVersion,
|
||||||
updateNote: ui.updateNotes.split('\n')[0]
|
updateNote: ui.updateNotes.split('\n')[0],
|
||||||
|
updateReleaseUrl: ui.updateReleaseUrl,
|
||||||
|
updateCanInstall: ui.updateCanInstall
|
||||||
});
|
});
|
||||||
} else if (notifications.message) {
|
} else if (notifications.message) {
|
||||||
Object.assign(state_, {
|
Object.assign(state_, {
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,8 @@ rpc.on('open file', ({path}) => {
|
||||||
store_.dispatch(uiActions.openFile(path));
|
store_.dispatch(uiActions.openFile(path));
|
||||||
});
|
});
|
||||||
|
|
||||||
rpc.on('update available', ({releaseName, releaseNotes}) => {
|
rpc.on('update available', ({releaseName, releaseNotes, releaseUrl, canInstall}) => {
|
||||||
store_.dispatch(updaterActions.updateAvailable(releaseName, releaseNotes));
|
store_.dispatch(updaterActions.updateAvailable(releaseName, releaseNotes, releaseUrl, canInstall));
|
||||||
});
|
});
|
||||||
|
|
||||||
rpc.on('move', () => {
|
rpc.on('move', () => {
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,9 @@ const reducer = (state = initial, action) => {
|
||||||
case UPDATE_AVAILABLE:
|
case UPDATE_AVAILABLE:
|
||||||
state_ = state.merge({
|
state_ = state.merge({
|
||||||
updateVersion: action.version,
|
updateVersion: action.version,
|
||||||
updateNotes: action.notes || ''
|
updateNotes: action.notes || '',
|
||||||
|
updateReleaseUrl: action.releaseUrl,
|
||||||
|
updateCanInstall: !!action.canInstall
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue