Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple fixes for the CLI #5328

Merged
merged 3 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"react-dom": "17.0.1",
"semver": "7.3.4",
"shell-env": "3.0.1",
"sudo-prompt": "^9.2.1",
"uuid": "8.3.2"
},
"optionalDependencies": {
Expand Down
10 changes: 10 additions & 0 deletions app/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {getDecoratedEnv} from './plugins';
import {productName, version} from './package.json';
import * as config from './config';
import {IPty, IWindowsPtyForkOptions, spawn as npSpawn} from 'node-pty';
import {cliScriptPath} from './config/paths';
import {dirname} from 'path';

const createNodePtyError = () =>
new Error(
Expand Down Expand Up @@ -118,6 +120,14 @@ export default class Session extends EventEmitter {
envFromConfig
);

// path to AppImage mount point is added to PATH environment variable automatically
// which conflicts with the cli
if (baseEnv['APPIMAGE'] && baseEnv['APPDIR']) {
baseEnv['PATH'] = [dirname(cliScriptPath)]
.concat((baseEnv['PATH'] || '').split(':').filter((val) => !val.startsWith(baseEnv['APPDIR'])))
.join(':');
}

// Electron has a default value for process.env.GOOGLE_API_KEY
// We don't want to leak this to the shell
// See https://github.com/vercel/hyper/issues/696
Expand Down
100 changes: 68 additions & 32 deletions app/utils/cli-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import notify from '../notify';
import {cliScriptPath, cliLinkPath} from '../config/paths';
import {Registry, loadRegistry} from './registry';
import type {ValueType} from 'native-reg';
import sudoPrompt from 'sudo-prompt';
import {clipboard, dialog} from 'electron';
import {mkdirpSync} from 'fs-extra';

const readlink = pify(fs.readlink);
const symlink = pify(fs.symlink);
const sudoExec = pify(sudoPrompt.exec, {multiArgs: true});

const checkInstall = () => {
return readlink(cliLinkPath)
Expand All @@ -20,15 +24,51 @@ const checkInstall = () => {
});
};

const addSymlink = () => {
return checkInstall().then((isInstalled) => {
const addSymlink = async (silent: boolean) => {
try {
const isInstalled = await checkInstall();
if (isInstalled) {
console.log('Hyper CLI already in PATH');
return Promise.resolve();
return;
}
console.log('Linking HyperCLI');
return symlink(cliScriptPath, cliLinkPath);
});
if (!fs.existsSync(path.dirname(cliLinkPath))) {
try {
mkdirpSync(path.dirname(cliLinkPath));
} catch (err) {
throw `Failed to create directory ${path.dirname(cliLinkPath)} - ${err}`;
}
}
await symlink(cliScriptPath, cliLinkPath);
} catch (err) {
// 'EINVAL' is returned by readlink,
// 'EEXIST' is returned by symlink
let error =
err.code === 'EEXIST' || err.code === 'EINVAL'
? `File already exists: ${cliLinkPath}`
: `Symlink creation failed: ${err.code}`;
// Need sudo access to create symlink
if (err.code === 'EACCES' && !silent) {
const result = await dialog.showMessageBox({
message: `You need to grant elevated privileges to add Hyper CLI to PATH
Or you can run
sudo ln -sf "${cliScriptPath}" "${cliLinkPath}"`,
type: 'info',
buttons: ['OK', 'Copy Command', 'Cancel']
});
if (result.response === 0) {
try {
await sudoExec(`ln -sf "${cliScriptPath}" "${cliLinkPath}"`, {name: 'Hyper'});
return;
} catch (_error) {
error = _error[0];
}
} else if (result.response === 1) {
clipboard.writeText(`sudo ln -sf "${cliScriptPath}" "${cliLinkPath}"`);
}
}
throw error;
}
};

const addBinToUserPath = () => {
Expand Down Expand Up @@ -89,35 +129,31 @@ const logNotify = (withNotification: boolean, title: string, body: string, detai
withNotification && notify(title, body, details);
};

export const installCLI = (withNotification: boolean) => {
export const installCLI = async (withNotification: boolean) => {
if (process.platform === 'win32') {
addBinToUserPath()
.then(() =>
logNotify(
withNotification,
'Hyper CLI installed',
'You may need to restart your computer to complete this installation process.'
)
)
.catch((err) =>
logNotify(withNotification, 'Hyper CLI installation failed', `Failed to add Hyper CLI path to user PATH ${err}`)
try {
await addBinToUserPath();
logNotify(
withNotification,
'Hyper CLI installed',
'You may need to restart your computer to complete this installation process.'
);
} else if (process.platform === 'darwin') {
addSymlink()
.then(() => logNotify(withNotification, 'Hyper CLI installed', `Symlink created at ${cliLinkPath}`))
.catch((err) => {
// 'EINVAL' is returned by readlink,
// 'EEXIST' is returned by symlink
const error =
err.code === 'EEXIST' || err.code === 'EINVAL'
? `File already exists: ${cliLinkPath}`
: `Symlink creation failed: ${err.code}`;

console.error(err);
logNotify(withNotification, 'Hyper CLI installation failed', error);
});
} catch (err) {
logNotify(withNotification, 'Hyper CLI installation failed', `Failed to add Hyper CLI path to user PATH ${err}`);
}
} else if (process.platform === 'darwin' || process.platform === 'linux') {
// AppImages are mounted on run at a temporary path, don't create symlink
if (process.env['APPIMAGE']) {
console.log('Skipping CLI symlink creation as it is an AppImage install');
return;
}
try {
await addSymlink(!withNotification);
logNotify(withNotification, 'Hyper CLI installed', `Symlink created at ${cliLinkPath}`);
} catch (error) {
logNotify(withNotification, 'Hyper CLI installation failed', `${error}`);
}
} else {
withNotification &&
notify('Hyper CLI installation', 'Command is added in PATH only at package installation. Please reinstall.');
logNotify(withNotification, 'Hyper CLI installation failed', `Unsupported platform ${process.platform}`);
}
};
5 changes: 5 additions & 0 deletions app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,11 @@ strip-final-newline@^2.0.0:
resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==

sudo-prompt@^9.2.1:
version "9.2.1"
resolved "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd"
integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==

to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
Expand Down