github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/buildtools/paket/paket.go (about) 1 package paket 2 3 import ( 4 "strings" 5 6 "github.com/fossas/fossa-cli/errors" 7 "github.com/fossas/fossa-cli/files" 8 "github.com/fossas/fossa-cli/graph" 9 "github.com/fossas/fossa-cli/pkg" 10 ) 11 12 // Group defines a paket dependency group. 13 type Group struct { 14 Name string 15 Specs []Spec 16 } 17 18 // Spec defines a paket dependency and its attributes. 19 type Spec struct { 20 Remote string 21 Name string 22 Version string 23 Type pkg.Type 24 Dependencies []string 25 } 26 27 // DependencyGraph parses a "paket.lock" file to create a dependency graph. 28 func DependencyGraph(target string) (graph.Deps, error) { 29 groups, err := readLockfile(target) 30 if err != nil { 31 return graph.Deps{}, err 32 } 33 34 depGraph, err := graphFromGroups(groups) 35 if err != nil { 36 return graph.Deps{}, err 37 } 38 39 return depGraph, nil 40 } 41 42 func readLockfile(filename string) ([]Group, error) { 43 contents, err := files.Read(filename) 44 if err != nil { 45 return []Group{}, errors.Wrapf(err, "could not read lockfile: %s", filename) 46 } 47 48 groups := []Group{} 49 groupSplit := strings.Split(string(contents), "GROUP ") 50 for _, group := range groupSplit { 51 newSpec := Spec{} 52 newGroup := Group{} 53 packagetype := pkg.NuGet 54 remote := "" 55 56 sections := strings.Split(group, "\n") 57 for _, section := range sections { 58 switch section { 59 case "HTTP": 60 fallthrough 61 case "GIT": 62 fallthrough 63 case "GITHUB": 64 packagetype = pkg.Git 65 case "NUGET": 66 packagetype = pkg.NuGet 67 default: 68 if !strings.HasPrefix(section, " ") { 69 continue 70 } 71 72 if strings.Contains(section, "remote:") { 73 remote = strings.Split(section, "remote: ")[1] 74 continue 75 } 76 77 matches := strings.Split(section, " ") 78 if strings.HasPrefix(section, " ") { 79 if len(matches) >= 7 { 80 newSpec.Dependencies = append(newSpec.Dependencies, matches[6]) 81 } 82 continue 83 } 84 85 if newSpec.Name != "" { 86 newGroup.Specs = append(newGroup.Specs, newSpec) 87 } 88 89 if len(matches) >= 6 { 90 revision := findRevision(matches[5]) 91 newSpec = Spec{ 92 Remote: remote, 93 Type: packagetype, 94 Name: matches[4], 95 Version: revision, 96 } 97 } 98 } 99 } 100 101 if newSpec.Name != "" { 102 newGroup.Specs = append(newGroup.Specs, newSpec) 103 } 104 newGroup.Name = sections[0] 105 groups = append(groups, newGroup) 106 } 107 return groups, nil 108 } 109 110 func graphFromGroups(groups []Group) (graph.Deps, error) { 111 packageMap := make(map[string]pkg.Import) 112 for _, group := range groups { 113 for _, spec := range group.Specs { 114 name := spec.Name 115 if spec.Type == pkg.Git { 116 name = spec.Remote + "/" + spec.Name 117 } 118 119 packageMap[spec.Name] = pkg.Import{ 120 Target: spec.Name, 121 Resolved: pkg.ID{ 122 Type: spec.Type, 123 Name: name, 124 Revision: spec.Version, 125 Location: spec.Remote, 126 }, 127 } 128 } 129 } 130 131 packageGraph := graph.Deps{ 132 Direct: []pkg.Import{}, 133 Transitive: make(map[pkg.ID]pkg.Package), 134 } 135 for _, group := range groups { 136 for _, spec := range group.Specs { 137 packageImport := packageMap[spec.Name] 138 packageGraph.Direct = append(packageGraph.Direct, packageImport) 139 140 imports := []pkg.Import{} 141 for _, dep := range spec.Dependencies { 142 imports = append(imports, packageMap[dep]) 143 } 144 145 packageGraph.Transitive[packageImport.Resolved] = pkg.Package{ 146 ID: packageImport.Resolved, 147 Imports: imports, 148 } 149 } 150 } 151 return packageGraph, nil 152 } 153 154 func findRevision(line string) string { 155 revision := strings.TrimPrefix(line, "(") 156 revision = strings.TrimSuffix(revision, ")") 157 return revision 158 }