@@ -6,17 +6,19 @@ const {spawnSync} = require('child_process');
66const { quote} = require ( 'shell-quote' ) ;
77const values = require ( 'lodash.values' ) ;
88const { 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 */
151169function 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
0 commit comments