fix: recursive install from subdir when injected deps are present (#3971)

close #3970
This commit is contained in:
Zoltan Kochan
2021-11-10 03:07:18 +02:00
committed by GitHub
parent 2511c82cd2
commit 108bd4a398
9 changed files with 41 additions and 16 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/directory-fetcher": patch
"pnpm": patch
---
Installing a workspace project with an injected dependency from a non-root directory should not fail [#3970](https://github.com/pnpm/pnpm/issues/3970).

View File

@@ -0,0 +1,7 @@
---
"@pnpm/local-resolver": patch
"@pnpm/npm-resolver": patch
"@pnpm/resolve-dependencies": patch
---
Injected directory resolutions should contain the relative path to the directory.

View File

@@ -6,6 +6,7 @@ import loadJsonFile from 'load-json-file'
import packlist from 'npm-packlist'
export interface DirectoryFetcherOptions {
lockfileDir: string
manifest?: DeferredManifestPromise
}
@@ -15,13 +16,16 @@ export default () => {
cafs: Cafs,
resolution: DirectoryResolution,
opts: DirectoryFetcherOptions
) => fetchFromDir(resolution.directory, opts),
) => {
const dir = path.join(opts.lockfileDir, resolution.directory)
return fetchFromDir(dir, opts)
},
}
}
export async function fetchFromDir (
dir: string,
opts: DirectoryFetcherOptions
opts: Omit<DirectoryFetcherOptions, 'lockfileDir'>
) {
const files = await packlist({ path: dir })
const filesIndex: Record<string, string> = fromPairs(files.map((file) => [file, path.join(dir, file)]))

View File

@@ -6,7 +6,12 @@ test('fetch', async () => {
const fetcher = createFetcher()
// eslint-disable-next-line
const fetchResult = await fetcher.directory({} as any, { directory: path.join(__dirname, '..'), type: 'directory' }, {})
const fetchResult = await fetcher.directory({} as any, {
directory: '..',
type: 'directory',
}, {
lockfileDir: __dirname,
})
expect(fetchResult.local).toBe(true)
expect(fetchResult.packageImportMethod).toBe('hardlink')

View File

@@ -78,7 +78,9 @@ function fromLocal (
}
}
const dependencyPath = normalize(path.resolve(fetchSpec))
const dependencyPath = injected
? normalize(path.relative(lockfileDir, fetchSpec))
: normalize(path.resolve(fetchSpec))
const id = !injected && (type === 'directory' || projectDir === lockfileDir)
? `${protocol}${normalize(path.relative(projectDir, fetchSpec))}`
: `${protocol}${normalize(path.relative(lockfileDir, fetchSpec))}`

View File

@@ -17,7 +17,7 @@ test('resolve injected directory', async () => {
expect(resolveResult!.id).toEqual('file:..')
expect(resolveResult!.normalizedPref).toEqual('file:..')
expect(resolveResult!['manifest']!.name).toEqual('@pnpm/local-resolver')
expect(resolveResult!.resolution['directory']).toEqual(normalize(path.join(__dirname, '..')))
expect(resolveResult!.resolution['directory']).toEqual('..')
expect(resolveResult!.resolution['type']).toEqual('directory')
})

View File

@@ -301,14 +301,21 @@ function resolveFromLocalPackage (
lockfileDir?: string
}
) {
let id!: string
let directory!: string
if (opts.hardLinkLocalPackages) {
directory = normalize(path.relative(opts.lockfileDir!, localPackage.dir))
id = `file:${directory}`
} else {
directory = localPackage.dir
id = `link:${normalize(path.relative(opts.projectDir, localPackage.dir))}`
}
return {
id: opts.hardLinkLocalPackages
? `file:${normalize(path.relative(opts.lockfileDir!, localPackage.dir))}`
: `link:${normalize(path.relative(opts.projectDir, localPackage.dir))}`,
id,
manifest: localPackage.manifest,
normalizedPref,
resolution: {
directory: localPackage.dir,
directory,
type: 'directory',
},
resolvedVia: 'local-filesystem',

View File

@@ -974,7 +974,7 @@ test('resolve injected dependency from local directory when it matches the lates
expect(resolveResult!.id).toBe('file:is-positive')
expect(resolveResult!.latest!.split('.').length).toBe(3)
expect(resolveResult!.resolution).toStrictEqual({
directory: '/home/istvan/src/is-positive',
directory: 'is-positive',
type: 'directory',
})
expect(resolveResult!.manifest).toBeTruthy()

View File

@@ -220,12 +220,6 @@ function toLockfileResolution (
): LockfileResolution {
/* eslint-disable @typescript-eslint/dot-notation */
if (dp.isAbsolute(depPath) || resolution.type !== undefined || !resolution['integrity']) {
if (resolution.type === 'directory') {
return {
type: 'directory',
directory: pkg.id.replace(/^file:/, ''),
}
}
return resolution as LockfileResolution
}
const base = registry !== resolution['registry'] ? { registry: resolution['registry'] } : {}