From b77e2647d612a862bb7eabebadbabde5216fd3f7 Mon Sep 17 00:00:00 2001 From: Victor Vlasenko Date: Tue, 7 Jun 2022 15:29:39 +0300 Subject: [PATCH 1/5] Implements content addressable storage for pnpm linker --- .pnp.cjs | 30 +++- .yarn/versions/258185fa.yml | 23 +++ CHANGELOG.md | 4 + .../sources/node-modules.test.ts | 74 +++++++-- .../plugin-nm/sources/NodeModulesLinker.ts | 151 +++++++++++------- packages/plugin-nm/sources/index.ts | 8 +- packages/plugin-pnpm/package.json | 1 + packages/plugin-pnpm/sources/PnpmLinker.ts | 42 +++-- yarn.lock | 1 + 9 files changed, 241 insertions(+), 93 deletions(-) create mode 100644 .yarn/versions/258185fa.yml diff --git a/.pnp.cjs b/.pnp.cjs index ea029628ecbf..45bd583b9b8c 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -235,7 +235,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/plugin-init", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-init", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-init", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-init", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-init", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-init", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-init", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-init", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-init", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-init", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-init", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-init", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-init", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-init", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-init", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-init", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-init", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-init", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-init", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-init", "workspace:packages/plugin-init"]],\ ["@yarnpkg/plugin-interactive-tools", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-interactive-tools", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-interactive-tools", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-interactive-tools", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-interactive-tools", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-interactive-tools", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-interactive-tools", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-interactive-tools", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-interactive-tools", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-interactive-tools", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-interactive-tools", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-interactive-tools", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-interactive-tools", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-interactive-tools", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-interactive-tools", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-interactive-tools", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-interactive-tools", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-interactive-tools", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-interactive-tools", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-interactive-tools", "workspace:packages/plugin-interactive-tools"]],\ ["@yarnpkg/plugin-link", ["virtual:712d04b0098634bdb13868ff8f85b327022bd7d3880873ada8c0ae56847ed36cf9da1fd74a88519380129cec528fe2bd2201426bc28ac9d4a8cc6734ff25c538#workspace:packages/plugin-link", "workspace:packages/plugin-link"]],\ - ["@yarnpkg/plugin-nm", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-nm", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-nm", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-nm", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-nm", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-nm", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-nm", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-nm", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-nm", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-nm", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-nm", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-nm", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-nm", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-nm", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-nm", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-nm", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-nm", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-nm", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-nm", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-nm", "workspace:packages/plugin-nm"]],\ + ["@yarnpkg/plugin-nm", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-nm", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-nm", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-nm", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-nm", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-nm", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-nm", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-nm", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-nm", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-nm", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-nm", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-nm", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-nm", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-nm", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-nm", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-nm", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-nm", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-nm", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-nm", "workspace:packages/plugin-nm"]],\ ["@yarnpkg/plugin-npm", ["virtual:08fe6ad7a76ed00f8dc32e3b968ce66fd4db8ac47424db78612ce3633e63ecb46d41984611094facf53bbef7eae7fbf98bbfd729fb77f5ccde564684f4e3a829#workspace:packages/plugin-npm", "virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-npm", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-npm", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-npm", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-npm", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-npm", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-npm", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-npm", "virtual:4a733c8d9614e2148392368219d98ec1a70b4e8ce99164edd551241b22f6c5233e9d0ccf9f6d83265c8a5aafc617cfd3c4100b3efef1e092a42053c23770ed9a#workspace:packages/plugin-npm", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-npm", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-npm", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-npm", "virtual:712d04b0098634bdb13868ff8f85b327022bd7d3880873ada8c0ae56847ed36cf9da1fd74a88519380129cec528fe2bd2201426bc28ac9d4a8cc6734ff25c538#workspace:packages/plugin-npm", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-npm", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-npm", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-npm", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-npm", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-npm", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-npm", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-npm", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-npm", "workspace:packages/plugin-npm"]],\ ["@yarnpkg/plugin-npm-cli", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-npm-cli", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-npm-cli", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-npm-cli", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-npm-cli", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-npm-cli", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-npm-cli", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-npm-cli", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-npm-cli", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-npm-cli", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-npm-cli", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-npm-cli", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-npm-cli", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-npm-cli", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-npm-cli", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-npm-cli", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-npm-cli", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-npm-cli", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-npm-cli", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-npm-cli", "workspace:packages/plugin-npm-cli"]],\ ["@yarnpkg/plugin-pack", ["virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-pack", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-pack", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-pack", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-pack", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-pack", "virtual:27ebb8cf1fa70157f710b4926b6d25c44192e74dbac3a766c8dc6505a59ebc433221bfb4b5aabc8cca814bbe95fcb6e1ecffcf94ba96ee6112a57c89364571ac#workspace:packages/plugin-pack", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-pack", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-pack", "virtual:4a733c8d9614e2148392368219d98ec1a70b4e8ce99164edd551241b22f6c5233e9d0ccf9f6d83265c8a5aafc617cfd3c4100b3efef1e092a42053c23770ed9a#workspace:packages/plugin-pack", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-pack", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-pack", "virtual:572569575af06858e5d7f4d0dbe6c0741e76db5e6c65708522a93857213495bf1c60f4e618b217daf88fc14605c64ad49f87b67a6007ad69373fb6d52190ee49#workspace:packages/plugin-pack", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-pack", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-pack", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-pack", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-pack", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-pack", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-pack", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-pack", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-pack", "workspace:packages/plugin-pack"]],\ @@ -10345,7 +10345,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/plugin-init", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-init"],\ ["@yarnpkg/plugin-interactive-tools", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-interactive-tools"],\ ["@yarnpkg/plugin-link", "virtual:712d04b0098634bdb13868ff8f85b327022bd7d3880873ada8c0ae56847ed36cf9da1fd74a88519380129cec528fe2bd2201426bc28ac9d4a8cc6734ff25c538#workspace:packages/plugin-link"],\ - ["@yarnpkg/plugin-nm", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-nm"],\ + ["@yarnpkg/plugin-nm", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-npm", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-npm"],\ ["@yarnpkg/plugin-npm-cli", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-npm-cli"],\ ["@yarnpkg/plugin-pack", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-pack"],\ @@ -14780,10 +14780,10 @@ const RAW_RUNTIME_STATE = ],\ "linkType": "SOFT"\ }],\ - ["virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-nm", {\ - "packageLocation": "./.yarn/__virtual__/@yarnpkg-plugin-nm-virtual-2a1154edb4/1/packages/plugin-nm/",\ + ["virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm", {\ + "packageLocation": "./.yarn/__virtual__/@yarnpkg-plugin-nm-virtual-8329a655c3/1/packages/plugin-nm/",\ "packageDependencies": [\ - ["@yarnpkg/plugin-nm", "virtual:b63ad861025672af62aed0e7c80dca4cfce3194ca046161e54fc14c498c39e3b82004ea844489c7a58d2f1a31867f388bf25b8128f5ccce46f35305e1f91e9ab#workspace:packages/plugin-nm"],\ + ["@yarnpkg/plugin-nm", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm"],\ ["@types/yarnpkg__cli", null],\ ["@types/yarnpkg__core", null],\ ["@yarnpkg/cli", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/yarnpkg-cli"],\ @@ -17593,6 +17593,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:a4e4e792796cefb4fb82f09187fa18bf4c97a9cb5b106da0eab6189e1895a4bb9bf068e5c91168fec85cee1392df48e4a120f3bae6cbbbde019ff2c21186a374#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:10635d85d43c1773f587c2d6565f7a30c3bff1c16e39550dcdd44b3745dd69317ced5e20de16484758df2d6dc9314da646bf356d1ef8485a0dcd939b71a3327c#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17616,6 +17617,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:f4e4f4a9a0213f122880195b39adaee7de5cb560c1d806ebc8bace6a3124e5b8f820bbb89ebecd4d535caeb6f527d343143210aa405689c118ff2813b78998a0#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:16f564b30745199d7e07a913c371ce0c078051290c6e08b972f07b3f1bf057a6993fe67b7c6ee24931d0b1dd67e1274151612081733a79b961dd8336318fdfb9#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17639,6 +17641,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:14a22fb3831dfc762a1bb8a042d17886271c56698e1a83233f09eaacff5a5b83fe6f87adb9255774eab3586392c18ff98cf87aa6b374d572d9b72f88829f6d9e#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:1c3d72c6b31a8950672985f8306a860ecc80c9a006aac95cf4a7ba13a6e7cc4e095e37186a53c9909e9efe97bc0f7f570a74b3879778e2a2356cdcf407120006#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17662,6 +17665,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:616a2ba0d005227805d037f4c8ec29f1dd09fdb3e3f49f7b5c4a07a62139a147d373d38bc5ebcb31bddab3956c3fc25d54edf8722741d9ebdbe9d36d21968f91#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:2351fd5ac4f83ad35b714d8af9fdeea561ada341d529d0dba50742dd5735dc3750df6c56bd680e14833d5b987026a1eab6618211ea0ef1b34b727372b3c77bc9#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:616a2ba0d005227805d037f4c8ec29f1dd09fdb3e3f49f7b5c4a07a62139a147d373d38bc5ebcb31bddab3956c3fc25d54edf8722741d9ebdbe9d36d21968f91#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17685,6 +17689,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:5fe64685a823dfbb7fb4a2b3276cfc4aa0db65837fed2fdadbcc54cab047059324a7d9490b3913073dcf62fc9a7db324f81bcd6b03e1175843cddeba54bfcd85#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:261c80968f83905e40b80f5f7b27c9a820efcfd23647733e32b44cd05d9ef12b818071d95555eec63b0ccbdc23a11bcc89146137a7ea2ac0a4c1f4d3c79b18be#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17708,6 +17713,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:ef8e1544cc953676e27fe7445218564293b5a190d023e4610c14767688870b772297269e2848a1d8d72f54605aacc9da3b2b7dc56dca754d297b70b14e6a665e#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:ef8e1544cc953676e27fe7445218564293b5a190d023e4610c14767688870b772297269e2848a1d8d72f54605aacc9da3b2b7dc56dca754d297b70b14e6a665e#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:45a6746f11cef24d8db9429cc5650999571e6bb77a8cfb3904a0e832f542be35246ec490516049308ca15b8678eb03bcf394199e514a8145ec32731af7235c91#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17731,6 +17737,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:4864d30fc563f2fd1b72a5e3869493c5f50bf38f98ed3886173d80c044d981c3f68220dbf17f2b5fc5b4c5fba7d0af2e003926efe3487086484049f41c449852#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17754,6 +17761,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:35104c47575f2fe378d8d20383ae667f19d4dd801df8cc4c76848603aa6b4a2234a00142ff12fd557f6f48bd2810880e31c40c767010ea61a31fca302c2cc5e0#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:4ff153bc11101851444cc464184bde5e42ffd55b3939421c30a4c2b69483c3267c1680de4a4c00a49c98cbbe35e70111bb3c26f5ce8836b703c15cd5b753451a#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17777,6 +17785,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:712d04b0098634bdb13868ff8f85b327022bd7d3880873ada8c0ae56847ed36cf9da1fd74a88519380129cec528fe2bd2201426bc28ac9d4a8cc6734ff25c538#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:712d04b0098634bdb13868ff8f85b327022bd7d3880873ada8c0ae56847ed36cf9da1fd74a88519380129cec528fe2bd2201426bc28ac9d4a8cc6734ff25c538#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:54c8b951e743ea46368d98ac86d4c1ac7d1aa57c9d31cbf6424fa2d918257654f26f71d51dbfe63844c533e97635ff97de50fd37e6e4bf74f2603a98754d6d22#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17800,6 +17809,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:27ebb8cf1fa70157f710b4926b6d25c44192e74dbac3a766c8dc6505a59ebc433221bfb4b5aabc8cca814bbe95fcb6e1ecffcf94ba96ee6112a57c89364571ac#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:6fc63e4d1a1b8c6564cfaaeabf378b05cdf49336a90189d76df005175060690d597b069801c0c39b9c60573a6fba29e7646274224b3007bd7f72c95871114cf2#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17823,6 +17833,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:142f2540721377707149f0b1d7ad0188d020f822e234abcdca162642d42824b344a1ac44bd6035644a0ca9babd62eb7d72923350ac75b876b51e87eb92b3e464#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:a4e201fc3c2d8b3ec5632082d407d554bbf8ea8b84182577dde1ce419148ae0981b382a0805280637d50e1132628fef8f78ee6a015164963130b1310a4cca910#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17846,6 +17857,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:a027ddc7edcbf74025e90effce333897039d2c6f8e1ebe319fb72c52c5be1b885da91acc56476d19bb6ce2e31cbc2d5b11241940b82f833a2cac262496c0088f#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:a7c38e9a420fd3b408ea245831c2c9f0e880eac64b268fab3219f5f0b1d6015f44b1f92d23aabfc6e980bbbbda00a23e9faa983fb98544fab94119ccd31f2440#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:a027ddc7edcbf74025e90effce333897039d2c6f8e1ebe319fb72c52c5be1b885da91acc56476d19bb6ce2e31cbc2d5b11241940b82f833a2cac262496c0088f#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17869,6 +17881,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:cfce476fbcac37853570c2d41665757b5f868b1c2f089ee6edbc8bb5aa32141e156cae7d75350d1095258d90afbabe2b2bb142142b995d133c3ee535c89d459b#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:adaf1cec8728346f1bf6a263f1954625a52d60518b8d2084da8a926203282105d2b95fb9da84922062af8d4fc84b8a1c39f220238424024e56f55577bdbc7208#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17892,6 +17905,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:3f21a2572d1fa6d1ff8d16d86e25bcefcbff7d17161c440fdbddbd871d9d675c377d66a2cbd98ddb8f2c024060bc7bc6c01e8ae328fa1fef861c72a9b2c30755#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:b4c0e602e8ac4e01a7b08db41bb5808da767dd1f6802758faa5125fb2423614bb0a8806ee1b30c3a0769f86da15ad37377f5118d93cd93fa48df0008a448fb35#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17915,6 +17929,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17938,6 +17953,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:e3ce0ce4b7f0796ca44011528cb9cdc133fc62a76363fea6de68497bae04bdbe5a6dd47e6b9f23c282eb8e4533d75e96cf378c943d07a4e78aae0b715f06a450#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:c4bd2716e35986fb2e70f5fba6e9570c69eceabc69282df5bcff5d22c6b7d0e696d0cfb4bcbd9a20675fe3e2eb6192b59d41b97baa8b27e1d474b94eeda3f778#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17961,6 +17977,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:86c95fabbcd56c56f5f2d2e080e64a1095e3fe233877aa9f7958f317f88a95627e0be2765e89c0cff02c9f08f27b64b7cbc9d5c3960c1df509d5e6ea98cca4f4#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:ce4dc3135569e847b88addae1199f9468fb0b37867e1a86ba6725f71b9df587a8ae43356ae86c3bfe3b0cbbf07dcf8c1a4a95199810d9f20df387eec0a1e1965#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -17984,6 +18001,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:743b60015fc887fe314a7ee01ea4843b516ac512d77939f47dc39d50bc7db742dc8994fe9bb2245ada0b3ce6f8aa58329d603fbc24093050cd499cb16a1a995f#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:d1d72d9e3903ca8b8d9c23a360395cc764db2689e5992ef9af91c79f03a839db10ec675af9e4c1c8f4842aff1a614eb5b115fcc0afe8256630151ef1252de94b#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -18007,6 +18025,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:4a733c8d9614e2148392368219d98ec1a70b4e8ce99164edd551241b22f6c5233e9d0ccf9f6d83265c8a5aafc617cfd3c4100b3efef1e092a42053c23770ed9a#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:f8376ca2bc11738adced76b97627e7eff07ec08f93f5b76caf8d6bd4f78f5ae9c1911cb9d1a0bd256ef3e0601dedeba933acf0d2381588b6513ee81e25626459#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ @@ -18028,6 +18047,7 @@ const RAW_RUNTIME_STATE = ["@yarnpkg/cli", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/yarnpkg-cli"],\ ["@yarnpkg/core", "workspace:packages/yarnpkg-core"],\ ["@yarnpkg/fslib", "workspace:packages/yarnpkg-fslib"],\ + ["@yarnpkg/plugin-nm", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-nm"],\ ["@yarnpkg/plugin-pnp", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-pnp"],\ ["@yarnpkg/plugin-stage", "virtual:baf8bf095598663073ea5e8bd5af72409e894f8926160bf6fe0a24c693d417f91b536d9e3bbb0ea5f3d0ad8cd2f1ec38b71e964f9475ba719a1f5a8505cf10c3#workspace:packages/plugin-stage"],\ ["clipanion", "virtual:576bf3e379b293160348e4cadfbd6541796e6f78477b0875c4437065090cec6f78b6ec2281b8e15d1c870d61578dc7dee16a5ae49a65701fec83e592ce2ebdeb#npm:3.2.0-rc.10"],\ diff --git a/.yarn/versions/258185fa.yml b/.yarn/versions/258185fa.yml new file mode 100644 index 000000000000..38d251ce2ba0 --- /dev/null +++ b/.yarn/versions/258185fa.yml @@ -0,0 +1,23 @@ +releases: + "@yarnpkg/cli": patch + "@yarnpkg/plugin-nm": patch + "@yarnpkg/plugin-pnpm": patch + +declined: + - "@yarnpkg/plugin-compat" + - "@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/builder" + - "@yarnpkg/core" + - "@yarnpkg/doctor" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d0581fd76a0..58c41aba4a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,10 @@ The following changes only affect people writing Yarn plugins: - The `getCustomDataKey` function in `Installer` from `@yarnpkg/core` has been moved to `Linker`. +### Installs +- Improved performance for `hardlinks-global` `node-modules` linker mode by 1.5x +- Added content addressable storage support to `pnpm` linker, can be enabled via `nmMode: hardlinks-global` config setting + ### Compatibility - The patched filesystem now supports `ftruncate`. diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/node-modules.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/node-modules.test.ts index 6d63f567b7e7..685a0824ade1 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/node-modules.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/node-modules.test.ts @@ -1280,12 +1280,50 @@ describe(`Node_Modules`, () => { ), ); - test(`should wire via hardlinks files having the same content when in nmMode: hardlinks-global`, + for (const nodeLinker of [`node-modules`, `pnpm`]) { + test(`should wire via hardlinks files having the same content when in nmMode: hardlinks-global for ${nodeLinker} linker`, + makeTemporaryEnv( + { + dependencies: { + dep1: `file:./dep1`, + dep2: `file:./dep2`, + }, + }, + { + nodeLinker, + nmMode: `hardlinks-global`, + }, + async ({path, run}) => { + await writeJson(ppath.resolve(path, `dep1/package.json` as Filename), { + name: `dep1`, + version: `1.0.0`, + }); + + const content = `The same content`; + await xfs.writeFilePromise(ppath.resolve(path, `dep1/index.js` as Filename), content); + + await writeJson(ppath.resolve(path, `dep2/package.json` as Filename), { + name: `dep2`, + version: `1.0.0`, + }); + await xfs.writeFilePromise(ppath.resolve(path, `dep2/index.js` as Filename), content); + + await run(`install`); + + const stats1 = await xfs.statPromise(`${path}/node_modules/dep1/index.js` as PortablePath); + const stats2 = await xfs.statPromise(`${path}/node_modules/dep2/index.js` as PortablePath); + + expect(stats1.ino).toEqual(stats2.ino); + }, + ), + ); + } + + test(`should recover from changes to the store on next install in nmMode: hardlinks-global`, makeTemporaryEnv( { dependencies: { - dep1: `file:./dep1`, - dep2: `file:./dep2`, + dep: `file:./dep`, }, }, { @@ -1293,31 +1331,31 @@ describe(`Node_Modules`, () => { nmMode: `hardlinks-global`, }, async ({path, run}) => { - await writeJson(ppath.resolve(path, `dep1/package.json` as Filename), { - name: `dep1`, + await writeJson(ppath.resolve(path, `dep/package.json` as Filename), { + name: `dep`, version: `1.0.0`, }); - const content = `The same content`; - await xfs.writeFilePromise(ppath.resolve(path, `dep1/index.js` as Filename), content); - - await writeJson(ppath.resolve(path, `dep2/package.json` as Filename), { - name: `dep2`, - version: `1.0.0`, - }); - await xfs.writeFilePromise(ppath.resolve(path, `dep2/index.js` as Filename), content); + const originalContent = `The same content`; + await xfs.writeFilePromise(ppath.resolve(path, `dep/index.js` as Filename), originalContent); await run(`install`); - const stats1 = await xfs.statPromise(`${path}/node_modules/dep1/index.js` as PortablePath); - const stats2 = await xfs.statPromise(`${path}/node_modules/dep2/index.js` as PortablePath); + const modifiedContent = `The modified content`; + const depNmPath = ppath.resolve(path, `node_modules/dep/index.js` as Filename); + await xfs.writeFilePromise(depNmPath, modifiedContent); + + await xfs.removePromise(ppath.resolve(path, `node_modules` as Filename)); + + await run(`install`); - expect(stats1.ino).toEqual(stats2.ino); + const depContent = await xfs.readFilePromise(depNmPath, `utf8`); + expect(depContent).toEqual(originalContent); }, ), ); - test(`should recover from changes to the store on next install in nmMode: cas`, + test(`should recover from changes to the store on next install in nmMode: hardlinks-global, when system clock is changed by the user`, makeTemporaryEnv( { dependencies: { @@ -1342,6 +1380,8 @@ describe(`Node_Modules`, () => { const modifiedContent = `The modified content`; const depNmPath = ppath.resolve(path, `node_modules/dep/index.js` as Filename); await xfs.writeFilePromise(depNmPath, modifiedContent); + const timeInThePast = new Date(new Date().getTime() - 10000); + await xfs.utimesPromise(depNmPath, timeInThePast, timeInThePast); await xfs.removePromise(ppath.resolve(path, `node_modules` as Filename)); diff --git a/packages/plugin-nm/sources/NodeModulesLinker.ts b/packages/plugin-nm/sources/NodeModulesLinker.ts index 7bd0ead62bce..00c68c2fdb8a 100644 --- a/packages/plugin-nm/sources/NodeModulesLinker.ts +++ b/packages/plugin-nm/sources/NodeModulesLinker.ts @@ -16,10 +16,13 @@ import {UsageError} from import crypto from 'crypto'; import fs from 'fs'; +export const HARDLINKS_STORE_VERSION = 1; const STATE_FILE_VERSION = 1; + const NODE_MODULES = `node_modules` as Filename; const DOT_BIN = `.bin` as Filename; const INSTALL_STATE_FILE = `.yarn-state.yml` as Filename; +const MTIME_ACCURANCY = 1000; type InstallState = {locatorMap: NodeModulesLocatorMap, locationTree: LocationTree, binSymlinks: BinSymlinkMap, nmMode: NodeModulesMode, mtimeMs: number}; type BinSymlinkMap = Map>; @@ -695,56 +698,67 @@ async function atomicFileWrite(tmpDir: PortablePath, dstPath: PortablePath, cont } } -async function copyFilePromise({srcPath, dstPath, srcMode, globalHardlinksStore, baseFs, nmMode, digest}: {srcPath: PortablePath, dstPath: PortablePath, srcMode: number, globalHardlinksStore: PortablePath | null, baseFs: FakeFS, nmMode: {value: NodeModulesMode}, digest?: string}) { - if (nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL && globalHardlinksStore && digest) { - const contentFilePath = ppath.join(globalHardlinksStore, digest.substring(0, 2) as Filename, `${digest.substring(2)}.dat` as Filename); +async function copyFilePromise({srcPath, dstPath, entry, hardlinksStorePath, baseFs, nmMode}: {srcPath: PortablePath, dstPath: PortablePath, entry: DirEntry, hardlinksStorePath: PortablePath | null, baseFs: FakeFS, nmMode: {value: NodeModulesMode}}) { + if (entry.kind === DirEntryKind.FILE) { + if (nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL && hardlinksStorePath && entry.digest) { + const contentFilePath = ppath.join(hardlinksStorePath, entry.digest.substring(0, 2) as Filename, `${entry.digest.substring(2)}.dat` as Filename); - let doesContentFileExist; - try { - const contentDigest = await hashUtils.checksumFile(contentFilePath, {baseFs: xfs, algorithm: `sha1`}); - if (contentDigest !== digest) { - // If file content was modified by the user, or corrupted, we first move it out of the way - const tmpPath = ppath.join(globalHardlinksStore, toFilename(`${crypto.randomBytes(16).toString(`hex`)}.tmp`)); - await xfs.renamePromise(contentFilePath, tmpPath); + let doesContentFileExist; + try { + const stats = await xfs.statPromise(contentFilePath); + + if (stats && (!entry.mtimeMs || stats.mtimeMs > entry.mtimeMs || stats.mtimeMs < entry.mtimeMs - MTIME_ACCURANCY)) { + const contentDigest = await hashUtils.checksumFile(contentFilePath, {baseFs: xfs, algorithm: `sha1`}); + if (contentDigest !== entry.digest) { + // If file content was modified by the user, or corrupted, we first move it out of the way + const tmpPath = ppath.join(hardlinksStorePath, toFilename(`${crypto.randomBytes(16).toString(`hex`)}.tmp`)); + await xfs.renamePromise(contentFilePath, tmpPath); + + // Then we overwrite the temporary file, thus restorting content of original file in all the linked projects + const content = await baseFs.readFilePromise(srcPath); + await xfs.writeFilePromise(tmpPath, content); + + try { + // Then we try to move content file back on its place, if its still free + // If we fail here, it means that some other process or thread has created content file + // And this is okay, we will end up with two content files, but both with original content, unlucky files will have `.tmp` extension + await xfs.linkPromise(tmpPath, contentFilePath); + entry.mtimeMs = new Date().getTime(); + await xfs.unlinkPromise(tmpPath); + } catch (e) { + } + } else if (!entry.mtimeMs) { + entry.mtimeMs = Math.ceil(stats.mtimeMs); + } + } - // Then we overwrite the temporary file, thus restorting content of original file in all the linked projects - const content = await baseFs.readFilePromise(srcPath); - await xfs.writeFilePromise(tmpPath, content); + await xfs.linkPromise(contentFilePath, dstPath); + doesContentFileExist = true; + } catch (e) { + doesContentFileExist = false; + } + if (!doesContentFileExist) { + const content = await baseFs.readFilePromise(srcPath); + await atomicFileWrite(hardlinksStorePath, contentFilePath, content); + entry.mtimeMs = new Date().getTime(); try { - // Then we try to move content file back on its place, if its still free - // If we fail here, it means that some other process or thread has created content file - // And this is okay, we will end up with two content files, but both with original content, unlucky files will have `.tmp` extension - await xfs.linkPromise(tmpPath, contentFilePath); - await xfs.unlinkPromise(tmpPath); + await xfs.linkPromise(contentFilePath, dstPath); } catch (e) { + if (e && e.code && e.code == `EXDEV`) { + nmMode.value = NodeModulesMode.HARDLINKS_LOCAL; + await xfs.writeFilePromise(dstPath, await baseFs.readFilePromise(srcPath)); + } } } - await xfs.linkPromise(contentFilePath, dstPath); - doesContentFileExist = true; - } catch (e) { - doesContentFileExist = false; + } else { + await xfs.writeFilePromise(dstPath, await baseFs.readFilePromise(srcPath)); } - - if (!doesContentFileExist) { - const content = await baseFs.readFilePromise(srcPath); - await atomicFileWrite(globalHardlinksStore, contentFilePath, content); - try { - await xfs.linkPromise(contentFilePath, dstPath); - } catch (e) { - if (e && e.code && e.code == `EXDEV`) { - nmMode.value = NodeModulesMode.HARDLINKS_LOCAL; - await baseFs.copyFilePromise(srcPath, dstPath); - } - } + const mode = entry.mode & 0o777; + // An optimization - files will have rw-r-r permissions (0o644) by default, we can skip chmod for them + if (mode !== 0o644) { + await xfs.chmodPromise(dstPath, mode); } - } else { - await baseFs.copyFilePromise(srcPath, dstPath); - } - const mode = srcMode & 0o777; - // An optimization - files will have rw-r-r permissions (0o644) by default, we can skip chmod for them - if (mode !== 0o644) { - await xfs.chmodPromise(dstPath, mode); } } @@ -756,6 +770,7 @@ type DirEntry = { kind: DirEntryKind.FILE; mode: number; digest?: string; + mtimeMs?: number; } | { kind: DirEntryKind. DIRECTORY; } | { @@ -763,7 +778,7 @@ type DirEntry = { symlinkTo: PortablePath; }; -const copyPromise = async (dstDir: PortablePath, srcDir: PortablePath, {baseFs, globalHardlinksStore, nmMode, packageChecksum}: {baseFs: FakeFS, globalHardlinksStore: PortablePath | null, nmMode: {value: NodeModulesMode}, packageChecksum: string | null}) => { +export const copyPromise = async (dstDir: PortablePath, srcDir: PortablePath, {baseFs, hardlinksStorePath, nmMode, packageChecksum}: {baseFs: FakeFS, hardlinksStorePath: PortablePath | null, nmMode: {value: NodeModulesMode}, packageChecksum: string | null}) => { await xfs.mkdirPromise(dstDir, {recursive: true}); const getEntriesRecursive = async (relativePath: PortablePath = PortablePath.dot): Promise> => { @@ -802,29 +817,39 @@ const copyPromise = async (dstDir: PortablePath, srcDir: PortablePath, {baseFs, }; let allEntries: Map; - if (nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL && globalHardlinksStore && packageChecksum) { - const entriesJsonPath = ppath.join(globalHardlinksStore, packageChecksum.substring(0, 2) as Filename, `${packageChecksum.substring(2)}.json` as Filename); + if (nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL && hardlinksStorePath && packageChecksum) { + const entriesJsonPath = ppath.join(hardlinksStorePath, packageChecksum.substring(0, 2) as Filename, `${packageChecksum.substring(2)}.json` as Filename); try { allEntries = new Map(Object.entries(JSON.parse(await xfs.readFilePromise(entriesJsonPath, `utf8`)))) as Map; } catch (e) { allEntries = await getEntriesRecursive(); - await atomicFileWrite(globalHardlinksStore, entriesJsonPath, Buffer.from(JSON.stringify(Object.fromEntries(allEntries)))); } } else { allEntries = await getEntriesRecursive(); } + let mtimesChanged = false; for (const [relativePath, entry] of allEntries) { const srcPath = ppath.join(srcDir, relativePath); const dstPath = ppath.join(dstDir, relativePath); if (entry.kind === DirEntryKind.DIRECTORY) { await xfs.mkdirPromise(dstPath, {recursive: true}); } else if (entry.kind === DirEntryKind.FILE) { - await copyFilePromise({srcPath, dstPath, srcMode: entry.mode, digest: entry.digest, nmMode, baseFs, globalHardlinksStore}); + const originalMtime = entry.mtimeMs; + await copyFilePromise({srcPath, dstPath, entry, nmMode, baseFs, hardlinksStorePath}); + if (entry.mtimeMs !== originalMtime) { + mtimesChanged = true; + } } else if (entry.kind === DirEntryKind.SYMLINK) { await symlinkPromise(ppath.resolve(ppath.dirname(dstPath), entry.symlinkTo), dstPath); } } + + if (nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL && hardlinksStorePath && mtimesChanged && packageChecksum) { + const entriesJsonPath = ppath.join(hardlinksStorePath, packageChecksum.substring(0, 2) as Filename, `${packageChecksum.substring(2)}.json` as Filename); + await xfs.removePromise(entriesJsonPath); + await atomicFileWrite(hardlinksStorePath, entriesJsonPath, Buffer.from(JSON.stringify(Object.fromEntries(allEntries)))); + } }; /** @@ -1014,10 +1039,23 @@ const areRealLocatorsEqual = (locatorKey1?: LocatorKey, locatorKey2?: LocatorKey return structUtils.areLocatorsEqual(locator1, locator2); }; -export function getGlobalHardlinksStore(configuration: Configuration): PortablePath { +export function getHardlinksStoreRootPath(configuration: Configuration): PortablePath { return ppath.join(configuration.get(`globalFolder`), `store` as Filename); } +export function getHardlinksStorePath(configuration: Configuration): PortablePath { + return ppath.join(getHardlinksStoreRootPath(configuration), `v${HARDLINKS_STORE_VERSION}` as Filename); +} + +export async function ensureHardlinksStoreExists(hardlinksStorePath: PortablePath) { + if (!await xfs.existsPromise(hardlinksStorePath)) { + await xfs.mkdirpPromise(hardlinksStorePath); + for (let idx = 0; idx < 256; idx++) { + await xfs.mkdirPromise(ppath.join(hardlinksStorePath, idx.toString(16).padStart(2, `0`) as Filename)); + } + } +} + async function persistNodeModules(preinstallState: InstallState, installState: NodeModulesLocatorMap, {baseFs, project, report, loadManifest, realLocatorChecksums}: {project: Project, baseFs: FakeFS, report: Report, loadManifest: LoadManifest, realLocatorChecksums: Map}) { const rootNmDirPath = ppath.join(project.cwd, NODE_MODULES); @@ -1031,14 +1069,14 @@ async function persistNodeModules(preinstallState: InstallState, installState: N const locationTree = buildLocationTree(installState, {skipPrefix: project.cwd}); const addQueue: Array> = []; - const addModule = async ({srcDir, dstDir, linkType, globalHardlinksStore, nmMode, packageChecksum}: {srcDir: PortablePath, dstDir: PortablePath, linkType: LinkType, globalHardlinksStore: PortablePath | null, nmMode: {value: NodeModulesMode}, packageChecksum: string | null}) => { + const addModule = async ({srcDir, dstDir, linkType, hardlinksStorePath, nmMode, packageChecksum}: {srcDir: PortablePath, dstDir: PortablePath, linkType: LinkType, hardlinksStorePath: PortablePath | null, nmMode: {value: NodeModulesMode}, packageChecksum: string | null}) => { const promise: Promise = (async () => { try { if (linkType === LinkType.SOFT) { await xfs.mkdirPromise(ppath.dirname(dstDir), {recursive: true}); await symlinkPromise(ppath.resolve(srcDir), dstDir); } else { - await copyPromise(dstDir, srcDir, {baseFs, globalHardlinksStore, nmMode, packageChecksum}); + await copyPromise(dstDir, srcDir, {baseFs, hardlinksStorePath, nmMode, packageChecksum}); } } catch (e) { e.message = `While persisting ${srcDir} -> ${dstDir} ${e.message}`; @@ -1255,19 +1293,14 @@ async function persistNodeModules(preinstallState: InstallState, installState: N // source directory. We'll later use the resulting install directories for // the other instances of the same package (this will avoid us having to // crawl the zip archives for each package). - const globalHardlinksStore = nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL ? `${getGlobalHardlinksStore(project.configuration)}/v1` as PortablePath : null; - if (globalHardlinksStore) { - if (!await xfs.existsPromise(globalHardlinksStore)) { - await xfs.mkdirpPromise(globalHardlinksStore); - for (let idx = 0; idx < 256; idx++) { - await xfs.mkdirPromise(ppath.join(globalHardlinksStore, idx.toString(16).padStart(2, `0`) as Filename)); - } - } - } + const hardlinksStorePath = nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL ? getHardlinksStorePath(project.configuration) : null; + if (hardlinksStorePath) + await ensureHardlinksStoreExists(hardlinksStorePath); + for (const entry of addList) { if (entry.linkType === LinkType.SOFT || !persistedLocations.has(entry.srcDir)) { persistedLocations.set(entry.srcDir, entry.dstDir); - await addModule({...entry, globalHardlinksStore, nmMode, packageChecksum: realLocatorChecksums.get(entry.realLocatorHash) || null}); + await addModule({...entry, hardlinksStorePath, nmMode, packageChecksum: realLocatorChecksums.get(entry.realLocatorHash) || null}); } } diff --git a/packages/plugin-nm/sources/index.ts b/packages/plugin-nm/sources/index.ts index 53f33c79b3fb..7a484063c608 100644 --- a/packages/plugin-nm/sources/index.ts +++ b/packages/plugin-nm/sources/index.ts @@ -3,7 +3,9 @@ import {xfs} from '@yarnpkg/fslib'; import {NodeModulesHoistingLimits} from '@yarnpkg/nm'; import {NodeModulesLinker, NodeModulesMode} from './NodeModulesLinker'; -import {getGlobalHardlinksStore} from './NodeModulesLinker'; +import {getHardlinksStorePath, copyPromise} from './NodeModulesLinker'; +import {getHardlinksStoreRootPath} from './NodeModulesLinker'; +import {ensureHardlinksStoreExists} from './NodeModulesLinker'; import {PnpLooseLinker} from './PnpLooseLinker'; declare module '@yarnpkg/core' { @@ -17,7 +19,7 @@ declare module '@yarnpkg/core' { const plugin: Plugin = { hooks: { cleanGlobalArtifacts: async configuration => { - const globalHardlinksDirectory = getGlobalHardlinksStore(configuration); + const globalHardlinksDirectory = getHardlinksStoreRootPath(configuration); await xfs.removePromise(globalHardlinksDirectory); }, }, @@ -54,5 +56,7 @@ const plugin: Plugin = { ], }; +export {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode}; + // eslint-disable-next-line arca/no-default-export export default plugin; diff --git a/packages/plugin-pnpm/package.json b/packages/plugin-pnpm/package.json index 22f4bc6a73a9..427a7b437e27 100644 --- a/packages/plugin-pnpm/package.json +++ b/packages/plugin-pnpm/package.json @@ -5,6 +5,7 @@ "main": "./sources/index.ts", "dependencies": { "@yarnpkg/fslib": "workspace:^", + "@yarnpkg/plugin-nm": "workspace:^", "@yarnpkg/plugin-pnp": "workspace:^", "@yarnpkg/plugin-stage": "workspace:^", "clipanion": "^3.2.0-rc.10", diff --git a/packages/plugin-pnpm/sources/PnpmLinker.ts b/packages/plugin-pnpm/sources/PnpmLinker.ts index 3fa7719b4533..95a94c76af98 100644 --- a/packages/plugin-pnpm/sources/PnpmLinker.ts +++ b/packages/plugin-pnpm/sources/PnpmLinker.ts @@ -1,5 +1,6 @@ import {Descriptor, FetchResult, formatUtils, Installer, InstallPackageExtraApi, Linker, LinkOptions, LinkType, Locator, LocatorHash, Manifest, MessageName, MinimalLinkOptions, Package, Project, miscUtils, structUtils} from '@yarnpkg/core'; import {Dirent, Filename, PortablePath, ppath, xfs} from '@yarnpkg/fslib'; +import {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode} from '@yarnpkg/plugin-nm'; import {jsInstallUtils} from '@yarnpkg/plugin-pnp'; import {UsageError} from 'clipanion'; @@ -81,7 +82,10 @@ class PnpmInstaller implements Installer { private readonly asyncActions = new miscUtils.AsyncActions(10); constructor(private opts: LinkOptions) { - // Nothing to do + const nmModeSetting = this.opts.project.configuration.get(`nmMode`); + this.nmMode = {value: nmModeSetting}; + + this.hardlinksStorePath = this.nmMode.value === NodeModulesMode.HARDLINKS_GLOBAL ? getHardlinksStorePath(this.opts.project.configuration) : null; } private customData: PnpmCustomData = { @@ -89,6 +93,11 @@ class PnpmInstaller implements Installer { locatorByPath: new Map(), }; + private readonly realLocatorChecksums: Map = new Map(); + private readonly nmMode: {value: NodeModulesMode}; + private readonly hardlinksStorePath: PortablePath | null; + private isHardlinksStoreExistenceEnsured: boolean = false; + attachCustomData(customData: any) { // We don't want to attach the data because it's only used in the Linker and we'll recompute it anyways in the Installer, // it needs to be invalidated because otherwise we'll never prune the store or we might run into various issues. @@ -114,21 +123,22 @@ class PnpmInstaller implements Installer { } async installPackageHard(pkg: Package, fetchResult: FetchResult, api: InstallPackageExtraApi) { + if (this.hardlinksStorePath && !this.isHardlinksStoreExistenceEnsured) + await ensureHardlinksStoreExists(this.hardlinksStorePath); + const pkgPath = getPackageLocation(pkg, {project: this.opts.project}); this.customData.locatorByPath.set(pkgPath, structUtils.stringifyLocator(pkg)); this.customData.pathByLocator.set(pkg.locatorHash, pkgPath); - api.holdFetchResult(this.asyncActions.set(pkg.locatorHash, async () => { - await xfs.mkdirPromise(pkgPath, {recursive: true}); - - // Copy the package source into the /n_m/.store/ directory, so - // that we can then create symbolic links to it later. - await xfs.copyPromise(pkgPath, fetchResult.prefixPath, { + api.holdFetchResult(this.asyncActions.set(pkg.locatorHash, async () => + await copyPromise(pkgPath, ppath.join(PortablePath.root, fetchResult.prefixPath), { baseFs: fetchResult.packageFs, - overwrite: false, - }); - })); + hardlinksStorePath: this.hardlinksStorePath, + nmMode: this.nmMode, + packageChecksum: this.realLocatorChecksums.get(pkg.locatorHash) || null}, + ), + )); const isVirtual = structUtils.isVirtualLocator(pkg); const devirtualizedLocator: Locator = isVirtual ? structUtils.devirtualizeLocator(pkg) : pkg; @@ -143,6 +153,18 @@ class PnpmInstaller implements Installer { const dependencyMeta = this.opts.project.getDependencyMeta(devirtualizedLocator, pkg.version); const buildScripts = jsInstallUtils.extractBuildScripts(pkg, buildConfig, dependencyMeta, {configuration: this.opts.project.configuration, report: this.opts.report}); + let realLocator: Locator = pkg; + // Only virtual packages should have effective peer dependencies, but the + // workspaces are a special case because the original packages are kept in + // the dependency tree even after being virtualized; so in their case we + // just ignore their declared peer dependencies. + if (structUtils.isVirtualLocator(pkg)) + realLocator = structUtils.devirtualizeLocator(pkg); + + // We need ZIP contents checksum for CAS addressing purposes, so we need to strip cache key from checksum here + const checksum = fetchResult.checksum ? fetchResult.checksum.substring(fetchResult.checksum.indexOf(`/`) + 1) : null; + this.realLocatorChecksums.set(realLocator.locatorHash, checksum); + return { packageLocation: pkgPath, buildDirective: buildScripts, diff --git a/yarn.lock b/yarn.lock index 34d4fd102377..7ac0e7c65a2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6134,6 +6134,7 @@ __metadata: "@yarnpkg/cli": "workspace:^" "@yarnpkg/core": "workspace:^" "@yarnpkg/fslib": "workspace:^" + "@yarnpkg/plugin-nm": "workspace:^" "@yarnpkg/plugin-pnp": "workspace:^" "@yarnpkg/plugin-stage": "workspace:^" clipanion: "npm:^3.2.0-rc.10" From 36513747ae980234ef39280220d6d0e9dbe310e8 Mon Sep 17 00:00:00 2001 From: Victor Vlasenko Date: Tue, 7 Jun 2022 15:48:53 +0300 Subject: [PATCH 2/5] Redeclare NodeModulesMode enum to workaround TS errors --- packages/plugin-nm/sources/index.ts | 2 +- packages/plugin-pnpm/sources/PnpmLinker.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/plugin-nm/sources/index.ts b/packages/plugin-nm/sources/index.ts index 7a484063c608..35d673563d0d 100644 --- a/packages/plugin-nm/sources/index.ts +++ b/packages/plugin-nm/sources/index.ts @@ -56,7 +56,7 @@ const plugin: Plugin = { ], }; -export {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode}; +export {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise}; // eslint-disable-next-line arca/no-default-export export default plugin; diff --git a/packages/plugin-pnpm/sources/PnpmLinker.ts b/packages/plugin-pnpm/sources/PnpmLinker.ts index 95a94c76af98..d1d520293bc3 100644 --- a/packages/plugin-pnpm/sources/PnpmLinker.ts +++ b/packages/plugin-pnpm/sources/PnpmLinker.ts @@ -1,9 +1,15 @@ import {Descriptor, FetchResult, formatUtils, Installer, InstallPackageExtraApi, Linker, LinkOptions, LinkType, Locator, LocatorHash, Manifest, MessageName, MinimalLinkOptions, Package, Project, miscUtils, structUtils} from '@yarnpkg/core'; import {Dirent, Filename, PortablePath, ppath, xfs} from '@yarnpkg/fslib'; -import {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode} from '@yarnpkg/plugin-nm'; +import {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise} from '@yarnpkg/plugin-nm'; import {jsInstallUtils} from '@yarnpkg/plugin-pnp'; import {UsageError} from 'clipanion'; +enum NodeModulesMode { + CLASSIC = `classic`, + HARDLINKS_LOCAL = `hardlinks-local`, + HARDLINKS_GLOBAL = `hardlinks-global`, +} + export type PnpmCustomData = { pathByLocator: Map; locatorByPath: Map; From 28e3bc9c995b2dd57774e9339020e37ddf650e42 Mon Sep 17 00:00:00 2001 From: Victor Vlasenko Date: Tue, 7 Jun 2022 16:43:21 +0300 Subject: [PATCH 3/5] Simplifies package checksum retrieving --- packages/plugin-pnpm/sources/PnpmLinker.ts | 24 +++++++--------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/packages/plugin-pnpm/sources/PnpmLinker.ts b/packages/plugin-pnpm/sources/PnpmLinker.ts index d1d520293bc3..34affae33e48 100644 --- a/packages/plugin-pnpm/sources/PnpmLinker.ts +++ b/packages/plugin-pnpm/sources/PnpmLinker.ts @@ -99,7 +99,6 @@ class PnpmInstaller implements Installer { locatorByPath: new Map(), }; - private readonly realLocatorChecksums: Map = new Map(); private readonly nmMode: {value: NodeModulesMode}; private readonly hardlinksStorePath: PortablePath | null; private isHardlinksStoreExistenceEnsured: boolean = false; @@ -137,14 +136,17 @@ class PnpmInstaller implements Installer { this.customData.locatorByPath.set(pkgPath, structUtils.stringifyLocator(pkg)); this.customData.pathByLocator.set(pkg.locatorHash, pkgPath); - api.holdFetchResult(this.asyncActions.set(pkg.locatorHash, async () => + // We need ZIP contents checksum for CAS addressing purposes, so we need to strip cache key from checksum here + const packageChecksum = fetchResult.checksum ? fetchResult.checksum.substring(fetchResult.checksum.indexOf(`/`) + 1) : null; + + api.holdFetchResult(this.asyncActions.set(pkg.locatorHash, async () => { await copyPromise(pkgPath, ppath.join(PortablePath.root, fetchResult.prefixPath), { baseFs: fetchResult.packageFs, hardlinksStorePath: this.hardlinksStorePath, nmMode: this.nmMode, - packageChecksum: this.realLocatorChecksums.get(pkg.locatorHash) || null}, - ), - )); + packageChecksum, + }); + })); const isVirtual = structUtils.isVirtualLocator(pkg); const devirtualizedLocator: Locator = isVirtual ? structUtils.devirtualizeLocator(pkg) : pkg; @@ -159,18 +161,6 @@ class PnpmInstaller implements Installer { const dependencyMeta = this.opts.project.getDependencyMeta(devirtualizedLocator, pkg.version); const buildScripts = jsInstallUtils.extractBuildScripts(pkg, buildConfig, dependencyMeta, {configuration: this.opts.project.configuration, report: this.opts.report}); - let realLocator: Locator = pkg; - // Only virtual packages should have effective peer dependencies, but the - // workspaces are a special case because the original packages are kept in - // the dependency tree even after being virtualized; so in their case we - // just ignore their declared peer dependencies. - if (structUtils.isVirtualLocator(pkg)) - realLocator = structUtils.devirtualizeLocator(pkg); - - // We need ZIP contents checksum for CAS addressing purposes, so we need to strip cache key from checksum here - const checksum = fetchResult.checksum ? fetchResult.checksum.substring(fetchResult.checksum.indexOf(`/`) + 1) : null; - this.realLocatorChecksums.set(realLocator.locatorHash, checksum); - return { packageLocation: pkgPath, buildDirective: buildScripts, From 416fcdd3fe9606b5e17b7c6a9aeecc6c59647f80 Mon Sep 17 00:00:00 2001 From: Victor Vlasenko Date: Tue, 7 Jun 2022 17:33:00 +0300 Subject: [PATCH 4/5] Fixes TS errors for NodeModulesMode --- packages/plugin-nm/sources/NodeModulesLinker.ts | 2 +- packages/plugin-nm/sources/core.d.ts | 9 +++++++++ packages/plugin-nm/sources/index.ts | 10 +--------- packages/plugin-pnpm/sources/PnpmLinker.ts | 8 +------- 4 files changed, 12 insertions(+), 17 deletions(-) create mode 100644 packages/plugin-nm/sources/core.d.ts diff --git a/packages/plugin-nm/sources/NodeModulesLinker.ts b/packages/plugin-nm/sources/NodeModulesLinker.ts index 00c68c2fdb8a..3c6df9514a2d 100644 --- a/packages/plugin-nm/sources/NodeModulesLinker.ts +++ b/packages/plugin-nm/sources/NodeModulesLinker.ts @@ -710,7 +710,7 @@ async function copyFilePromise({srcPath, dstPath, entry, hardlinksStorePath, bas if (stats && (!entry.mtimeMs || stats.mtimeMs > entry.mtimeMs || stats.mtimeMs < entry.mtimeMs - MTIME_ACCURANCY)) { const contentDigest = await hashUtils.checksumFile(contentFilePath, {baseFs: xfs, algorithm: `sha1`}); if (contentDigest !== entry.digest) { - // If file content was modified by the user, or corrupted, we first move it out of the way + // If file content was modified by the user, or corrupted, we first move it out of the way const tmpPath = ppath.join(hardlinksStorePath, toFilename(`${crypto.randomBytes(16).toString(`hex`)}.tmp`)); await xfs.renamePromise(contentFilePath, tmpPath); diff --git a/packages/plugin-nm/sources/core.d.ts b/packages/plugin-nm/sources/core.d.ts new file mode 100644 index 000000000000..a1881a6f51c2 --- /dev/null +++ b/packages/plugin-nm/sources/core.d.ts @@ -0,0 +1,9 @@ +import '@yarnpkg/core'; + +declare module '@yarnpkg/core' { + interface ConfigurationValueMap { + nmHoistingLimits: NodeModulesHoistingLimits; + nmMode: NodeModulesMode; + nmSelfReferences: boolean; + } +} diff --git a/packages/plugin-nm/sources/index.ts b/packages/plugin-nm/sources/index.ts index 35d673563d0d..1fdbde2c0cda 100644 --- a/packages/plugin-nm/sources/index.ts +++ b/packages/plugin-nm/sources/index.ts @@ -8,14 +8,6 @@ import {getHardlinksStoreRootPath} from './NodeModulesLinker'; import {ensureHardlinksStoreExists} from './NodeModulesLinker'; import {PnpLooseLinker} from './PnpLooseLinker'; -declare module '@yarnpkg/core' { - interface ConfigurationValueMap { - nmHoistingLimits: NodeModulesHoistingLimits; - nmMode: NodeModulesMode; - nmSelfReferences: boolean; - } -} - const plugin: Plugin = { hooks: { cleanGlobalArtifacts: async configuration => { @@ -56,7 +48,7 @@ const plugin: Plugin = { ], }; -export {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise}; +export {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode}; // eslint-disable-next-line arca/no-default-export export default plugin; diff --git a/packages/plugin-pnpm/sources/PnpmLinker.ts b/packages/plugin-pnpm/sources/PnpmLinker.ts index 34affae33e48..f778ea367159 100644 --- a/packages/plugin-pnpm/sources/PnpmLinker.ts +++ b/packages/plugin-pnpm/sources/PnpmLinker.ts @@ -1,15 +1,9 @@ import {Descriptor, FetchResult, formatUtils, Installer, InstallPackageExtraApi, Linker, LinkOptions, LinkType, Locator, LocatorHash, Manifest, MessageName, MinimalLinkOptions, Package, Project, miscUtils, structUtils} from '@yarnpkg/core'; import {Dirent, Filename, PortablePath, ppath, xfs} from '@yarnpkg/fslib'; -import {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise} from '@yarnpkg/plugin-nm'; +import {getHardlinksStorePath, ensureHardlinksStoreExists, copyPromise, NodeModulesMode} from '@yarnpkg/plugin-nm'; import {jsInstallUtils} from '@yarnpkg/plugin-pnp'; import {UsageError} from 'clipanion'; -enum NodeModulesMode { - CLASSIC = `classic`, - HARDLINKS_LOCAL = `hardlinks-local`, - HARDLINKS_GLOBAL = `hardlinks-global`, -} - export type PnpmCustomData = { pathByLocator: Map; locatorByPath: Map; From 94a66e00c3599f0722c7ee1b86053f8d4818f8d6 Mon Sep 17 00:00:00 2001 From: Victor Vlasenko Date: Tue, 7 Jun 2022 17:40:21 +0300 Subject: [PATCH 5/5] Code cleanup --- packages/plugin-nm/sources/NodeModulesLinker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-nm/sources/NodeModulesLinker.ts b/packages/plugin-nm/sources/NodeModulesLinker.ts index 3c6df9514a2d..e1f7d873a397 100644 --- a/packages/plugin-nm/sources/NodeModulesLinker.ts +++ b/packages/plugin-nm/sources/NodeModulesLinker.ts @@ -16,7 +16,7 @@ import {UsageError} from import crypto from 'crypto'; import fs from 'fs'; -export const HARDLINKS_STORE_VERSION = 1; +const HARDLINKS_STORE_VERSION = 1; const STATE_FILE_VERSION = 1; const NODE_MODULES = `node_modules` as Filename;