github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/buildtools/pip/pip.go (about) 1 package pip 2 3 import ( 4 "encoding/json" 5 "strings" 6 7 "github.com/apex/log" 8 9 "github.com/fossas/fossa-cli/exec" 10 "github.com/fossas/fossa-cli/files" 11 ) 12 13 // TODO: add a Python sidecar that evaluates `setup.py`. 14 15 type Pip struct { 16 Cmd string 17 PythonCmd string 18 } 19 20 type Requirement struct { 21 Name string `json:"name"` 22 Revision string `json:"version"` 23 Operator string 24 } 25 26 func (r Requirement) String() string { 27 return r.Name + r.Operator + r.Revision 28 } 29 30 func (p *Pip) Install(requirementsFilename string) error { 31 _, _, err := exec.Run(exec.Cmd{ 32 Name: p.Cmd, 33 Argv: []string{"install", "-r", requirementsFilename}, 34 }) 35 return err 36 } 37 38 func (p *Pip) List() ([]Requirement, error) { 39 stdout, _, err := exec.Run(exec.Cmd{ 40 Name: p.Cmd, 41 Argv: []string{"list", "--format=json"}, 42 }) 43 if err != nil { 44 return nil, err 45 } 46 var reqs []Requirement 47 err = json.Unmarshal([]byte(stdout), &reqs) 48 if err != nil { 49 return nil, err 50 } 51 return reqs, nil 52 } 53 54 func FromFile(filename string) ([]Requirement, error) { 55 contents, err := files.Read(filename) 56 if err != nil { 57 return nil, err 58 } 59 60 var reqs []Requirement 61 for _, line := range strings.Split(string(contents), "\n") { 62 // Remove all line comments and whitespace. 63 commentSplit := strings.Split(line, "#") 64 trimmed := strings.TrimSpace(commentSplit[0]) 65 if strings.HasPrefix(trimmed, "#") || strings.HasPrefix(trimmed, "-") || trimmed == "" { 66 continue 67 } 68 69 log.WithField("line", line).Debug("parsing line") 70 // See https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format 71 // and https://pip.pypa.io/en/stable/reference/pip_install/#pip-install-examples 72 matched := false 73 operators := []string{"===", "<=", ">=", "==", ">", "<", "!=", "~="} 74 for _, op := range operators { 75 sections := strings.Split(trimmed, op) 76 if len(sections) == 2 { 77 reqs = append(reqs, Requirement{ 78 Name: checkForExtra(sections[0]), 79 Revision: sections[1], 80 Operator: op, 81 }) 82 matched = true 83 break 84 } 85 } 86 if !matched { 87 reqs = append(reqs, Requirement{ 88 Name: checkForExtra(trimmed), 89 }) 90 } 91 } 92 93 return reqs, nil 94 } 95 96 // https://www.python.org/dev/peps/pep-0508/#extras 97 func checkForExtra(name string) string { 98 if strings.HasSuffix(name, "]") { 99 i := strings.Index(name, "[") 100 if i > 0 { 101 return name[:i] 102 } 103 } 104 return name 105 }