From 3779a94e10a012f32c557ff848c9495b817028de Mon Sep 17 00:00:00 2001 From: Danny Guo Date: Fri, 3 Mar 2017 00:16:14 -0500 Subject: [PATCH] Add optional offline mirror pruning --- __tests__/commands/remove.js | 10 ++++ __tests__/commands/upgrade.js | 13 +++++ .../remove/prune-offline-mirror/.yarnrc | 6 ++ .../mirror-for-offline/dep-a-1.0.0.tgz | Bin 0 -> 886 bytes .../mirror-for-offline/dep-b-1.0.0.tgz | Bin 0 -> 866 bytes .../mirror-for-offline/dep-c-1.0.0.tgz | Bin 0 -> 570 bytes .../remove/prune-offline-mirror/package.json | 6 ++ .../remove/prune-offline-mirror/yarn.lock | 17 ++++++ .../upgrade/prune-offline-mirror/.yarnrc | 6 ++ .../mirror-for-offline/dep-a-1.0.0.tgz | Bin 0 -> 886 bytes .../mirror-for-offline/dep-a-1.1.0.tgz | Bin 0 -> 567 bytes .../mirror-for-offline/dep-b-1.0.0.tgz | Bin 0 -> 866 bytes .../upgrade/prune-offline-mirror/package.json | 5 ++ .../upgrade/prune-offline-mirror/yarn.lock | 17 ++++++ src/cli/commands/install.js | 52 +++++++++++++++++- src/config.js | 4 ++ 16 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 __tests__/fixtures/remove/prune-offline-mirror/.yarnrc create mode 100644 __tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-a-1.0.0.tgz create mode 100644 __tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-b-1.0.0.tgz create mode 100644 __tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-c-1.0.0.tgz create mode 100755 __tests__/fixtures/remove/prune-offline-mirror/package.json create mode 100755 __tests__/fixtures/remove/prune-offline-mirror/yarn.lock create mode 100644 __tests__/fixtures/upgrade/prune-offline-mirror/.yarnrc create mode 100644 __tests__/fixtures/upgrade/prune-offline-mirror/mirror-for-offline/dep-a-1.0.0.tgz create mode 100644 __tests__/fixtures/upgrade/prune-offline-mirror/mirror-for-offline/dep-a-1.1.0.tgz create mode 100644 __tests__/fixtures/upgrade/prune-offline-mirror/mirror-for-offline/dep-b-1.0.0.tgz create mode 100755 __tests__/fixtures/upgrade/prune-offline-mirror/package.json create mode 100755 __tests__/fixtures/upgrade/prune-offline-mirror/yarn.lock diff --git a/__tests__/commands/remove.js b/__tests__/commands/remove.js index c23fba74bd..9edea77ffc 100644 --- a/__tests__/commands/remove.js +++ b/__tests__/commands/remove.js @@ -140,3 +140,13 @@ test.concurrent('removes subdependencies', (): Promise => { assert.equal(lockFileLines[0], 'dep-c@^1.0.0:'); }); }); + +test.concurrent('can prune the offline mirror', (): Promise => { + return runRemove(['dep-a'], {}, 'prune-offline-mirror', async (config, reporter) => { + const mirrorPath = 'mirror-for-offline'; + assert(!await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-a-1.0.0.tgz`))); + // dep-a depends on dep-b, so dep-b should also be pruned + assert(!await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-b-1.0.0.tgz`))); + assert(await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-c-1.0.0.tgz`))); + }); +}); diff --git a/__tests__/commands/upgrade.js b/__tests__/commands/upgrade.js index 937008f180..912d7da1fa 100644 --- a/__tests__/commands/upgrade.js +++ b/__tests__/commands/upgrade.js @@ -165,3 +165,16 @@ test.concurrent('doesn\'t warn when peer dependency is still met after upgrade', 'peer-dependency-no-warn', ); }); + +test.concurrent('can prune the offline mirror', (): Promise => { + return runUpgrade(['dep-a@1.1.0'], {}, 'prune-offline-mirror', async (config): ?Promise => { + const lockfile = explodeLockfile(await fs.readFile(path.join(config.cwd, 'yarn.lock'))); + assert(lockfile.indexOf('dep-a@1.1.0:') === 0); + + const mirrorPath = 'mirror-for-offline'; + assert(await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-a-1.1.0.tgz`))); + assert(!await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-a-1.0.0.tgz`))); + // In 1.1.0, dep-a doesn't depend on dep-b anymore, so dep-b should be pruned + assert(!await fs.exists(path.join(config.cwd, `${mirrorPath}/dep-b-1.0.0.tgz`))); + }); +}); diff --git a/__tests__/fixtures/remove/prune-offline-mirror/.yarnrc b/__tests__/fixtures/remove/prune-offline-mirror/.yarnrc new file mode 100644 index 0000000000..444ff9631b --- /dev/null +++ b/__tests__/fixtures/remove/prune-offline-mirror/.yarnrc @@ -0,0 +1,6 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +yarn-offline-mirror "./mirror-for-offline" +yarn-offline-mirror-pruning true diff --git a/__tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-a-1.0.0.tgz b/__tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-a-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..89a694e0667f608a9b0b99fb5fbd4b2b599a7ad0 GIT binary patch literal 886 zcmV-+1Bv_}iwFP!000001MQaGj?*|4$GZ|2$WL*|1p^}{jh!?}85u2NcLmb2pap5Q z8jXaTdRo)ej-0e~cBr&3wokzet(}iHOFJtN!*|Y&<&*z8c24YH&QrE}$k~|de#Vj+ zoA73IU*<~ouEadg3xfc9f7?ks{l|{i)te))G)(*mdYD8$8IXVw-1G1t2nWzxUCr|U zZ;QNO+HCPd^HeVboAE0#JcQq#{Pgql`@g$mo)uGy5eYV~GnJ<56+L5V&XFH({9+=N z=D&!P=dMRxnawNDWg1M~i6|OPyjMeL`{W_t+o&49WOGi;tYx@hlyBn2}_nPIEWmWg!@{vbL9IwIhI`KHXgg4>$Nx92xk2JmC|GT)*`Rd z1edEY<@umplpO`3tjrSZW-)Kd<(SJvnCjTq9yR;IJK9tvT;`lUe)JrXA!N*a$$b|Z zk!@^oo^fhxkBAS?9z1;X>z`(sCBUKGXc(=$qEx%i9Iz#E2$kS3XsiVkoz^h2`*fl@-SId@(wQYEvT#^`fjk8j>S z9`(1jkN-bx`0x4V_`St{e^8?IsyDLFzH|Pg3k2X;vO0IcDdFnev91!*XsM-|2LeLU)Kt#9z3HD09L<*Q8TA~)q~>iqgO zoGoNxe_wFRB)DBRzIBEhH*8M0c@qv!R9WBZtDGJHrMB*F!qT)1J4Wl{4xOEK*4aDQ MzhZ+u8~_*q0BU*4qW}N^ literal 0 HcmV?d00001 diff --git a/__tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-b-1.0.0.tgz b/__tests__/fixtures/remove/prune-offline-mirror/mirror-for-offline/dep-b-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4a4afe531cfb26ea31d3dbcb57287d575a6683fc GIT binary patch literal 866 zcmV-o1D*UIiwFP!000001MQaGZre5#$30*d1E1nl7flF?F3{&?tB!Z`9_fJy9=kOU+M2ObWC2*Y4?JS z7DdUl+2ZHssb2;*<1G;$!A~#0`~J<7pWQLf%PGZ(1RK+t$};typ0TXp$d5L5F_B91 zXCmW;>rq$c^V)Ki52o%!l&w#)*N4#VpND*J5aR%j-!$d5(geA)s97F+3!V|68Ir9CT980bX8;@Pj^|~8v9cKLez0za*)}m^}0*~XUVIj6Rsi1_gO>GKyq z{Avobq&SM>m=F))q&3S-$eH=vIEIB7(@_xlNkWp?x=f4#Cvk+a7spBWk2uX{h4{c} z;Ef_gNSjPZMME5q{KPClpmM<@4-u~usnS_N6ZBvI^1V8`IqGk}*4=J!T|H=kXfqooI%wUas#ZW`oA!? z=im4I!1&?FoPTo{1%3bbZ>aD8Zb$zY{(d~vD99->d?T>S&*&HtBV#UX6 zd)HJ}&C7+BaB-?swyx_mSK~#-UB1edE(=qxw$2|v!r4Nm_WFW*Cc*ux@oh5Pxnpy} s-Mesbtg8CfU*+TgD7AHWQ%9wiwFSpgu7S(1MQVdZ`wc*fI0hDOne9lO3fN$ECo@u>ZymShgRwVA!TC^ z;9z#G^_qeR|GjH_okVTuLn@Wp&UYE_cxHDzk9E%D6<=V#b3zznQ5ZrkM~!5IVIwWz z2P_;#Y!LVim>&#-umj;KgK8-Y&6Noy;X>>dr95V5%;xj&>|?*R_ zr#QppV>BEduYWWcfj=lNCiS_Fwd|^ zHz?p{!?T+v9N+?YeX?0sD%|pQp5e7!T5MPs)7jm z04aWVkNs%=2T|~F{|};i{-YtI`Tr9*RhPMfuhG2*H^KZx>|Rx>1dCXudDV~An>S00 zSCG!146Et3678hc-Pky8P!-n6_n5~T?Fx6FrAi8;p1QW@-79dh2rE%fx;wKc=V<;$ zB2KX~-ydpimc}TGI?8u%Kf2E07n+;tYx@hlyBn2}_nPIEWmWg!@{vbL9IwIhI`KHXgg4>$Nx92xk2JmC|GT)*`Rd z1edEY<@umplpO`3tjrSZW-)Kd<(SJvnCjTq9yR;IJK9tvT;`lUe)JrXA!N*a$$b|Z zk!@^oo^fhxkBAS?9z1;X>z`(sCBUKGXc(=$qEx%i9Iz#E2$kS3XsiVkoz^h2`*fl@-SId@(wQYEvT#^`fjk8j>S z9`(1jkN-bx`0x4V_`St{e^8?IsyDLFzH|Pg3k2X;vO0IcDdFnev91!*XsM-|2LeLU)Kt#9z3HD09L<*Q8TA~)q~>iqgO zoGoNxe_wFRB)DBRzIBEhH*8M0c@qv!R9WBZtDGJHrMB*F!qT)1J4Wl{4xOEK*4aDQ MzhZ+u8~_*q0BU*4qW}N^ literal 0 HcmV?d00001 diff --git a/__tests__/fixtures/upgrade/prune-offline-mirror/mirror-for-offline/dep-a-1.1.0.tgz b/__tests__/fixtures/upgrade/prune-offline-mirror/mirror-for-offline/dep-a-1.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..33db3dbc39c13f1c45b0388c8b1ec1a6a2c6067e GIT binary patch literal 567 zcmV-70?7RziwFSDDZ5wz1MQVdZ<|06fOFkWg@KZEd;L3LE6Vp4~aFwVD&N*uG(X7l-X_A&4AMgAoerv52UaN|6b zr#M6BBMO4!^&j~Wc>d5G2HMVxbp1om^UlCMMKE9UpV!|S^!pa{AuV4^$+r4-U|DM> zI|WRjk&ao9tw;pqr zmCw2KddF>R{i}jWmcuSjH<;`}zeS^!s4B@}cP~V?Z}XIkq{`62O(CQzb-KDdKR&{| z;;~8vhfBS|73?ekv%~p$y(e5;KyNCV{I*q@^IE(eU8=@741^3TXcS2v*%?HfK57H()1NykPcqtxB+rWm?qzSU-8Q#CQei z{9sshw^e8+wduyzagDMxPM+gAZmV74_LGoFsnt{4^t^oyHkM&6nn|~3=HvqP--yR4 z*5F?F3{&?tB!Z`9_fJy9=kOU+M2ObWC2*Y4?JS z7DdUl+2ZHssb2;*<1G;$!A~#0`~J<7pWQLf%PGZ(1RK+t$};typ0TXp$d5L5F_B91 zXCmW;>rq$c^V)Ki52o%!l&w#)*N4#VpND*J5aR%j-!$d5(geA)s97F+3!V|68Ir9CT980bX8;@Pj^|~8v9cKLez0za*)}m^}0*~XUVIj6Rsi1_gO>GKyq z{Avobq&SM>m=F))q&3S-$eH=vIEIB7(@_xlNkWp?x=f4#Cvk+a7spBWk2uX{h4{c} z;Ef_gNSjPZMME5q{KPClpmM<@4-u~usnS_N6ZBvI^1V8`IqGk}*4=J!T|H=kXfqooI%wUas#ZW`oA!? z=im4I!1&?FoPTo{1%3bbZ>aD8Zb$zY{(d~vD99->d?T>S&*&HtBV#UX6 zd)HJ}&C7+BaB-?swyx_mSK~#-UB1edE(=qxw$2|v!r4Nm_WFW*Cc*ux@oh5Pxnpy} s-Mesbtg8CfU*+TgD7AHWQ): boolean { + let inSync = true; + for (const pattern of patterns) { + if (!this.lockfile.getLocked(pattern)) { + inSync = false; + break; + } + } + return inSync; + } + + /** + * Remove offline tarballs that are no longer required + */ + + async pruneOfflineMirror(lockfile: Object): Promise { + const mirror = this.config.getOfflineMirrorPath(); + if (!mirror) { + return; + } + + const requiredTarballs = new Set(); + for (const dependency in lockfile) { + const resolved = lockfile[dependency].resolved; + if (resolved) { + requiredTarballs.add(resolved.split('#')[0]); + } + } + + const mirrorTarballs = await fs.walk(mirror); + for (const tarball of mirrorTarballs) { + if (!requiredTarballs.has(tarball.basename)) { + await fs.unlink(tarball.absolute); + } + } + } + /** * Save updated integrity and lockfiles. */ @@ -559,8 +602,13 @@ export class Install { return; } - // stringify current lockfile - const lockSource = lockStringify(this.lockfile.getLockfile(this.resolver.patterns)); + const lockfile = this.lockfile.getLockfile(this.resolver.patterns); + + if (this.config.pruneOfflineMirror) { + await this.pruneOfflineMirror(lockfile); + } + + const lockSource = lockStringify(lockfile); // write integrity hash await this.integrityChecker.save(patterns, lockSource, this.flags, this.resolver.usedRegistries); diff --git a/src/config.js b/src/config.js index 339488fa5c..8a636d057e 100644 --- a/src/config.js +++ b/src/config.js @@ -29,6 +29,7 @@ export type ConfigOptions = { linkFolder?: ?string, offline?: boolean, preferOffline?: boolean, + pruneOfflineMirror?: boolean, captureHar?: boolean, ignoreScripts?: boolean, ignorePlatform?: boolean, @@ -85,6 +86,7 @@ export default class Config { looseSemver: boolean; offline: boolean; preferOffline: boolean; + pruneOfflineMirror: boolean; ignorePlatform: boolean; binLinks: boolean; @@ -241,6 +243,8 @@ export default class Config { constants.MODULE_CACHE_DIRECTORY, ); + this.pruneOfflineMirror = Boolean(this.getOption('yarn-offline-mirror-pruning')); + //init & create cacheFolder, tempFolder this.cacheFolder = path.join(this._cacheRootFolder, 'v' + String(constants.CACHE_VERSION)); this.tempFolder = opts.tempFolder || path.join(this.cacheFolder, '.tmp');