Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions __tests__/commands/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,13 @@ test.concurrent('removes subdependencies', (): Promise<void> => {
assert.equal(lockFileLines[0], 'dep-c@^1.0.0:');
});
});

test.concurrent('can prune the offline mirror', (): Promise<void> => {
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`)));
});
});
13 changes: 13 additions & 0 deletions __tests__/commands/upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> => {
return runUpgrade(['dep-a@1.1.0'], {}, 'prune-offline-mirror', async (config): ?Promise<void> => {
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`)));
});
});
6 changes: 6 additions & 0 deletions __tests__/fixtures/remove/prune-offline-mirror/.yarnrc
Original file line number Diff line number Diff line change
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions __tests__/fixtures/remove/prune-offline-mirror/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"dep-a": "1.0.0",
"dep-c": "1.0.0"
}
}
17 changes: 17 additions & 0 deletions __tests__/fixtures/remove/prune-offline-mirror/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


dep-a@1.0.0:
version "1.0.0"
resolved dep-a-1.0.0.tgz#d170a960654001b74bdee4747e71f744ecf0a24f
dependencies:
dep-b "1.0.0"

dep-b@1.0.0:
version "1.0.0"
resolved dep-b-1.0.0.tgz#fa3fab4e36d8eb93ac74790748a30547e9cb0f3f

dep-c@1.0.0:
version "1.0.0"
resolved dep-c-1.0.0.tgz#67156f3be73744a1d4b7c959c4d0d3575e54f442
6 changes: 6 additions & 0 deletions __tests__/fixtures/upgrade/prune-offline-mirror/.yarnrc
Original file line number Diff line number Diff line change
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions __tests__/fixtures/upgrade/prune-offline-mirror/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"dep-a": "1.0.0"
}
}
17 changes: 17 additions & 0 deletions __tests__/fixtures/upgrade/prune-offline-mirror/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


dep-a@1.0.0:
version "1.0.0"
resolved dep-a-1.0.0.tgz#d170a960654001b74bdee4747e71f744ecf0a24f
dependencies:
dep-b "1.0.0"

dep-a@1.1.0:
version "1.1.0"
resolved dep-a-1.1.0.tgz#a347d002113da949bd89b6b71195ec3bca09db7a

dep-b@1.0.0:
version "1.0.0"
resolved dep-b-1.0.0.tgz#fa3fab4e36d8eb93ac74790748a30547e9cb0f3f
52 changes: 50 additions & 2 deletions src/cli/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,49 @@ export class Install {
return flattenedPatterns;
}

/**
<<<<<<< HEAD
=======
* Check if the loaded lockfile has all the included patterns
*/

lockFileInSync(patterns: Array<string>): 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<void> {
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]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it is okay to depend on the format of resolved like this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests would fail if there are breaking changes.
I suppose it should be fine.

}
}

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.
*/
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type ConfigOptions = {
linkFolder?: ?string,
offline?: boolean,
preferOffline?: boolean,
pruneOfflineMirror?: boolean,
captureHar?: boolean,
ignoreScripts?: boolean,
ignorePlatform?: boolean,
Expand Down Expand Up @@ -85,6 +86,7 @@ export default class Config {
looseSemver: boolean;
offline: boolean;
preferOffline: boolean;
pruneOfflineMirror: boolean;
ignorePlatform: boolean;
binLinks: boolean;

Expand Down Expand Up @@ -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');
Expand Down