@@ -23,7 +23,20 @@ const INSTALL_STATE_FILE = `.yarn-state.yml` as Filename;
23
23
const MTIME_ACCURANCY = 1000 ;
24
24
25
25
type InstallState = { locatorMap : NodeModulesLocatorMap , locationTree : LocationTree , binSymlinks : BinSymlinkMap , nmMode : NodeModulesMode , mtimeMs : number } ;
26
- type BinSymlinkMap = Map < PortablePath , Map < Filename , PortablePath > > ;
26
+
27
+ /**
28
+ * @example
29
+ * Map {
30
+ * 'example-package' -> Map {
31
+ * 'bin-file' ->
32
+ * [
33
+ * '/example-package/node_modules/example-dependency/bin/bin-file',
34
+ * '/example-package/node_modules/example-dependency/'
35
+ * ]
36
+ * }
37
+ * }
38
+ */
39
+ type BinSymlinkMap = Map < PortablePath , Map < Filename , [ PortablePath , PortablePath ] > > ;
27
40
type LoadManifest = ( locator : LocatorKey , installLocation : PortablePath ) => Promise < Pick < Manifest , `bin`> > ;
28
41
29
42
export enum NodeModulesMode {
@@ -436,7 +449,7 @@ async function writeInstallState(project: Project, locatorMap: NodeModulesLocato
436
449
throw new Error ( `Assertion failed: Expected the path to be within the project (${ location } )` ) ;
437
450
438
451
locatorState += ` ${ JSON . stringify ( internalPath ) } :\n` ;
439
- for ( const [ name , target ] of symlinks ) {
452
+ for ( const [ name , [ target ] ] of symlinks ) {
440
453
const relativePath = ppath . relative ( ppath . join ( location , NODE_MODULES ) , target ) ;
441
454
locatorState += ` ${ JSON . stringify ( name ) } : ${ JSON . stringify ( relativePath ) } \n` ;
442
455
}
@@ -493,7 +506,7 @@ async function findInstallState(project: Project, {unrollAliases = false}: {unro
493
506
const location = ppath . join ( rootPath , npath . toPortablePath ( relativeLocation ) ) ;
494
507
const symlinks = miscUtils . getMapWithDefault ( binSymlinks , location ) ;
495
508
for ( const [ name , target ] of Object . entries ( locationSymlinks as any ) ) {
496
- symlinks . set ( name as Filename , npath . toPortablePath ( [ location , NODE_MODULES , target ] . join ( ppath . sep ) ) ) ;
509
+ symlinks . set ( name as Filename , [ npath . toPortablePath ( [ location , NODE_MODULES , target ] . join ( ppath . sep ) ) , location ] ) ;
497
510
}
498
511
}
499
512
}
@@ -990,14 +1003,14 @@ async function createBinSymlinkMap(installState: NodeModulesLocatorMap, location
990
1003
991
1004
const binSymlinks : BinSymlinkMap = new Map ( ) ;
992
1005
993
- const getBinSymlinks = ( location : PortablePath , parentLocatorLocation : PortablePath , node : LocationNode ) : Map < Filename , PortablePath > => {
1006
+ const getBinSymlinks = ( location : PortablePath , parentLocatorLocation : PortablePath , node : LocationNode ) : Map < Filename , [ PortablePath , PortablePath ] > => {
994
1007
const symlinks = new Map ( ) ;
995
1008
const internalPath = ppath . contains ( projectRoot , location ) ;
996
1009
if ( node . locator && internalPath !== null ) {
997
1010
const binScripts = locatorScriptMap . get ( node . locator ) ! ;
998
1011
for ( const [ filename , scriptPath ] of binScripts ) {
999
1012
const symlinkTarget = ppath . join ( location , npath . toPortablePath ( scriptPath ) ) ;
1000
- symlinks . set ( filename , symlinkTarget ) ;
1013
+ symlinks . set ( filename , [ symlinkTarget , location ] ) ;
1001
1014
}
1002
1015
for ( const [ childLocation , childNode ] of node . children ) {
1003
1016
const absChildLocation = ppath . join ( location , childLocation ) ;
@@ -1009,8 +1022,8 @@ async function createBinSymlinkMap(installState: NodeModulesLocatorMap, location
1009
1022
} else {
1010
1023
for ( const [ childLocation , childNode ] of node . children ) {
1011
1024
const childSymlinks = getBinSymlinks ( ppath . join ( location , childLocation ) , parentLocatorLocation , childNode ) ;
1012
- for ( const [ name , symlinkTarget ] of childSymlinks ) {
1013
- symlinks . set ( name , symlinkTarget ) ;
1025
+ for ( const [ name , value ] of childSymlinks ) {
1026
+ symlinks . set ( name , value ) ;
1014
1027
}
1015
1028
}
1016
1029
}
@@ -1315,7 +1328,9 @@ async function persistNodeModules(preinstallState: InstallState, installState: N
1315
1328
await xfs . mkdirPromise ( rootNmDirPath , { recursive : true } ) ;
1316
1329
1317
1330
const binSymlinks = await createBinSymlinkMap ( installState , locationTree , project . cwd , { loadManifest} ) ;
1318
- await persistBinSymlinks ( prevBinSymlinks , binSymlinks , project . cwd , windowsLinkType ) ;
1331
+ const addedDirs = new Set ( addList . map ( l => l . dstDir ) ) ;
1332
+
1333
+ await persistBinSymlinks ( prevBinSymlinks , binSymlinks , project . cwd , windowsLinkType , addedDirs ) ;
1319
1334
1320
1335
await writeInstallState ( project , installState , binSymlinks , nmMode , { installChangedByUser} ) ;
1321
1336
@@ -1327,7 +1342,7 @@ async function persistNodeModules(preinstallState: InstallState, installState: N
1327
1342
}
1328
1343
}
1329
1344
1330
- async function persistBinSymlinks ( previousBinSymlinks : BinSymlinkMap , binSymlinks : BinSymlinkMap , projectCwd : PortablePath , windowsLinkType : WindowsLinkType ) {
1345
+ async function persistBinSymlinks ( previousBinSymlinks : BinSymlinkMap , binSymlinks : BinSymlinkMap , projectCwd : PortablePath , windowsLinkType : WindowsLinkType , addedDirs : Set < PortablePath > ) {
1331
1346
// Delete outdated .bin folders
1332
1347
for ( const location of previousBinSymlinks . keys ( ) ) {
1333
1348
if ( ppath . contains ( projectCwd , location ) === null )
@@ -1354,11 +1369,11 @@ async function persistBinSymlinks(previousBinSymlinks: BinSymlinkMap, binSymlink
1354
1369
}
1355
1370
}
1356
1371
1357
- for ( const [ name , target ] of symlinks ) {
1372
+ for ( const [ name , [ target , binPackageLocation ] ] of symlinks ) {
1358
1373
const prevTarget = prevSymlinks . get ( name ) ;
1359
1374
const symlinkPath = ppath . join ( binDir , name ) ;
1360
- // Skip unchanged .bin symlinks
1361
- if ( prevTarget === target )
1375
+ // Skip unchanged .bin symlinks except for added/changed packages since they need permissions applied
1376
+ if ( prevTarget === target && ! addedDirs . has ( binPackageLocation ) )
1362
1377
continue ;
1363
1378
1364
1379
if ( process . platform === `win32` ) {
0 commit comments