Skip to content

Commit

Permalink
Adds support for creating link: to a missinig folder (#1170)
Browse files Browse the repository at this point in the history
  • Loading branch information
larixer authored Apr 9, 2020
1 parent 879f5bb commit d0b3906
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 21 deletions.
20 changes: 20 additions & 0 deletions .yarn/versions/8dc23b49.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
releases:
"@yarnpkg/cli": prerelease
"@yarnpkg/plugin-node-modules": prerelease

declined:
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-essentials"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/core"
- "@yarnpkg/doctor"
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ describe('Node_Modules', () => {
),
);

test(`should support dependency via link: protocol to a missing folder`,
makeTemporaryEnv(
{
dependencies: {
abc: `link:../abc`,
},
},
async ({path, run, source}) => {
await writeFile(npath.toPortablePath(`${path}/../one-fixed-dep.local/abc.js`), '');

await writeFile(npath.toPortablePath(`${path}/.yarnrc.yml`), `
nodeLinker: "node-modules"
`);

await expect(run(`install`)).resolves.toBeTruthy();

await expect(xfs.lstatPromise(npath.toPortablePath(`${path}/node_modules/abc`))).resolves.toBeDefined();
},
),
);

test(`should support replacement of regular dependency with portal: protocol dependency`,
makeTemporaryEnv(
{
Expand Down
56 changes: 35 additions & 21 deletions packages/plugin-node-modules/sources/NodeModulesLinker.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import {BuildDirective, MessageName, Project} from '@yarnpkg/core';
import {Linker, LinkOptions, MinimalLinkOptions, LinkType} from '@yarnpkg/core';
import {Locator, Package, BuildType} from '@yarnpkg/core';
import {structUtils, Report, Manifest, miscUtils, FinalizeInstallStatus, FetchResult, DependencyMeta} from '@yarnpkg/core';
import {VirtualFS, ZipOpenFS} from '@yarnpkg/fslib';
import {PortablePath, npath, ppath, toFilename, Filename, xfs, FakeFS} from '@yarnpkg/fslib';
import {getLibzipPromise} from '@yarnpkg/libzip';
import {parseSyml} from '@yarnpkg/parsers';
import {AbstractPnpInstaller} from '@yarnpkg/plugin-pnp';
import {NodeModulesLocatorMap, buildLocatorMap, buildNodeModulesTree} from '@yarnpkg/pnpify';
import {PnpSettings, makeRuntimeApi} from '@yarnpkg/pnp';
import cmdShim from '@zkochan/cmd-shim';
import {UsageError} from 'clipanion';
import fs from 'fs';
import {BuildDirective, MessageName, Project, FetchResult} from '@yarnpkg/core';
import {Linker, LinkOptions, MinimalLinkOptions, LinkType} from '@yarnpkg/core';
import {Locator, Package, BuildType, FinalizeInstallStatus} from '@yarnpkg/core';
import {structUtils, Report, Manifest, miscUtils, DependencyMeta} from '@yarnpkg/core';
import {VirtualFS, ZipOpenFS, xfs, FakeFS} from '@yarnpkg/fslib';
import {PortablePath, npath, ppath, toFilename, Filename} from '@yarnpkg/fslib';
import {getLibzipPromise} from '@yarnpkg/libzip';
import {parseSyml} from '@yarnpkg/parsers';
import {AbstractPnpInstaller} from '@yarnpkg/plugin-pnp';
import {NodeModulesLocatorMap, buildLocatorMap} from '@yarnpkg/pnpify';
import {buildNodeModulesTree} from '@yarnpkg/pnpify';
import {PnpSettings, makeRuntimeApi} from '@yarnpkg/pnp';
import cmdShim from '@zkochan/cmd-shim';
import {UsageError} from 'clipanion';
import fs from 'fs';

const STATE_FILE_VERSION = 1;
const NODE_MODULES = `node_modules` as Filename;
Expand Down Expand Up @@ -113,8 +114,11 @@ class NodeModulesInstaller extends AbstractPnpInstaller {

const installStatuses: Array<FinalizeInstallStatus> = [];

for (const [locatorStr, installRecord] of locatorMap.entries()) {
const locator = structUtils.parseLocator(locatorStr);
for (const [locatorKey, installRecord] of locatorMap.entries()) {
if (isLinkLocator(locatorKey))
continue;

const locator = structUtils.parseLocator(locatorKey);
const pnpLocator = {name: structUtils.stringifyIdent(locator), reference: locator.reference};

const pnpEntry = pnp.getPackageInformation(pnpLocator);
Expand Down Expand Up @@ -514,16 +518,26 @@ function refineNodeModulesRoots(locationTree: LocationTree, binSymlinks: BinSyml
return {locationTree: refinedLocationTree, binSymlinks: refinedBinSymlinks};
};

function isLinkLocator(locatorKey: LocatorKey): boolean {
let descriptor = structUtils.parseDescriptor(locatorKey);
if (structUtils.isVirtualDescriptor(descriptor))
descriptor = structUtils.devirtualizeDescriptor(descriptor);

return descriptor.range.startsWith('link:');
};

async function createBinSymlinkMap(installState: NodeModulesLocatorMap, locationTree: LocationTree, projectRoot: PortablePath, {loadManifest}: {loadManifest: (sourceLocation: PortablePath) => Promise<Manifest>}) {
const locatorScriptMap = new Map<LocatorKey, Map<string, string>>();
for (const [locatorKey, {locations}] of installState) {
const manifest = await loadManifest(locations[0]);
let manifest = isLinkLocator(locatorKey) ? null : await loadManifest(locations[0]);

const bin = new Map();
for (const [name, value] of manifest.bin) {
const target = ppath.join(locations[0], value);
if (value !== '' && xfs.existsSync(target)) {
bin.set(name, value);
if (manifest) {
for (const [name, value] of manifest.bin) {
const target = ppath.join(locations[0], value);
if (value !== '' && xfs.existsSync(target)) {
bin.set(name, value);
}
}
}

Expand Down

0 comments on commit d0b3906

Please sign in to comment.