Skip to content

Commit

Permalink
[breaking] ES2015ify and promisify the API
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Jan 23, 2016
1 parent 7ef2c00 commit 6cf43ed
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 86 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ language: node_js
node_js:
- '5'
- '4'
- '0.12'
122 changes: 52 additions & 70 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,56 @@
'use strict';
var childProcess = require('child_process');
var stripAnsi = require('strip-ansi');
var delimiter = require('path').delimiter;
var os = require('os');
var shell = process.env.SHELL || '/bin/sh';
var user = process.env.USER;
var opts = {encoding: 'utf8'};

module.exports = function (cb) {
if (process.platform === 'win32') {
setImmediate(cb, null, process.env.PATH);
return;
}
const os = require('os');
const childProcess = require('child_process');
const path = require('path');
const execa = require('execa');
const stripAnsi = require('strip-ansi');
const shell = process.env.SHELL || '/bin/sh';
const user = process.env.USER;
const opts = {encoding: 'utf8'};

var todo = [pathFromShell, pathFromSudo];
var results = [];
todo.forEach(function (fn) {
fn(function (path) {
results.push(path);
if (results.length === todo.length) {
// return the longest found path
cb(null, longest(results.concat(process.env.PATH)));
}
});
});
};
function clean(str, isEnv) {
str = stripAnsi(str.trim());

module.exports.sync = function () {
if (process.platform === 'win32') {
return process.env.PATH;
if (isEnv) {
return str;
}

var p1 = pathFromShellSync();
var p2 = pathFromSudoSync();
// return the longest found path
return longest([p1, p2, process.env.PATH]);
};
if (str.indexOf(os.EOL) === -1) {
return str;
}

function pathFromShell(cb) {
childProcess.execFile(shell, ['-i', '-c', 'echo "$PATH"'], opts, function (err, stdout) {
if (err) {
cb('');
return;
}
str = str.split(os.EOL);
return str[str.length - 1];
}

cb(clean(stdout) || '');
});
function pathFromShell() {
return execa(shell, ['-i', '-c', 'echo "$PATH"'], opts)
.then(x => clean(x.stdout))
.catch(() => '');
}

function pathFromShellSync() {
return clean(childProcess.execFileSync(shell, ['-i', '-c', 'echo "$PATH"'], opts)) || '';
}

function pathFromSudo(cb) {
childProcess.execFile('sudo', ['-Hiu', user, 'env'], opts, function (err, stdout) {
if (err) {
// may fail with 'sudo: must be setuid root'
cb('');
return;
}

cb(parseEnv(clean(stdout, true)) || '');
});
function pathFromSudo() {
return execa('sudo', ['-Hiu', user, 'env'], opts)
.then(x => parseEnv(clean(x.stdout, true)) || '')
.catch(() => '');
}

function pathFromSudoSync() {
try {
return parseEnv(clean(childProcess.execFileSync('sudo', ['-Hiu', user, 'env'], opts), true)) || '';
const stdout = childProcess.execFileSync('sudo', ['-Hiu', user, 'env'], opts);
return parseEnv(clean(stdout, true)) || '';
} catch (err) {
// may fail with 'sudo: must be setuid root'
return '';
}
}

function parseEnv(env) {
var pathLine = env.trim().split(os.EOL).filter(function (line) {
return /^PATH=/.test(line.trim());
})[0];
const pathLine = env.trim().split(os.EOL).filter(x => /^PATH=/.test(x.trim()))[0];

if (!pathLine) {
return '';
Expand All @@ -85,23 +59,31 @@ function parseEnv(env) {
return pathLine.split('=')[1] || '';
}

function clean(str, isEnv) {
str = stripAnsi(str.trim());
function longest(arr) {
return arr.reduce((a, b) => {
return a.split(path.delimiter).length > b.split(path.delimiter).length ? a : b;
});
}

if (isEnv) {
return str;
module.exports = () => {
if (process.platform === 'win32') {
return Promise.resolve(process.env.PATH);
}

if (str.indexOf(os.EOL) === -1) {
return str;
}
return Promise.all([pathFromShell(), pathFromSudo()]).then(result => {
return longest(result.concat(process.env.PATH));
});
};

str = str.split(os.EOL);
return str[str.length - 1];
}
module.exports.sync = () => {
if (process.platform === 'win32') {
return process.env.PATH;
}

function longest(arr) {
return arr.reduce(function (a, b) {
return a.split(delimiter).length > b.split(delimiter).length ? a : b;
});
}
// return the longest found path
return longest([
pathFromShellSync(),
pathFromSudoSync(),
process.env.PATH
]);
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"silverwind <[email protected]> (github.com/silverwind)"
],
"engines": {
"node": ">=0.10.0"
"node": ">=4"
},
"scripts": {
"test": "xo && ava"
Expand All @@ -36,6 +36,7 @@
"nwjs"
],
"dependencies": {
"execa": "^0.2.2",
"strip-ansi": "^3.0.0"
},
"devDependencies": {
Expand Down
8 changes: 5 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# shell-path [![Build Status](https://travis-ci.org/sindresorhus/shell-path.svg?branch=master)](https://travis-ci.org/sindresorhus/shell-path)

> Get the `$PATH` from the shell
> Get the [`$PATH`](https://en.wikipedia.org/wiki/PATH_(variable)) from the shell
Useful for Electron/NW.js apps as GUI apps on OS X doesn't inherit the `$PATH` defined in your dotfiles *(.bashrc/.bash_profile/.zshrc/etc)*.

Expand Down Expand Up @@ -29,11 +29,13 @@ console.log(shellPath.sync());

## API

### shellPath(callback(error, path))
### shellPath()

Return a promise for the `$PATH`.

### shellPath.sync()

Synchronous version. Returns the `$PATH`.
Returns the `$PATH`.


## Related
Expand Down
19 changes: 8 additions & 11 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import test from 'ava';
import os from 'os';
import test from 'ava';
import m from './';

test.cb('async', t => {
m((err, p) => {
t.ifError(err);
t.true(p.indexOf('/usr/bin') !== -1);
t.true(p.indexOf(os.EOL) === -1);
t.end();
});
test('async', async t => {
const PATH = await m();
t.true(PATH.includes('/usr/bin'));
t.false(PATH.includes(os.EOL));
});

test('sync', t => {
var output = m.sync();
t.true(output.indexOf('/usr/bin') !== -1);
t.true(output.indexOf(os.EOL) === -1);
const PATH = m.sync();
t.true(PATH.includes('/usr/bin'));
t.false(PATH.includes(os.EOL));
});

0 comments on commit 6cf43ed

Please sign in to comment.