Skip to content

Commit

Permalink
Cleaning node_modules/.cache
Browse files Browse the repository at this point in the history
New flag: clearSharedCache
When enabled, it cleans node_modules/.cache before each push
  • Loading branch information
mutantcornholio committed Jan 11, 2020
1 parent 1862c18 commit 51949a8
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 13 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ Example:
```js
veendorVersion: '>=2.1'
```
Please notice that `veendorVersion` option is not supported in veendor before 2.0, so if your team might use 1.x, add this to your .veendor.js:

```js
if (!global.VEENDOR_VERSION) {
throw new Error('veendor version is incompatible, please update');
}
```

#### dedupe
Optional, defaults to `false`
Expand All @@ -135,11 +142,13 @@ Example:
dedupe: true
```

Please notice that `veendorVersion` option is not supported in veendor before 2.0, so if your team might use 1.x, add this to your .veendor.js:
#### clearSharedCache
Optional, defaults to `false`
Some software (e.g. babel) uses `node_modules/.cache` as a place for caches. In cases when such software runs in postinstall scripts or just in cases of poor luck, these caches may end up in your veendor bundles.
If you add `clearSharedCache: true` to your config, veendor will remove said directory from your `node_modules` before each push.
Example:
```js
if (!global.VEENDOR_VERSION) {
throw new Error('veendor version is incompatible, please update');
}
clearSharedCache: true
```

### Built-in backends
Expand Down
4 changes: 2 additions & 2 deletions src/lib/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import {getLogger} from '@/lib/util/logger';
import * as helpers from './helpers';
import pushBackends from './pushBackends';
import {pushBackends} from './pushBackends';
import * as rsyncWrapper from '@/lib/commandWrappers/rsyncWrapper';
import * as npmWrapper from '@/lib/commandWrappers/npmWrapper';
import * as gitWrapper from '@/lib/commandWrappers/gitWrapper';
Expand Down Expand Up @@ -164,7 +164,7 @@ export default async function install(
* Pushing bundle
*/
try {
await pushBackends(backendsToPush, hash, false);
await pushBackends(backendsToPush, hash, false, config.clearSharedCache);
} catch (pushError) {
if (pushError instanceof errors.RePullNeeded) {
// this happens if we failed to push bundle because someone got faster then us
Expand Down
24 changes: 20 additions & 4 deletions src/lib/install/pushBackends.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
import fsExtra from 'fs-extra';
import path from 'path';

import {BackendCalls, BackendConfig} from '@/types';

import * as errors from '../errors';
import {getLogger} from '../util/logger';
import * as helpers from './helpers';
import {provideBackendCallTools} from '../util/progress';
import {BackendCalls, BackendConfig} from '@/types';

export default async function pushBackends(
backendConfigs: BackendConfig[], hash: string, rePull?: boolean): Promise<void> {
export async function pushBackends(
backendConfigs: BackendConfig[], hash: string, rePull?: boolean, clearCache?: boolean): Promise<void> {
const logger = getLogger();
logger.trace(`Pushing '${hash}' to backends`);

const pushingBackends = backendConfigs.filter(backend => backend.push);

if (pushingBackends.length === 0 && backendConfigs.length > 0) {
logger.info(`No backends with push: true found. Exiting`);
return;
}

const dirPromises = pushingBackends.map(backend => {
return helpers.createCleanCacheDir(backend);
});

const sharedCachePath = path.join(process.cwd(), 'node_modules', '.cache');

if (clearCache) {
await fsExtra.pathExists(sharedCachePath).then(() => {
logger.info(`Shared cache directory found at '${sharedCachePath}'. Removing`);
return fsExtra.remove(sharedCachePath);
}, (err) => {
if (err.code !== 'ENOENT') {
throw err;
}
});
}
const cacheDirs = await Promise.all(dirPromises);

const pushingPromises = [];
Expand Down
4 changes: 4 additions & 0 deletions src/lib/validateConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export default function validateConfig(config: PartialConfig): Promise<Config> {
config.dedupe = false;
}

if (config.clearSharedCache === undefined) {
config.clearSharedCache = false;
}

if (config.veendorVersion !== undefined) {
if (!semver.satisfies(global.VEENDOR_VERSION, config.veendorVersion)) {
return Promise.reject(new InvalidVeendorVersionError(config.veendorVersion));
Expand Down
17 changes: 17 additions & 0 deletions src/test/unit/install/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import install, {
PkgJsonNotFoundError
} from '@/lib/install';
import * as installHelpers from '@/lib/install/helpers';
import * as pushBackends from '@/lib/install/pushBackends';
import * as pkgJson from '@/lib/pkgjson';
import * as gitWrapper from '@/lib/commandWrappers/gitWrapper';
import * as npmWrapper from '@/lib/commandWrappers/npmWrapper';
Expand Down Expand Up @@ -1107,5 +1108,21 @@ describe('install', () => {
await install({config});
backendMock0.verify();
});

it('should pass clearSharedCache to `pushBackends(1)`', async () => {
config.clearSharedCache = false;
const mock = sandbox.mock(pushBackends);
mock.expects('pushBackends').withArgs(sinon.match.any, sinon.match.any, sinon.match.any, false);
await install({config});
mock.verify();
});

it('should pass clearSharedCache to `pushBackends(2)`', async () => {
config.clearSharedCache = true;
const mock = sandbox.mock(pushBackends);
mock.expects('pushBackends').withArgs(sinon.match.any, sinon.match.any, sinon.match.any, true);
await install({config});
mock.verify();
});
});
});
63 changes: 61 additions & 2 deletions src/test/unit/install/pushBackends.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import {afterEach, beforeEach, describe, it} from 'mocha';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import sinon from 'sinon';
import mockfs from 'mock-fs';
import fsExtra from 'fs-extra';

import pushBackends from '@/lib/install/pushBackends';
import {pushBackends} from '@/lib/install/pushBackends';
import * as errors from '@/lib/errors';

import * as helpers from '../helpers';
import {BackendConfig} from '@/types';
import {BackendConfig, PkgJson} from '@/types';

const assert = chai.assert;
chai.use(chaiAsPromised);

let PKGJSON: PkgJson;

describe('pushBackends', function () {
let sandbox: sinon.SinonSandbox;
let fakeBackends: BackendConfig[];
Expand All @@ -22,6 +26,17 @@ describe('pushBackends', function () {
fakeBackends = [helpers.fakeBackendConfig('fakeBackends[0]'), helpers.fakeBackendConfig('fakeBackends[1]')];
fakeBackends[0].backend.pull = () => Promise.reject(new errors.BundleNotFoundError);
fakeBackends[0].push = true;

PKGJSON = {
dependencies: {
foo: '2.2.8',
c: '2.2.9'
},
devDependencies: {
baz: '6.6.6'
}
};

});

afterEach(function () {
Expand All @@ -41,4 +56,48 @@ describe('pushBackends', function () {
return assert.isRejected(pushBackends(fakeBackends, fakeSha1), helpers.AnError);
});

it('should not clear node_modules/.cache, if `clearSharedCache` is set in config', async () => {
mockfs({
'package.json': JSON.stringify(PKGJSON),
'node_modules': {
'left-pad': {
'package.json': '{"a": "b"}',
},
'.cache': {
'some': 'garbage',
}
}
});

fakeBackends[0].backend.push = () => fsExtra
.stat('node_modules/.cache')
.then(
() => assert(true, 'cache is not cleared before push'),
() => assert(false, 'cache is cleared before push'),
);

await pushBackends(fakeBackends, fakeSha1);
});
it('should not clear node_modules/.cache, if parameter is not passed', async () => {
mockfs({
'package.json': JSON.stringify(PKGJSON),
'node_modules': {
'left-pad': {
'package.json': '{"a": "b"}',
},
'.cache': {
'some': 'garbage',
}
}
});

fakeBackends[0].backend.push = () => fsExtra
.stat('node_modules/.cache')
.then(
() => assert(false, 'cache is not cleared before push'),
() => assert(true, 'cache is cleared before push'),
);

await pushBackends(fakeBackends, fakeSha1, false, true);
});
});
7 changes: 6 additions & 1 deletion src/test/unit/validateConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('validateConfig', function () {

sandbox = sinon.sandbox.create();

const veendorVersion = require('../../package.json').version;
const veendorVersion = require('../../../package.json').version;
global.VEENDOR_VERSION = veendorVersion;
});

Expand Down Expand Up @@ -285,4 +285,9 @@ describe('validateConfig', function () {
const res = await validateConfig(config);
return assert.equal(res.dedupe, false);
});

it('should set default `clearSharedCache` value', async () => {
const res = await validateConfig(config);
return assert.equal(res.clearSharedCache, false);
});
});
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type Config = {
veendorVersion?: string,
npmVersion?: string,
dedupe?: boolean,
clearSharedCache?: boolean,
}

export type ConfigWithHistory = Config & {
Expand Down

0 comments on commit 51949a8

Please sign in to comment.