@@ -11,9 +11,11 @@ const {
11
11
checkForAndDeleteMaxCacheVersions,
12
12
sha256Path,
13
13
getRequirementsWorkingPath,
14
- getUserCachePath
14
+ getUserCachePath,
15
+ sha256Hash,
15
16
} = require ( './shared' ) ;
16
17
18
+
17
19
/**
18
20
* Omit empty commands.
19
21
* In this context, a "command" is a list of arguments. An empty list or falsy value is ommitted.
@@ -469,23 +471,28 @@ function installRequirementsIfNeeded(
469
471
modulePath ,
470
472
options ,
471
473
funcOptions ,
472
- serverless
474
+ serverless ,
475
+ extraTargetPath
473
476
) {
474
477
// Our source requirements, under our service path, and our module path (if specified)
475
478
const fileName = path . join ( servicePath , modulePath , options . fileName ) ;
479
+ if ( ! extraTargetPath ) {
480
+ extraTargetPath = modulePath ;
481
+ }
476
482
477
483
// Skip requirements generation, if requirements file doesn't exist
478
484
if ( ! requirementsFileExists ( servicePath , options , fileName ) ) {
485
+ serverless . cli . log ( `Could not find requirements file at ${ fileName } ` )
479
486
return false ;
480
487
}
481
488
482
489
let requirementsTxtDirectory ;
483
490
// Copy our requirements to another path in .serverless (incase of individually packaged)
484
- if ( modulePath && modulePath !== '.' ) {
491
+ if ( extraTargetPath && extraTargetPath !== '.' ) {
485
492
requirementsTxtDirectory = path . join (
486
493
servicePath ,
487
494
'.serverless' ,
488
- modulePath
495
+ extraTargetPath
489
496
) ;
490
497
} else {
491
498
requirementsTxtDirectory = path . join ( servicePath , '.serverless' ) ;
@@ -579,6 +586,7 @@ function installAllRequirements() {
579
586
// Then if we're going to package functions individually...
580
587
if ( this . serverless . service . package . individually ) {
581
588
let doneModules = [ ] ;
589
+ let doneExtraRequirements = [ ] ;
582
590
this . targetFuncs
583
591
. filter ( func =>
584
592
( func . runtime || this . serverless . service . provider . runtime ) . match (
@@ -617,14 +625,61 @@ function installAllRequirements() {
617
625
if ( process . platform == 'win32' ) {
618
626
fse . copySync ( reqsInstalledAt , modulePath ) ;
619
627
} else {
620
- fse . symlink ( reqsInstalledAt , modulePath ) ;
628
+ fse . symlinkSync ( reqsInstalledAt , modulePath ) ;
621
629
}
622
630
} else {
623
- fse . rename ( reqsInstalledAt , modulePath ) ;
631
+ fse . renameSync ( reqsInstalledAt , modulePath ) ;
624
632
}
625
633
}
626
634
doneModules . push ( f . module ) ;
627
635
}
636
+ return f ;
637
+ } )
638
+ . map ( f => {
639
+ const extraRequirementsPath = get ( f , 'pythonRequirements.fileName' ) ;
640
+ this . serverless . cli . log ( `Found extra requirements ${ extraRequirementsPath } for ${ f . name } ` )
641
+ if ( extraRequirementsPath ) {
642
+ const extraRequirementsPathHash = sha256Hash ( extraRequirementsPath ) ;
643
+ // this.serverless.cli.log(`Computed path hash ${extraRequirementsPathHash}, doneExtraRequirements=${doneExtraRequirements}`)
644
+ // If we didn't already process a module (functions can re-use modules)
645
+ if ( ! doneExtraRequirements . includes ( extraRequirementsPath ) ) {
646
+ const reqsInstalledAt = installRequirementsIfNeeded (
647
+ this . servicePath ,
648
+ '' ,
649
+ Object . assign ( { } , this . options , f . pythonRequirements ) ,
650
+ f ,
651
+ this . serverless ,
652
+ extraRequirementsPathHash
653
+ ) ;
654
+ // this.serverless.cli.log(`Installed reqs to ${reqsInstalledAt}`)
655
+ // Add modulePath into .serverless for each module so it's easier for injecting and for users to see where reqs are
656
+ let extraRequirementsDirectoryPath = path . join (
657
+ this . servicePath ,
658
+ '.serverless' ,
659
+ extraRequirementsPathHash ,
660
+ 'requirements'
661
+ ) ;
662
+ // Only do if we didn't already do it
663
+ if (
664
+ reqsInstalledAt &&
665
+ ! fse . existsSync ( extraRequirementsDirectoryPath ) &&
666
+ reqsInstalledAt != extraRequirementsDirectoryPath
667
+ ) {
668
+ if ( this . options . useStaticCache ) {
669
+ // Windows can't symlink so we have to copy on Windows,
670
+ // it's not as fast, but at least it works
671
+ if ( process . platform == 'win32' ) {
672
+ fse . copySync ( reqsInstalledAt , extraRequirementsDirectoryPath ) ;
673
+ } else {
674
+ fse . symlinkSync ( reqsInstalledAt , extraRequirementsDirectoryPath ) ;
675
+ }
676
+ } else {
677
+ fse . renameSync ( reqsInstalledAt , extraRequirementsDirectoryPath ) ;
678
+ }
679
+ }
680
+ doneExtraRequirements . push ( extraRequirementsPath ) ;
681
+ }
682
+ }
628
683
} ) ;
629
684
} else {
630
685
const reqsInstalledAt = installRequirementsIfNeeded (
0 commit comments