github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/bom/python/poetry.go (about) 1 /* 2 * Copyright (c) 2021 CodeNotary, Inc. All Rights Reserved. 3 * This software is released under GPL3. 4 * The full license information can be found under: 5 * https://www.gnu.org/licenses/gpl-3.0.en.html 6 * 7 */ 8 9 package python 10 11 import ( 12 "fmt" 13 "path/filepath" 14 15 "github.com/BurntSushi/toml" 16 "github.com/schollz/progressbar/v3" 17 18 "github.com/vchain-us/vcn/pkg/bom/artifact" 19 ) 20 21 // pythonArtifactFromPoetry implements Artifact interface 22 type pythonArtifactFromPoetry struct { 23 pythonArtifact 24 } 25 26 // poetry.lock TOML structure 27 type poetryFile struct { 28 Packages []pkg `toml:"package"` 29 } 30 type pkg struct { 31 Name string 32 Version string 33 } 34 35 // poetry.lock file contains list of all dependencies with hashes 36 func (a *pythonArtifactFromPoetry) ResolveDependencies(output artifact.OutputOptions) ([]artifact.Dependency, error) { 37 if a.Deps != nil { 38 return a.Deps, nil 39 } 40 var poetry poetryFile 41 _, err := toml.DecodeFile(filepath.Join(a.path, poetryFileName), &poetry) 42 if err != nil { 43 return nil, err 44 } 45 var bar *progressbar.ProgressBar 46 if output == artifact.Progress { 47 bar = progressbar.Default(int64(len(poetry.Packages))) 48 } 49 50 // init goroutine throttling - channels, start goroutines. 51 // We can be sure that there will be no more in-flight messages in channels than known modules 52 tasks := make(chan task, len(poetry.Packages)) 53 results := make(chan result, len(poetry.Packages)) 54 for i := 0; i < artifact.MaxGoroutines; i++ { 55 go poetryWorker(tasks, results, output, bar) 56 } 57 defer close(results) 58 defer close(tasks) // signal workers to stop 59 60 taskCount := 0 61 62 for _, pkg := range poetry.Packages { 63 tasks <- task{name: pkg.Name, version: pkg.Version} 64 taskCount++ 65 } 66 67 res := make([]artifact.Dependency, 0, len(poetry.Packages)) 68 for done := 0; taskCount == 0 || done < taskCount; done++ { 69 result := <-results 70 if result.err != nil { 71 close(tasks) // signal workers to stop 72 return nil, err 73 } 74 res = append(res, artifact.Dependency{ 75 Name: result.name, 76 Version: result.version, 77 Hash: result.hash, 78 HashType: result.hashType, 79 License: result.license}) 80 } 81 82 a.Deps = res 83 return res, nil 84 } 85 86 func poetryWorker(tasks <-chan task, results chan<- result, output artifact.OutputOptions, bar *progressbar.ProgressBar) { 87 for task := range tasks { 88 lic, hashType, hash, err := QueryPkgDetails(task.name, task.version) 89 if err != nil { 90 results <- result{err: err} 91 continue 92 } 93 94 results <- result{name: task.name, version: task.version, hash: hash, hashType: hashType, license: lic, err: nil} 95 switch output { 96 case artifact.Progress: 97 bar.Add(1) 98 case artifact.Debug: 99 fmt.Printf("%s@%s (%s)\n", task.name, task.version, hash) 100 } 101 } 102 }