Skip to content

Commit

Permalink
WIP: feat(type): add support for new link: dependency type
Browse files Browse the repository at this point in the history
  • Loading branch information
mgcrea committed May 23, 2017
1 parent d57cce9 commit 7f3946f
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 7 deletions.
26 changes: 26 additions & 0 deletions __tests__/commands/install/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,32 @@ test.concurrent('properly find and save build artifacts', async () => {
});
});

test.concurrent('creates a symlink to a directory when using the link: protocol', async () => {
await runInstall({}, 'install-link', async (config): Promise<void> => {
const expectPath = path.join(config.cwd, 'node_modules', 'test-absolute');
expect(await fs.exists(expectPath)).toEqual(true);

const stat = await fs.stat(expectPath);
expect(stat.isLink()).toEqual(true);

const target = await fs.readlink(expectPath);
expect(target).toEqual('/some-test-path');
});
});

test.concurrent('resolves the symlinks relative to the package path when using the link: protocol; not the node_modules', async () => {
await runInstall({}, 'install-link', async (config): Promise<void> => {
const expectPath = path.join(config.cwd, 'node_modules', 'test-relative');
expect(await fs.exists(expectPath)).toEqual(true);

const stat = await fs.stat(expectPath);
expect(stat.isLink()).toEqual(true);

const target = await fs.readlink(expectPath);
expect(target).toEqual('../some-test-path');
});
});

test('changes the cache path when bumping the cache version', async () => {
await runInstall({}, 'install-github', async (config): Promise<void> => {
const inOut = new stream.PassThrough();
Expand Down
9 changes: 9 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type ConfigOptions = {
preferOffline?: boolean,
pruneOfflineMirror?: boolean,
enableMetaFolder?: boolean,
linkFileDependencies?: boolean,
captureHar?: boolean,
ignoreScripts?: boolean,
ignorePlatform?: boolean,
Expand Down Expand Up @@ -90,7 +91,11 @@ export default class Config {
offline: boolean;
preferOffline: boolean;
pruneOfflineMirror: boolean;
<<<<<<< HEAD
enableMetaFolder: boolean;
=======
linkFileDependencies: boolean;
>>>>>>> Makes the link-file-dependencies configurable via the yarnrc
disableLockfileVersions: boolean;
ignorePlatform: boolean;
binLinks: boolean;
Expand Down Expand Up @@ -262,7 +267,11 @@ export default class Config {
this.workspacesExperimental = Boolean(this.getOption('workspaces-experimental'));

this.pruneOfflineMirror = Boolean(this.getOption('yarn-offline-mirror-pruning'));
<<<<<<< HEAD
this.enableMetaFolder = Boolean(this.getOption('enable-meta-folder'));
=======
this.linkFileDependencies = Boolean(this.getOption('yarn-link-file-dependencies'));
>>>>>>> Makes the link-file-dependencies configurable via the yarnrc
this.disableLockfileVersions = Boolean(this.getOption('yarn-disable-lockfile-versions'));

//init & create cacheFolder, tempFolder
Expand Down
2 changes: 1 addition & 1 deletion src/fetchers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export {TarballFetcher as tarball};

export type Fetchers = BaseFetcher | CopyFetcher | GitFetcher | TarballFetcher;

export type FetcherNames = 'base' | 'copy' | 'git' | 'tarball';
export type FetcherNames = 'base' | 'copy' | 'git' | 'link' | 'tarball';
9 changes: 8 additions & 1 deletion src/package-fetcher.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @flow */

import type {FetchedMetadata} from './types.js';
import type {Manifest, FetchedMetadata} from './types.js';
import type PackageResolver from './package-resolver.js';
import type {Fetchers} from './fetchers/index.js';
import type {Reporter} from './reporters/index.js';
Expand Down Expand Up @@ -37,6 +37,13 @@ export default class PackageFetcher {
const dest = this.config.generateHardModulePath(ref);

const remote = ref.remote;

// Mock metedata for linked dependencies
if (remote.type === 'link') {
const mockPkg: Manifest = {_uid: '', name: '', version: '0.0.0'};
return Promise.resolve({resolved: null, hash: '', dest, package: mockPkg, cached: false});
}

const Fetcher = fetchers[remote.type];
if (!Fetcher) {
throw new MessageError(this.reporter.lang('unknownFetcherFor', remote.type));
Expand Down
14 changes: 10 additions & 4 deletions src/package-linker.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,20 @@ export default class PackageLinker {
const hardlinksEnabled = linkDuplicates && (await fs.hardlinksWork(this.config.cwd));

const copiedSrcs: Map<string, string> = new Map();
for (const [dest, {pkg, loc: src}] of flatTree) {
for (const [dest, {pkg, loc}] of flatTree) {
const remote = pkg._remote || {type: ''};
const ref = pkg._reference;
const src = remote.type === 'link' ? remote.reference : loc;
invariant(ref, 'expected package reference');
ref.setLocation(dest);

// backwards compatibility: get build artifacts from metadata
const metadata = await this.config.readPackageMetadata(src);
for (const file of metadata.artifacts) {
artifactFiles.push(path.join(dest, file));
// does not apply to linked dependencies
if (remote.type !== 'link') {
const metadata = await this.config.readPackageMetadata(src);
for (const file of metadata.artifacts) {
artifactFiles.push(path.join(dest, file));
}
}

const integrityArtifacts = this.artifacts[`${pkg.name}@${pkg.version}`];
Expand All @@ -166,6 +171,7 @@ export default class PackageLinker {
copyQueue.set(dest, {
src,
dest,
type: remote.type,
onFresh() {
if (ref) {
ref.setFresh(true);
Expand Down
14 changes: 14 additions & 0 deletions src/resolvers/exotics/file-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import type {Manifest} from '../../types.js';
import type PackageRequest from '../../package-request.js';
import type {RegistryNames} from '../../registries/index.js';
import {MessageError} from '../../errors.js';
import ExoticResolver from './exotic-resolver.js';
import * as util from '../../util/misc.js';
Expand Down Expand Up @@ -30,6 +31,19 @@ export default class FileResolver extends ExoticResolver {
if (!path.isAbsolute(loc)) {
loc = path.join(this.config.cwd, loc);
}

if (this.config.linkFileDependencies) {
const registry: RegistryNames = 'npm';
const manifest: Manifest = {_uid: '', name: '', version: '0.0.0', _registry: registry};
manifest._remote = {
type: 'link',
registry,
hash: null,
reference: loc,
};
manifest._uid = manifest.version;
return manifest;
}
if (!await fs.exists(loc)) {
throw new MessageError(this.reporter.lang('doesntExist', loc));
}
Expand Down
41 changes: 41 additions & 0 deletions src/resolvers/exotics/link-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* @flow */

import type {Manifest} from '../../types.js';
import type {RegistryNames} from '../../registries/index.js';
import type PackageRequest from '../../package-request.js';
import ExoticResolver from './exotic-resolver.js';
import * as util from '../../util/misc.js';

const path = require('path');

export default class LinkResolver extends ExoticResolver {
constructor(request: PackageRequest, fragment: string) {
super(request, fragment);
this.loc = util.removePrefix(fragment, 'link:');
}

loc: string;

static protocol = 'link';

resolve(): Promise<Manifest> {
let loc = this.loc;
if (!path.isAbsolute(loc)) {
loc = path.join(this.config.cwd, loc);
}

const registry: RegistryNames = 'npm';
const manifest: Manifest = {_uid: '', name: '', version: '0.0.0', _registry: registry};

manifest._remote = {
type: 'link',
registry,
hash: null,
reference: loc,
};

manifest._uid = manifest.version;

return Promise.resolve(manifest);
}
}
2 changes: 2 additions & 0 deletions src/resolvers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ExoticGit from './exotics/git-resolver.js';
import ExoticTarball from './exotics/tarball-resolver.js';
import ExoticGitHub from './exotics/github-resolver.js';
import ExoticFile from './exotics/file-resolver.js';
import ExoticLink from './exotics/link-resolver.js';
import ExoticGitLab from './exotics/gitlab-resolver.js';
import ExoticGist from './exotics/gist-resolver.js';
import ExoticBitbucket from './exotics/bitbucket-resolver.js';
Expand All @@ -23,6 +24,7 @@ export const exotics = {
tarball: ExoticTarball,
github: ExoticGitHub,
file: ExoticFile,
link: ExoticLink,
gitlab: ExoticGitLab,
gist: ExoticGist,
bitbucket: ExoticBitbucket,
Expand Down
15 changes: 14 additions & 1 deletion src/util/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const noop = () => {};
export type CopyQueueItem = {
src: string,
dest: string,
type?: string,
onFresh?: ?() => void,
onDone?: ?() => void,
};
Expand Down Expand Up @@ -159,11 +160,23 @@ async function buildActionsForCopy(

//
async function build(data): Promise<void> {
const {src, dest} = data;
const {src, dest, type} = data;
const onFresh = data.onFresh || noop;
const onDone = data.onDone || noop;
files.add(dest);

if (type === 'link') {
await mkdirp(path.dirname(dest));
onFresh();
actions.push({
type: 'symlink',
dest,
linkname: src,
});
onDone();
return;
}

if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) {
// ignored file
return;
Expand Down

0 comments on commit 7f3946f

Please sign in to comment.