Skip to content

Commit 548c104

Browse files
author
Farley
committed
Static and download caching, rebased and Windows working
1 parent 01c1fb1 commit 548c104

File tree

9 files changed

+661
-95
lines changed

9 files changed

+661
-95
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ admin.env
4242
#PYTHON STUFF
4343
*.py[co]
4444
__pycache__
45+
46+
#NODE STUFF
47+
package-lock.json

README.md

+26-11
Original file line numberDiff line numberDiff line change
@@ -140,25 +140,40 @@ custom:
140140
```
141141

142142
## Extra Config Options
143-
### extra pip arguments
144-
You can specify extra arguments to be passed to pip like this:
143+
### Caching
144+
You can enable two kinds of caching with this plugin which are currently both DISABLED by default. First, a download cache that will cache downloads that pip needs to compile the packages. And second, a what we call "static caching" which caches output of pip after compiling everything for your requirements file. Since generally requirements.txt files rarely change, you will often see large amounts of speed improvements when enabling the static cache feature. These caches will be shared between all your projects if no custom cacheLocation is specified (see below).
145+
146+
_**Please note:** This has replaced the previously recommended usage of "--cache-dir" in the pipCmdExtraArgs_
145147
```yaml
146148
custom:
147149
pythonRequirements:
148-
dockerizePip: true
149-
pipCmdExtraArgs:
150-
- --cache-dir
151-
- .requirements-cache
150+
useDownloadCache: true
151+
useStaticCache: true
152152
```
153+
_Additionally, In future versions of this plugin, both caching features will probably be enabled by default_
153154

154-
When using `--cache-dir` don't forget to also exclude it from the package.
155+
### Other caching options...
156+
There are two additional options related to caching. You can specify where in your system that this plugin caches with the `cacheLocation` option. By default it will figure out automatically where based on your username and your OS to store the cache via the [appdirectory](https://www.npmjs.com/package/appdirectory) module. Additionally, you can specify how many max static caches to store with `staticCacheMaxVersions`, as a simple attempt to limit disk space usage for caching. This is DISABLED (set to 0) by default. Example:
157+
```yaml
158+
custom:
159+
pythonRequirements:
160+
useStaticCache: true
161+
useDownloadCache: true
162+
cacheLocation: '/home/user/.my_cache_goes_here'
163+
staticCacheMaxVersions: 10
164+
165+
```
155166

167+
### Extra pip arguments
168+
You can specify extra arguments [supported by pip](https://pip.pypa.io/en/stable/reference/pip_install/#options) to be passed to pip like this:
156169
```yaml
157-
package:
158-
exclude:
159-
- .requirements-cache/**
170+
custom:
171+
pythonRequirements:
172+
pipCmdExtraArgs:
173+
- --compile
160174
```
161175

176+
162177
### Customize requirements file name
163178
[Some `pip` workflows involve using requirements files not named
164179
`requirements.txt`](https://www.kennethreitz.org/essays/a-better-pip-workflow).
@@ -350,4 +365,4 @@ zipinfo .serverless/xxx.zip
350365
improved pip chache support when using docker.
351366
* [@dee-me-tree-or-love](https://github.com/dee-me-tree-or-love) - the `slim` package option
352367
* [@alexjurkiewicz](https://github.com/alexjurkiewicz) - [docs about docker workflows](#native-code-dependencies-during-build)
353-
368+
* [@andrewfarley](https://github.com/andrewfarley) - Implemented download caching and static caching

index.js

+21-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const {
1212
const { injectAllRequirements } = require('./lib/inject');
1313
const { installAllRequirements } = require('./lib/pip');
1414
const { pipfileToRequirements } = require('./lib/pipenv');
15-
const { cleanup } = require('./lib/clean');
15+
const { cleanup, cleanupCache } = require('./lib/clean');
1616

1717
BbPromise.promisifyAll(fse);
1818

@@ -39,6 +39,10 @@ class ServerlessPythonRequirements {
3939
dockerSsh: false,
4040
dockerImage: null,
4141
dockerFile: null,
42+
useStaticCache: false,
43+
useDownloadCache: false,
44+
cacheLocation: false,
45+
staticCacheMaxVersions: 0,
4246
pipCmdExtraArgs: [],
4347
noDeploy: [
4448
'boto3',
@@ -115,6 +119,11 @@ class ServerlessPythonRequirements {
115119
install: {
116120
usage: 'install requirements manually',
117121
lifecycleEvents: ['install']
122+
},
123+
cleanCache: {
124+
usage:
125+
'Removes all items in the pip download/static cache (if present)',
126+
lifecycleEvents: ['cleanCache']
118127
}
119128
}
120129
}
@@ -128,6 +137,11 @@ class ServerlessPythonRequirements {
128137
return args[1].functionObj.runtime.startsWith('python');
129138
};
130139

140+
const clean = () =>
141+
BbPromise.bind(this)
142+
.then(cleanup)
143+
.then(removeVendorHelper);
144+
131145
const before = () => {
132146
if (!isFunctionRuntimePython(arguments)) {
133147
return;
@@ -155,13 +169,13 @@ class ServerlessPythonRequirements {
155169

156170
const invalidateCaches = () => {
157171
if (this.options.invalidateCaches) {
158-
return BbPromise.bind(this)
159-
.then(cleanup)
160-
.then(removeVendorHelper);
172+
return clean;
161173
}
162174
return BbPromise.resolve();
163175
};
164176

177+
const cleanCache = () => BbPromise.bind(this).then(cleanupCache);
178+
165179
this.hooks = {
166180
'after:package:cleanup': invalidateCaches,
167181
'before:package:createDeploymentArtifacts': before,
@@ -172,16 +186,9 @@ class ServerlessPythonRequirements {
172186
this.serverless.cli.generateCommandsHelp(['requirements']);
173187
return BbPromise.resolve();
174188
},
175-
'requirements:install:install': () =>
176-
BbPromise.bind(this)
177-
.then(pipfileToRequirements)
178-
.then(addVendorHelper)
179-
.then(installAllRequirements)
180-
.then(packRequirements),
181-
'requirements:clean:clean': () =>
182-
BbPromise.bind(this)
183-
.then(cleanup)
184-
.then(removeVendorHelper)
189+
'requirements:install:install': before,
190+
'requirements:clean:clean': clean,
191+
'requirements:cleanCache:cleanCache': cleanCache
185192
};
186193
}
187194
}

lib/clean.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const BbPromise = require('bluebird');
22
const fse = require('fs-extra');
33
const path = require('path');
4+
const glob = require('glob-all');
5+
const { getUserCachePath } = require('./shared');
46

57
BbPromise.promisifyAll(fse);
68

@@ -29,4 +31,32 @@ function cleanup() {
2931
);
3032
}
3133

32-
module.exports = { cleanup };
34+
/**
35+
* Clean up static cache, remove all items in there
36+
* @return {Promise}
37+
*/
38+
function cleanupCache() {
39+
const cacheLocation = getUserCachePath(this.options);
40+
if (fse.existsSync(cacheLocation)) {
41+
if (this.serverless) {
42+
this.serverless.cli.log(`Removing static caches at: ${cacheLocation}`);
43+
}
44+
45+
// Only remove cache folders that we added, just incase someone accidentally puts a weird
46+
// static cache location so we don't remove a bunch of personal stuff
47+
const promises = [];
48+
glob
49+
.sync([path.join(cacheLocation, '*slspyc/')], { mark: true, dot: false })
50+
.forEach(file => {
51+
promises.push(fse.removeAsync(file));
52+
});
53+
return BbPromise.all(promises);
54+
} else {
55+
if (this.serverless) {
56+
this.serverless.cli.log(`No static cache found`);
57+
}
58+
return BbPromise.resolve();
59+
}
60+
}
61+
62+
module.exports = { cleanup, cleanupCache };

lib/docker.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,11 @@ function findTestFile(servicePath) {
4949
if (fse.pathExistsSync(path.join(servicePath, 'serverless.json'))) {
5050
return 'serverless.json';
5151
}
52+
if (fse.pathExistsSync(path.join(servicePath, 'requirements.txt'))) {
53+
return 'requirements.txt';
54+
}
5255
throw new Error(
53-
'Unable to find serverless.yml or serverless.yaml or serverless.json for getBindPath()'
56+
'Unable to find serverless.{yml|yaml|json} or requirements.txt for getBindPath()'
5457
);
5558
}
5659

@@ -154,7 +157,7 @@ function getDockerUid(bindPath) {
154157
'stat',
155158
'-c',
156159
'%u',
157-
'/test/.serverless'
160+
'/bin/sh'
158161
];
159162
const ps = dockerCommand(options);
160163
return ps.stdout.trim();

0 commit comments

Comments
 (0)