@@ -2,6 +2,7 @@ package supply
22
33import (
44 "bytes"
5+ "encoding/json"
56 "fmt"
67 "io"
78 "io/ioutil"
@@ -47,14 +48,14 @@ type Command interface {
4748}
4849
4950type Supplier struct {
50- PythonVersion string
51- Manifest Manifest
52- Installer Installer
53- Stager Stager
54- Command Command
55- Log * libbuildpack.Logger
56- Logfile * os.File
57- HasNltkData bool
51+ PythonVersion string
52+ Manifest Manifest
53+ Installer Installer
54+ Stager Stager
55+ Command Command
56+ Log * libbuildpack.Logger
57+ Logfile * os.File
58+ HasNltkData bool
5859 removeRequirementsText bool
5960}
6061
@@ -340,55 +341,103 @@ func (s *Supplier) InstallPipEnv() error {
340341 requirementstxtExists , err := libbuildpack .FileExists (filepath .Join (s .Stager .BuildDir (), "requirements.txt" ))
341342 if err != nil {
342343 return err
344+ } else if requirementstxtExists {
345+ return nil
343346 }
344347
345348 pipfileExists , err := libbuildpack .FileExists (filepath .Join (s .Stager .BuildDir (), "Pipfile" ))
346349 if err != nil {
347350 return err
351+ } else if ! pipfileExists {
352+ return nil
348353 }
349354
350- if pipfileExists && ! requirementstxtExists {
351- s .Log .Info ("Installing pipenv" )
352- if err := s .Installer .InstallOnlyVersion ("pipenv" , filepath .Join ("/tmp" , "pipenv" )); err != nil {
353- return err
355+ hasLockFile , err := libbuildpack .FileExists (filepath .Join (s .Stager .BuildDir (), "Pipfile.lock" ))
356+ if err != nil {
357+ return fmt .Errorf ("could not check Pipfile.lock existence: %v" , err )
358+ } else if hasLockFile {
359+ s .Log .Info ("Generating 'requirements.txt' from Pipfile.lock" )
360+ requirementsContents , err := pipfileToRequirements (filepath .Join (s .Stager .BuildDir (), "Pipfile.lock" ))
361+ if err != nil {
362+ return fmt .Errorf ("failed to write `requirement.txt` from Pipfile.lock: %s" , err .Error ())
354363 }
355364
356- if err := s .installFfi (); err != nil {
357- return err
358- }
365+ return s .writeTempRequirementsTxt (requirementsContents )
366+ }
359367
360- for _ , dep := range []string {"setuptools_scm" , "pytest-runner" , "parver" , "invoke" , "pipenv" , "wheel" } {
361- s .Log .Info ("Installing %s" , dep )
362- out := & bytes.Buffer {}
363- stderr := & bytes.Buffer {}
364- if err := s .Command .Execute (s .Stager .BuildDir (), out , stderr , "pip" , "install" , dep , "--exists-action=w" , "--no-index" , fmt .Sprintf ("--find-links=%s" , filepath .Join ("/tmp" , "pipenv" ))); err != nil {
365- return fmt .Errorf ("Failed to install %s: %v.\n Stdout: %v\n Stderr: %v" , dep , err , out , stderr )
366- }
368+ s .Log .Info ("Installing pipenv" )
369+ if err := s .Installer .InstallOnlyVersion ("pipenv" , filepath .Join ("/tmp" , "pipenv" )); err != nil {
370+ return err
371+ }
372+
373+ if err := s .installFfi (); err != nil {
374+ return err
375+ }
376+
377+ for _ , dep := range []string {"setuptools_scm" , "pytest-runner" , "parver" , "invoke" , "pipenv" , "wheel" } {
378+ s .Log .Info ("Installing %s" , dep )
379+ out := & bytes.Buffer {}
380+ stderr := & bytes.Buffer {}
381+ if err := s .Command .Execute (s .Stager .BuildDir (), out , stderr , "pip" , "install" , dep , "--exists-action=w" , "--no-index" , fmt .Sprintf ("--find-links=%s" , filepath .Join ("/tmp" , "pipenv" ))); err != nil {
382+ return fmt .Errorf ("Failed to install %s: %v.\n Stdout: %v\n Stderr: %v" , dep , err , out , stderr )
367383 }
368- s . Stager . LinkDirectoryInDepDir ( filepath . Join ( s . Stager . DepDir (), "python" , "bin" ), "bin" )
369- s . Log . Info ( "Generating 'requirements.txt' with pipenv " )
384+ }
385+ s . Stager . LinkDirectoryInDepDir ( filepath . Join ( s . Stager . DepDir (), "python" , "bin" ), "bin " )
370386
371- cmd := exec .Command ("pipenv" , "lock" , "--requirements" )
372- cmd .Dir = s .Stager .BuildDir ()
373- cmd .Env = append (os .Environ (), "VIRTUALENV_NEVER_DOWNLOAD=true" )
374- output , err := s .Command .RunWithOutput (cmd )
375- outputString := string (output )
387+ s .Log .Info ("Generating 'requirements.txt' with pipenv" )
388+ cmd := exec .Command ("pipenv" , "lock" , "--requirements" )
389+ cmd .Dir = s .Stager .BuildDir ()
390+ cmd .Env = append (os .Environ (), "VIRTUALENV_NEVER_DOWNLOAD=true" )
391+ output , err := s .Command .RunWithOutput (cmd )
392+ if err != nil {
393+ return err
394+ }
395+ outputString := string (output )
376396
377- if err != nil {
378- return err
397+ // Remove output due to virtualenv
398+ if strings .HasPrefix (outputString , "Using " ) {
399+ reqs := strings .SplitN (outputString , "\n " , 2 )
400+ if len (reqs ) > 0 {
401+ outputString = reqs [1 ]
379402 }
403+ }
380404
381- // Remove output due to virtualenv
382- if strings .HasPrefix (outputString , "Using " ) {
383- reqs := strings .SplitN (outputString , "\n " , 2 )
384- if len (reqs ) > 0 {
385- outputString = reqs [1 ]
405+ return s .writeTempRequirementsTxt (outputString )
406+ }
407+
408+ func pipfileToRequirements (lockFilePath string ) (string , error ) {
409+ var lockFile struct {
410+ Meta struct {
411+ Sources []struct {
412+ URL string
386413 }
414+ } `json:"_meta"`
415+ Default map [string ]struct {
416+ Version string
387417 }
418+ }
388419
389- return s .writeTempRequirementsTxt (outputString )
420+ lockContents , err := ioutil .ReadFile (lockFilePath )
421+ if err != nil {
422+ return "" , err
390423 }
391- return nil
424+
425+ err = json .Unmarshal (lockContents , & lockFile )
426+ if err != nil {
427+ return "" , err
428+ }
429+
430+ buf := & bytes.Buffer {}
431+
432+ for _ , source := range lockFile .Meta .Sources {
433+ fmt .Fprintf (buf , "-i %s\n " , source .URL )
434+ }
435+
436+ for pkg , obj := range lockFile .Default {
437+ fmt .Fprintf (buf , "%s%s\n " , pkg , obj .Version )
438+ }
439+
440+ return buf .String (), nil
392441}
393442
394443func (s * Supplier ) HandlePylibmc () error {
0 commit comments