From c4e2540dd2f424df0ef5c7249cf1008d6d211f1d Mon Sep 17 00:00:00 2001 From: zkochan Date: Sat, 13 May 2017 00:07:36 +0300 Subject: [PATCH] fix(shrinkwrap): don't save absolute path shrinkwrap.yaml Relative path to the current working directory is saved in the `shrinkwrap.yaml`. Close #744 --- src/api/install.ts | 2 ++ src/fs/pkgIdToFilename.ts | 8 ++++++++ src/install/fetch.ts | 9 +++++---- src/install/installMultiple.ts | 15 +++++++++------ src/link/index.ts | 3 ++- src/resolve/index.ts | 2 +- src/resolve/local.ts | 17 +++++++---------- test/install/local.ts | 32 ++++++++++++++++++++++++++++---- tsconfig.json | 1 + 9 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 src/fs/pkgIdToFilename.ts diff --git a/src/api/install.ts b/src/api/install.ts index 0d25cf20da..df51f7d548 100644 --- a/src/api/install.ts +++ b/src/api/install.ts @@ -224,6 +224,8 @@ async function installInContext ( nodeModules: nodeModulesPath, update: opts.update, keypath: [], + referencedFrom: opts.prefix, + prefix: opts.prefix, } const nonLinkedPkgs = await pFilter(packagesToInstall, (spec: PackageSpec) => !spec.name || safeIsInnerLink(nodeModulesPath, spec.name)) const pkgs: InstalledPackage[] = await installMultiple( diff --git a/src/fs/pkgIdToFilename.ts b/src/fs/pkgIdToFilename.ts new file mode 100644 index 0000000000..84e44c78bb --- /dev/null +++ b/src/fs/pkgIdToFilename.ts @@ -0,0 +1,8 @@ +import path = require('path') +import normalize = require('normalize-path') + +export default function pkgIdToFilename (pkgId: string) { + if (pkgId.indexOf('file:') !== 0) return pkgId + + return `local/${encodeURIComponent(normalize(path.resolve(pkgId.slice(5))))}` +} diff --git a/src/install/fetch.ts b/src/install/fetch.ts index 3ed484ae3e..276ecd1327 100644 --- a/src/install/fetch.ts +++ b/src/install/fetch.ts @@ -9,6 +9,7 @@ import resolve, { PackageMeta, } from '../resolve' import mkdirp = require('mkdirp-promise') +import pkgIdToFilename from '../fs/pkgIdToFilename' import readPkg from '../fs/readPkg' import exists = require('path-exists') import memoize, {MemoizedFunc} from '../memoize' @@ -33,7 +34,7 @@ export type FetchedPackage = { export default async function fetch ( spec: PackageSpec, options: { - root: string, + prefix: string, storePath: string, localRegistry: string, registry: string, @@ -54,7 +55,7 @@ export default async function fetch ( if (!resolution || options.update) { const resolveResult = await resolve(spec, { loggedPkg: options.loggedPkg, - root: options.root, + prefix: options.prefix, got: options.got, localRegistry: options.localRegistry, registry: options.registry, @@ -75,7 +76,7 @@ export default async function fetch ( logStatus({status: 'resolved', pkgId: id, pkg: options.loggedPkg}) - const target = path.join(options.storePath, id) + const target = path.join(options.storePath, pkgIdToFilename(id)) const fetchingFiles = options.fetchingLocker(id, () => fetchToStore({ target, @@ -97,7 +98,7 @@ export default async function fetch ( resolution, path: target, srcPath: resolution.type == 'directory' - ? resolution.root + ? path.join(options.prefix, resolution.root) : undefined, abort: async () => { try { diff --git a/src/install/installMultiple.ts b/src/install/installMultiple.ts index 8ae7eb3912..0c96875d50 100644 --- a/src/install/installMultiple.ts +++ b/src/install/installMultiple.ts @@ -44,7 +44,8 @@ export default async function installMultiple ( specs: PackageSpec[], options: { force: boolean, - root: string, + prefix: string, + referencedFrom: string, storePath: string, localRegistry: string, registry: string, @@ -125,7 +126,8 @@ async function install ( ctx: InstallContext, options: { force: boolean, - root: string, + prefix: string, + referencedFrom: string, storePath: string, localRegistry: string, registry: string, @@ -170,7 +172,7 @@ async function install ( update: options.update, fetchingLocker: ctx.fetchingLocker, registry, - root: options.root, + prefix: options.prefix, storePath: options.storePath, localRegistry: options.localRegistry, metaCache: options.metaCache, @@ -202,7 +204,7 @@ async function install ( fetchedPkg.id, ctx, Object.assign({}, options, { - root: fetchedPkg.srcPath, + referencedFrom: fetchedPkg.srcPath, isInstallable, }) ) @@ -304,7 +306,8 @@ async function installDependencies ( ctx: InstallContext, opts: { force: boolean, - root: string, + prefix: string, + referencedFrom: string, storePath: string, localRegistry: string, registry: string, @@ -331,7 +334,7 @@ async function installDependencies ( const deps = depsToSpecs( filterDeps(Object.assign({}, pkg.optionalDependencies, pkg.dependencies)), { - where: opts.root, + where: opts.referencedFrom, devDependencies: pkg.devDependencies || {}, optionalDependencies: pkg.optionalDependencies || {}, } diff --git a/src/link/index.ts b/src/link/index.ts index 08ac315f36..5caa9fd1ac 100644 --- a/src/link/index.ts +++ b/src/link/index.ts @@ -12,6 +12,7 @@ import linkBins from './linkBins' import {Package, Dependencies} from '../types' import resolvePeers, {DependencyTreeNode, DependencyTreeNodeMap} from './resolvePeers' import logStatus from '../logging/logInstallStatus' +import pkgIdToFilename from '../fs/pkgIdToFilename' export type LinkedPackage = { id: string, @@ -49,7 +50,7 @@ export default async function ( peerDependencies: installedPkg.pkg.peerDependencies || {}, hasBundledDependencies: !!(installedPkg.pkg.bundledDependencies || installedPkg.pkg.bundleDependencies), fetchingFiles: installedPkg.fetchingFiles, - localLocation: path.join(opts.baseNodeModules, `.${installedPkg.id}`), + localLocation: path.join(opts.baseNodeModules, `.${pkgIdToFilename(installedPkg.id)}`), path: installedPkg.path, dependencies: installedPkg.dependencies, } diff --git a/src/resolve/index.ts b/src/resolve/index.ts index aa88fed2d4..7b7404b161 100644 --- a/src/resolve/index.ts +++ b/src/resolve/index.ts @@ -92,7 +92,7 @@ export type ResolveOptions = { localRegistry: string, registry: string, metaCache: Map, - root: string, + prefix: string, offline: boolean, } diff --git a/src/resolve/local.ts b/src/resolve/local.ts index e005fa06be..546aa5bfb7 100644 --- a/src/resolve/local.ts +++ b/src/resolve/local.ts @@ -1,5 +1,4 @@ -import {resolve} from 'path' -import * as path from 'path' +import path = require('path') import readPkg from '../fs/readPkg' import { PackageSpec, @@ -9,19 +8,21 @@ import { ResolveResult, } from '.' import fs = require('mz/fs') +import normalize = require('normalize-path') /** * Resolves a package hosted on the local filesystem */ export default async function resolveLocal (spec: PackageSpec, opts: ResolveOptions): Promise { - const dependencyPath = resolve(opts.root, spec.fetchSpec) + const dependencyPath = normalize(path.relative(opts.prefix, spec.fetchSpec)) + const id = `file:${dependencyPath}` if (spec.type === 'file') { const resolution: TarballResolution = { - tarball: `file:${dependencyPath}`, + tarball: id, } return { - id: createLocalPkgId(dependencyPath), + id, resolution, } } @@ -32,11 +33,7 @@ export default async function resolveLocal (spec: PackageSpec, opts: ResolveOpti root: dependencyPath, } return { - id: createLocalPkgId(dependencyPath), + id, resolution, } } - -function createLocalPkgId (dependencyPath: string): string { - return 'local/' + encodeURIComponent(dependencyPath) -} diff --git a/test/install/local.ts b/test/install/local.ts index 7e2835f332..d5643e403b 100644 --- a/test/install/local.ts +++ b/test/install/local.ts @@ -2,6 +2,9 @@ import tape = require('tape') import promisifyTape from 'tape-promise' import normalizePath = require('normalize-path') import readPkg = require('read-pkg') +import ncpCB = require('ncp') +import thenify = require('thenify') +import path = require('path') import {install, installPkgs} from '../../src' import { prepare, @@ -10,9 +13,10 @@ import { local, } from '../utils' +const ncp = thenify(ncpCB.ncp) const test = promisifyTape(tape) -test('scoped modules from a directory', async function (t) { +test('scoped modules from a directory', async function (t: tape.Test) { const project = prepare(t) await installPkgs([local('local-scoped-pkg')], testDefaults()) @@ -21,13 +25,33 @@ test('scoped modules from a directory', async function (t) { t.equal(m(), '@scope/local-scoped-pkg', 'localScopedPkg() is available') }) -test('local file', async function (t) { +test('local file', async function (t: tape.Test) { const project = prepare(t) - await installPkgs([local('local-pkg')], testDefaults()) + await ncp(pathToLocalPkg('local-pkg'), path.resolve('..', 'local-pkg')) + + await installPkgs(['file:../local-pkg'], testDefaults()) const m = project.requireModule('local-pkg') t.ok(m, 'localPkg() is available') + + const shr = await project.loadShrinkwrap() + + t.deepEqual(shr, { + dependencies: { + [`local-pkg@file:..${path.sep}local-pkg`]: 'file:../local-pkg', + }, + packages: { + 'file:../local-pkg': { + resolution: { + root: '../local-pkg', + type: 'directory', + }, + }, + }, + registry: 'http://localhost:4873/', + version: 2, + }) }) test('package with a broken symlink', async function (t) { @@ -39,7 +63,7 @@ test('package with a broken symlink', async function (t) { t.ok(m, 'has-broken-symlink is available') }) -test('nested local dependency of a local dependency', async function (t) { +test('nested local dependency of a local dependency', async function (t: tape.Test) { const project = prepare(t) await installPkgs([local('pkg-with-local-dep')], testDefaults()) diff --git a/tsconfig.json b/tsconfig.json index ec1e325de4..8399ac373a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -52,6 +52,7 @@ "src/fs/getPkgDirs.ts", "src/fs/gracefulify.ts", "src/fs/modulesController.ts", + "src/fs/pkgIdToFilename.ts", "src/fs/readPkg.ts", "src/fs/safeReadPkg.ts", "src/fs/shrinkwrap.ts",