github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/cmd/depsgen/config.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 ) 8 9 // knownLoads is a mapping between load symbols and their source. Those with an 10 // empty string are native and do not need a load statement. 11 var knownLoads = map[string]string{ 12 "bind": "", 13 "go_repository": "@bazel_gazelle//:deps.bzl", 14 "http_archive": "@bazel_tools//tools/build_defs/repo:http.bzl", 15 "http_file": "@bazel_tools//tools/build_defs/repo:http.bzl", 16 "local_repository": "", 17 "npm_install": "@build_bazel_rules_nodejs//:index.bzl", 18 "yarn_install": "@build_bazel_rules_nodejs//:index.bzl", 19 } 20 21 type Config struct { 22 // Out is the filename to write 23 Out string 24 // Name is a prefix for the generated deps macro function. 25 Name string 26 // Deps is the list of ProtoDependencyInfos 27 Deps []*ProtoDependencyInfo 28 } 29 30 // ProtoDependencyInfo represents the starlark ProtoDependencyInfo provider. 31 // The fields are a mashup of all possible fields from repository rules. 32 type ProtoDependencyInfo struct { 33 BuildFile string 34 BuildFileContent string 35 BuildFileProtoMode string 36 Deps []*ProtoDependencyInfo 37 Executable bool 38 Importpath string 39 Label string 40 Name string 41 Path string 42 RepositoryRule string 43 Sha256 string 44 StripPrefix string 45 SymlinkNodeModules bool 46 FrozenLockfile bool 47 Sum string 48 Urls []string 49 Version string 50 WorkspaceSnippet string 51 PackageJson string 52 PackageLockJson string 53 PatchArgs []string 54 Patches []string 55 YarnLock string 56 } 57 58 type LoadInfo struct { 59 Label string 60 Symbols []string 61 } 62 63 // fromJSON constructs a Config struct from the given filename that contains a 64 // JSON. 65 func fromJSON(filename string) (*Config, error) { 66 data, err := ioutil.ReadFile(filename) 67 if err != nil { 68 return nil, fmt.Errorf("read: %w", err) 69 } 70 71 var config Config 72 if err := json.Unmarshal(data, &config); err != nil { 73 return nil, fmt.Errorf("unmarshal: %w", err) 74 } 75 76 return &config, nil 77 } 78 79 // collectDeps accumulates the transitive dependencies. 80 func collectDeps(top []*ProtoDependencyInfo) (deps []*dependency) { 81 seen := make(map[string]bool) 82 83 var visit func(string, *ProtoDependencyInfo) 84 visit = func(parentName string, dep *ProtoDependencyInfo) { 85 if seen[dep.Name] { 86 return 87 } 88 seen[dep.Name] = true 89 for _, child := range dep.Deps { 90 visit(dep.Name, child) 91 } 92 deps = append(deps, &dependency{ 93 ParentName: parentName, 94 Dep: dep, 95 }) 96 } 97 98 for _, dep := range top { 99 if seen[dep.Name] { 100 continue 101 } 102 visit("<TOP>", dep) 103 } 104 105 return 106 } 107 108 // collectLoads accumulates the required load statements. 109 func collectLoads(deps []*dependency) []*LoadInfo { 110 required := make(map[string][]string) 111 112 for _, item := range deps { 113 symbol := item.Dep.RepositoryRule 114 source := knownLoads[symbol] 115 if source == "" { 116 continue 117 } 118 required[source] = append(required[source], symbol) 119 } 120 121 loads := make([]*LoadInfo, 0) 122 123 for source, symbols := range required { 124 load := &LoadInfo{Label: source} 125 loads = append(loads, load) 126 seen := make(map[string]bool) 127 for _, symbol := range symbols { 128 if seen[symbol] { 129 continue 130 } 131 seen[symbol] = true 132 load.Symbols = append(load.Symbols, symbol) 133 } 134 } 135 136 return loads 137 } 138 139 type dependency struct { 140 ParentName string 141 Dep *ProtoDependencyInfo 142 }