Skip to content

Commit

Permalink
Fix: Fix yarn global prefix directory (#3721)
Browse files Browse the repository at this point in the history
**Sumary**

Refs #2064.

Uses `%LOCALAPPDATA%\Yarn\bin` and `/usr/local/bin` on POSIX systems if it's writeable, falling back to `~/.yarn/bin` if it is not.

**Test plan**

N/A. Should add automated tests.
  • Loading branch information
KishanBagaria authored and BYK committed Jul 17, 2017
1 parent f7aa742 commit 2134f5b
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 32 deletions.
6 changes: 1 addition & 5 deletions __tests__/commands/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ const runGlobal = buildRun.bind(
);

function getGlobalPath(prefix, name): string {
if (process.platform === 'win32') {
return path.join(prefix, name);
} else {
return path.join(prefix, 'bin', name);
}
return path.join(prefix, 'bin', name);
}

function getTempGlobalFolder(): string {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg

await runGlobal(config, reporter, {}, ['add', packageName]);

const binFolder = getBinFolder(config, {});
const binFolder = await getBinFolder(config, {});
const command = path.resolve(binFolder, path.basename(commandName));

await child.spawn(command, [...rest], {stdio: `inherit`, shell: true});
Expand Down
49 changes: 26 additions & 23 deletions src/cli/commands/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import {run as runRemove} from './remove.js';
import {run as runUpgrade} from './upgrade.js';
import {run as runUpgradeInteractive} from './upgrade-interactive.js';
import {linkBin} from '../../package-linker.js';
import {POSIX_GLOBAL_PREFIX, FALLBACK_GLOBAL_PREFIX} from '../../constants.js';
import * as fs from '../../util/fs.js';

const nativeFs = require('fs');

class GlobalAdd extends Add {
maybeOutputSaveTree(): Promise<void> {
for (const pattern of this.addedPatterns) {
Expand Down Expand Up @@ -69,44 +72,44 @@ async function getBins(config: Config): Promise<Set<string>> {
return paths;
}

function getGlobalPrefix(config: Config, flags: Object): string {
async function getGlobalPrefix(config: Config, flags: Object): Promise<string> {
if (flags.prefix) {
return flags.prefix;
} else if (config.getOption('prefix')) {
return String(config.getOption('prefix'));
} else if (process.env.PREFIX) {
return process.env.PREFIX;
} else if (process.platform === 'win32') {
}

let prefix = FALLBACK_GLOBAL_PREFIX;
if (process.platform === 'win32') {
// %LOCALAPPDATA%\Yarn --> C:\Users\Alice\AppData\Local\Yarn
if (process.env.LOCALAPPDATA) {
return path.join(process.env.LOCALAPPDATA, 'Yarn', 'bin');
prefix = path.join(process.env.LOCALAPPDATA, 'Yarn');
}
// c:\node\node.exe --> prefix=c:\node\
return path.dirname(process.execPath);
} else {
// /usr/local/bin/node --> prefix=/usr/local
let prefix = path.dirname(path.dirname(process.execPath));

// destdir only is respected on Unix
if (process.env.DESTDIR) {
prefix = path.join(process.env.DESTDIR, prefix);
prefix = POSIX_GLOBAL_PREFIX;
}
try {
await fs.access(path.join(prefix, 'bin'), (nativeFs.constants || nativeFs).W_OK);
} catch (err) {
if (err.code === 'EACCES') {
prefix = FALLBACK_GLOBAL_PREFIX;
} else {
throw err;
}

return prefix;
}
return prefix;
}

export function getBinFolder(config: Config, flags: Object): string {
const prefix = getGlobalPrefix(config, flags);
if (process.platform === 'win32') {
return prefix;
} else {
return path.resolve(prefix, 'bin');
}
export async function getBinFolder(config: Config, flags: Object): Promise<string> {
const prefix = await getGlobalPrefix(config, flags);
return path.resolve(prefix, 'bin');
}

async function initUpdateBins(config: Config, reporter: Reporter, flags: Object): Promise<() => Promise<void>> {
const beforeBins = await getBins(config);
const binFolder = getBinFolder(config, flags);
const binFolder = await getBinFolder(config, flags);

function throwPermError(err: Error & {[code: string]: string}, dest: string) {
if (err.code === 'EACCES') {
Expand Down Expand Up @@ -205,8 +208,8 @@ const {run, setFlags: _setFlags} = buildSubCommands('global', {
await updateBins();
},

bin(config: Config, reporter: Reporter, flags: Object, args: Array<string>) {
reporter.log(getBinFolder(config, flags));
async bin(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
reporter.log(await getBinFolder(config, flags));
},

async ls(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
// If there is a `bin` defined in the package.json,
// link each bin to the global bin
if (manifest.bin) {
const globalBinFolder = getGlobalBinFolder(config, flags);
const globalBinFolder = await getGlobalBinFolder(config, flags);
for (const binName in manifest.bin) {
const binSrc = manifest.bin[binName];
const binSrcLoc = path.join(linkLoc, binSrc);
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/unlink.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
// If there is a `bin` defined in the package.json,
// link each bin to the global bin
if (manifest.bin) {
const globalBinFolder = getGlobalBinFolder(config, flags);
const globalBinFolder = await getGlobalBinFolder(config, flags);
for (const binName in manifest.bin) {
const binDestLoc = path.join(globalBinFolder, binName);
if (await fs.exists(binDestLoc)) {
Expand Down
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export const CONFIG_DIRECTORY = getDirectory('config');
export const LINK_REGISTRY_DIRECTORY = path.join(CONFIG_DIRECTORY, 'link');
export const GLOBAL_MODULE_DIRECTORY = path.join(CONFIG_DIRECTORY, 'global');

export const POSIX_GLOBAL_PREFIX = '/usr/local';
export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn');

export const META_FOLDER = '.yarn-meta';
export const INTEGRITY_FILENAME = '.yarn-integrity';
export const LOCKFILE_FILENAME = 'yarn.lock';
Expand Down
2 changes: 1 addition & 1 deletion src/util/execute-lifecycle-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export async function executeLifecycleScript(

// Add global bin folder if it is not present already, as some packages depend
// on a globally-installed version of node-gyp.
const globalBin = getGlobalBinFolder(config, {});
const globalBin = await getGlobalBinFolder(config, {});
if (pathParts.indexOf(globalBin) === -1) {
pathParts.unshift(globalBin);
}
Expand Down

0 comments on commit 2134f5b

Please sign in to comment.