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  }