Skip to content

[WIP] Add options to improve development with linked modules #3753

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

Closed
wants to merge 3 commits into from
Closed
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 src/cli/commands/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export function setFlags(commander: Object) {
commander.option('-O, --optional', 'save package to your `optionalDependencies`');
commander.option('-E, --exact', 'install exact version');
commander.option('-T, --tilde', 'install most recent release with the same minor version');
commander.option('--link', 'link local dependencies');
}

export async function run(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
Expand Down
3 changes: 2 additions & 1 deletion src/cli/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class Install {
this.config = config;
this.flags = normalizeFlags(config, flags);

this.resolver = new PackageResolver(config, lockfile);
this.resolver = new PackageResolver(config, flags, lockfile);
this.integrityChecker = new InstallationIntegrityChecker(config);
this.linker = new PackageLinker(config, this.resolver);
this.scripts = new PackageInstallScripts(config, this.resolver, this.flags.force);
Expand Down Expand Up @@ -846,6 +846,7 @@ export function setFlags(commander: Object) {
commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`');
commander.option('-E, --save-exact', 'DEPRECATED');
commander.option('-T, --save-tilde', 'DEPRECATED');
commander.option('--link', 'link local dependencies');
}

export async function install(config: Config, reporter: Reporter, flags: Object, lockfile: Lockfile): Promise<void> {
Expand Down
56 changes: 40 additions & 16 deletions src/cli/commands/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type Config from '../../config.js';
import {MessageError} from '../../errors.js';
import * as fs from '../../util/fs.js';
import {getBinFolder as getGlobalBinFolder} from './global';
import {getPackageFilters} from './pack';

const invariant = require('invariant');
const path = require('path');
Expand All @@ -26,7 +27,9 @@ export function hasWrapper(commander: Object, args: Array<string>): boolean {
return true;
}

export function setFlags(commander: Object) {}
export function setFlags(commander: Object) {
commander.option('--deep', 'create a link for each file inside the current directory instead of the directory itself');
}

export async function run(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
if (args.length) {
Expand Down Expand Up @@ -56,28 +59,49 @@ export async function run(config: Config, reporter: Reporter, flags: Object, arg
const linkLoc = path.join(config.linkFolder, name);
if (await fs.exists(linkLoc)) {
reporter.warn(reporter.lang('linkCollision', name));
await fs.unlink(path.join(config.cwd, linkLoc));
}

if (flags.deep) {
await linkDeep(config, linkLoc);
} else {
await fs.mkdirp(path.dirname(linkLoc));
await fs.symlink(config.cwd, linkLoc);
}

// If there is a `bin` defined in the package.json,
// link each bin to the global bin
if (manifest.bin) {
const globalBinFolder = await getGlobalBinFolder(config, flags);
for (const binName in manifest.bin) {
const binSrc = manifest.bin[binName];
const binSrcLoc = path.join(linkLoc, binSrc);
const binDestLoc = path.join(globalBinFolder, binName);
if (await fs.exists(binDestLoc)) {
reporter.warn(reporter.lang('binLinkCollision', binName));
} else {
await fs.symlink(binSrcLoc, binDestLoc);
}
// If there is a `bin` defined in the package.json,
// link each bin to the global bin
if (manifest.bin) {
const globalBinFolder = await getGlobalBinFolder(config, flags);
for (const binName in manifest.bin) {
const binSrc = manifest.bin[binName];
const binSrcLoc = path.join(linkLoc, binSrc);
const binDestLoc = path.join(globalBinFolder, binName);
if (await fs.exists(binDestLoc)) {
reporter.warn(reporter.lang('binLinkCollision', binName));
} else {
await fs.symlink(binSrcLoc, binDestLoc);
}
}
}

reporter.success(reporter.lang('linkRegistered', name));
reporter.info(reporter.lang('linkRegisteredMessage', name));
reporter.success(reporter.lang('linkRegistered', name));
reporter.info(reporter.lang('linkRegisteredMessage', name));
}
}

async function linkDeep(config, linkLoc) {
await fs.mkdirp(linkLoc);

const {keepFiles} = await getPackageFilters(config);
for (let name of await fs.readdir(config.cwd)) {
const relative = path.relative(config.cwd, name);
if (!keepFiles.has(relative)) {
continue;
}

const src = path.join(config.cwd, name);
const dest = path.join(linkLoc, name);
await fs.symlink(src, dest);
}
}
14 changes: 9 additions & 5 deletions src/cli/commands/pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ const NEVER_IGNORE = ignoreLinesToRegex([
'!/+(changes|changelog|history)*',
]);

export async function packTarball(
config: Config,
{mapHeader}: {mapHeader?: Object => Object} = {},
): Promise<stream$Duplex> {
export async function getPackageFilters(config) {
const pkg = await config.readRootManifest();
const {bundledDependencies, main, files: onlyFiles} = pkg;

Expand Down Expand Up @@ -108,7 +105,14 @@ export async function packTarball(
const possibleKeepFiles: Set<string> = new Set();

// apply filters
sortFilter(files, filters, keepFiles, possibleKeepFiles, ignoredFiles);
return sortFilter(files, filters, keepFiles, possibleKeepFiles, ignoredFiles);
}

export async function packTarball(
config: Config,
{mapHeader}: {mapHeader?: Object => Object} = {},
): Promise<stream$Duplex> {
const {keepFiles} = await getPackageFilters(config);

const packer = tar.pack(config.cwd, {
ignore: name => {
Expand Down
9 changes: 8 additions & 1 deletion src/package-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,14 @@ export default class PackageRequest {
}

async normalize(pattern: string): any {
const {name, range, hasVersion} = PackageRequest.normalizePattern(pattern);
let {name, range, hasVersion} = PackageRequest.normalizePattern(pattern);

// Check if package is linked globally if specified
const linkPath = path.join(this.config.linkFolder, name);
if (this.resolver.flags.link && await fs.exists(linkPath)) {
range = 'link:' + linkPath;
}

const newRange = await this.normalizeRange(range);
return {name, range: newRange, hasVersion};
}
Expand Down
3 changes: 2 additions & 1 deletion src/package-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export type ResolverOptions = {|
|};

export default class PackageResolver {
constructor(config: Config, lockfile: Lockfile) {
constructor(config: Config, flags: Object, lockfile: Lockfile) {
this.patternsByPackage = map();
this.fetchingPatterns = map();
this.fetchingQueue = new BlockingQueue('resolver fetching');
Expand All @@ -34,6 +34,7 @@ export default class PackageResolver {
this.reporter = config.reporter;
this.lockfile = lockfile;
this.config = config;
this.flags = flags;
this.delayedResolveQueue = [];
}

Expand Down