Skip to content

Commit cbd9ea3

Browse files
committed
Initial proof-of-concept to have a static cache
1 parent a25ba8f commit cbd9ea3

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

lib/pip.js

+59-5
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@ const {spawnSync} = require('child_process');
66
const {quote} = require('shell-quote');
77
const values = require('lodash.values');
88
const {buildImage, getBindPath} = require('./docker');
9+
const md5File = require('md5-file')
10+
911

1012
/**
11-
* Install requirements described in requirementsPath to targetPath
13+
* Just generate the requirements file in the .serverless folder
1214
* @param {string} requirementsPath
1315
* @param {string} targetFolder
1416
* @param {Object} serverless
1517
* @param {string} servicePath
1618
* @param {Object} options
1719
* @return {undefined}
1820
*/
19-
function installRequirements(requirementsPath, targetFolder, serverless, servicePath, options) {
21+
function installRequirementsFile(requirementsPath, targetFolder, serverless, servicePath, options) {
2022
// Create target folder if it does not exist
2123
const targetRequirementsFolder = path.join(targetFolder, 'requirements');
2224
fse.ensureDirSync(targetRequirementsFolder);
@@ -27,8 +29,24 @@ function installRequirements(requirementsPath, targetFolder, serverless, service
2729
} else {
2830
generateRequirementsFile(requirementsPath, dotSlsReqs, options);
2931
}
32+
33+
serverless.cli.log(`Generated requirements of ${requirementsPath} in ${targetFolder}...`);
34+
}
3035

31-
serverless.cli.log(`Installing requirements of ${requirementsPath} in ${targetFolder}...`);
36+
37+
/**
38+
* Install requirements described in requirementsPath to targetPath
39+
* @param {string} targetFolder
40+
* @param {Object} serverless
41+
* @param {string} servicePath
42+
* @param {Object} options
43+
* @return {undefined}
44+
*/
45+
function installRequirements(targetFolder, serverless, servicePath, options) {
46+
const targetRequirementsFolder = path.join(targetFolder, 'requirements');
47+
const dotSlsReqs = path.join(targetFolder, 'requirements.txt');
48+
49+
serverless.cli.log(`Installing requirements from ${dotSlsReqs} ...`);
3250

3351
let cmd;
3452
let cmdOptions;
@@ -149,7 +167,13 @@ function generateRequirementsFile(source, target, options) {
149167
* @return {undefined}
150168
*/
151169
function installAllRequirements() {
170+
// Added a static cache folder and try to read the cached sum
171+
const requirementsStaticCacheFolder = path.join(this.servicePath, '.serverless-python-requirements-static-cache');
172+
fse.ensureDirSync(requirementsStaticCacheFolder);
173+
try { cached_sum = fse.readFileSync(path.join(requirementsStaticCacheFolder, '.requirements.txt.md5')); } catch (exception) { cached_sum = false; }
174+
152175
fse.ensureDirSync(path.join(this.servicePath, '.serverless'));
176+
153177
if (this.serverless.service.package.individually) {
154178
let doneModules = [];
155179
values(this.serverless.service.functions)
@@ -158,24 +182,54 @@ function installAllRequirements() {
158182
set(f, ['module'], '.');
159183
}
160184
if (!doneModules.includes(f.module)) {
161-
installRequirements(
185+
installRequirementsFile(
162186
path.join(f.module, this.options.fileName),
163187
path.join('.serverless', f.module),
164188
this.serverless,
165189
this.servicePath,
166190
this.options
167191
);
192+
if ( cached_sum && cached_sum == md5File.sync(path.join(this.servicePath, '.serverless/requirements.txt')) ) {
193+
this.serverless.cli.log(`Using static cache...`);
194+
fse.copySync(requirementsStaticCacheFolder, path.join('.serverless', f.module, 'requirements/'))
195+
fse.removeSync(path.join('.serverless', f.module, 'requirements/.requirements.txt.md5'))
196+
} else {
197+
installRequirements(
198+
path.join('.serverless', f.module),
199+
this.serverless,
200+
this.servicePath,
201+
this.options
202+
);
203+
}
204+
// Write our MD5 hash of our requirements.txt to a file to detect if we need to re-run installRequirements
205+
fse.writeFileSync(path.join(requirementsStaticCacheFolder, '.requirements.txt.md5'), md5File.sync(path.join(this.servicePath, '.serverless/requirements.txt')));
168206
doneModules.push(f.module);
169207
}
170208
});
171209
} else {
172-
installRequirements(
210+
installRequirementsFile(
173211
this.options.fileName,
174212
'.serverless',
175213
this.serverless,
176214
this.servicePath,
177215
this.options
178216
);
217+
if ( cached_sum && cached_sum == md5File.sync(path.join(this.servicePath, '.serverless/requirements.txt')) ) {
218+
this.serverless.cli.log(`Using static cache...`);
219+
fse.copySync(requirementsStaticCacheFolder, '.serverless/requirements/')
220+
fse.removeSync('.serverless/requirements/.requirements.txt.md5')
221+
} else {
222+
installRequirements(
223+
'.serverless',
224+
this.serverless,
225+
this.servicePath,
226+
this.options
227+
);
228+
}
229+
// Backup our static files to cache...
230+
fse.copySync('.serverless/requirements', requirementsStaticCacheFolder)
231+
// Write our MD5 hash of our requirements.txt to a file to detect if we need to re-run installRequirements
232+
fse.writeFileSync(path.join(requirementsStaticCacheFolder, '.requirements.txt.md5'), md5File.sync(path.join(this.servicePath, '.serverless/requirements.txt')));
179233
}
180234
};
181235

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"glob-all": "^3.1.0",
5252
"is-wsl": "^1.1.0",
5353
"jszip": "^2.5.0",
54+
"md5-file": "^3.2.3",
5455
"lodash.get": "^4.4.2",
5556
"lodash.set": "^4.3.2",
5657
"lodash.values": "^4.3.0",

0 commit comments

Comments
 (0)