github.com/tiagovtristao/plz@v13.4.0+incompatible/src/query/graph.go (about)

     1  package query
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"path"
     8  	"sync"
     9  
    10  	"github.com/thought-machine/please/src/build"
    11  	"github.com/thought-machine/please/src/core"
    12  )
    13  
    14  // Graph prints a representation of the build graph as JSON.
    15  func Graph(state *core.BuildState, targets []core.BuildLabel) {
    16  	log.Notice("Generating graph...")
    17  	g := makeJSONGraph(state, targets)
    18  	log.Notice("Marshalling...")
    19  	b, err := json.MarshalIndent(g, "", "    ")
    20  	if err != nil {
    21  		log.Fatalf("Failed to serialise JSON: %s\n", err)
    22  	}
    23  	log.Notice("Writing...")
    24  	fmt.Println(string(b))
    25  	log.Notice("Done")
    26  }
    27  
    28  // JSONGraph is an alternate representation of our build graph; will contain different information
    29  // to the structures in core (also those ones can't be printed as JSON directly).
    30  type JSONGraph struct {
    31  	Packages map[string]JSONPackage `json:"packages"`
    32  }
    33  
    34  // JSONPackage is an alternate representation of a build package
    35  type JSONPackage struct {
    36  	name    string
    37  	Targets map[string]JSONTarget `json:"targets"`
    38  }
    39  
    40  // JSONTarget is an alternate representation of a build target
    41  type JSONTarget struct {
    42  	Inputs   []string `json:"inputs,omitempty" note:"declared inputs of target"`
    43  	Outputs  []string `json:"outs,omitempty" note:"corresponds to outs in rule declaration"`
    44  	Sources  []string `json:"srcs,omitempty" note:"corresponds to srcs in rule declaration"`
    45  	Deps     []string `json:"deps,omitempty" note:"corresponds to deps in rule declaration"`
    46  	Data     []string `json:"data,omitempty" note:"corresponds to data in rule declaration"`
    47  	Labels   []string `json:"labels,omitempty" note:"corresponds to labels in rule declaration"`
    48  	Requires []string `json:"requires,omitempty" note:"corresponds to requires in rule declaration"`
    49  	Hash     string   `json:"hash" note:"partial hash of target, does not include source hash"`
    50  	Test     bool     `json:"test,omitempty" note:"true if target is a test"`
    51  	Binary   bool     `json:"binary,omitempty" note:"true if target is a binary"`
    52  	TestOnly bool     `json:"test_only,omitempty" note:"true if target should be restricted to test code"`
    53  }
    54  
    55  func makeJSONGraph(state *core.BuildState, targets []core.BuildLabel) *JSONGraph {
    56  	ret := JSONGraph{Packages: map[string]JSONPackage{}}
    57  	if len(targets) == 0 {
    58  		for pkg := range makeAllPackages(state) {
    59  			ret.Packages[pkg.name] = pkg
    60  		}
    61  	} else {
    62  		done := map[core.BuildLabel]struct{}{}
    63  		for _, target := range targets {
    64  			addJSONTarget(state, &ret, target, done)
    65  		}
    66  	}
    67  	return &ret
    68  }
    69  
    70  // makeAllPackages constructs all the JSONPackage objects for this graph in parallel.
    71  func makeAllPackages(state *core.BuildState) <-chan JSONPackage {
    72  	ch := make(chan JSONPackage, 100)
    73  	go func() {
    74  		packages := state.Graph.PackageMap()
    75  		var wg sync.WaitGroup
    76  		wg.Add(len(packages))
    77  		for _, pkg := range packages {
    78  			go func(pkg *core.Package) {
    79  				ch <- makeJSONPackage(state, pkg)
    80  				wg.Done()
    81  			}(pkg)
    82  		}
    83  		wg.Wait()
    84  		close(ch)
    85  	}()
    86  	return ch
    87  }
    88  
    89  func addJSONTarget(state *core.BuildState, ret *JSONGraph, label core.BuildLabel, done map[core.BuildLabel]struct{}) {
    90  	if _, present := done[label]; present {
    91  		return
    92  	}
    93  	done[label] = struct{}{}
    94  	if label.IsAllTargets() {
    95  		pkg := state.Graph.PackageOrDie(label)
    96  		for _, target := range pkg.AllTargets() {
    97  			addJSONTarget(state, ret, target.Label, done)
    98  		}
    99  		return
   100  	}
   101  	target := state.Graph.TargetOrDie(label)
   102  	if _, present := ret.Packages[label.PackageName]; present {
   103  		ret.Packages[label.PackageName].Targets[label.Name] = makeJSONTarget(state, target)
   104  	} else {
   105  		ret.Packages[label.PackageName] = JSONPackage{
   106  			Targets: map[string]JSONTarget{
   107  				label.Name: makeJSONTarget(state, target),
   108  			},
   109  		}
   110  	}
   111  	for _, dep := range target.Dependencies() {
   112  		addJSONTarget(state, ret, dep.Label, done)
   113  	}
   114  }
   115  
   116  func makeJSONPackage(state *core.BuildState, pkg *core.Package) JSONPackage {
   117  	targets := map[string]JSONTarget{}
   118  	for _, target := range pkg.AllTargets() {
   119  		targets[target.Label.Name] = makeJSONTarget(state, target)
   120  	}
   121  	return JSONPackage{name: pkg.Name, Targets: targets}
   122  }
   123  
   124  func makeJSONTarget(state *core.BuildState, target *core.BuildTarget) JSONTarget {
   125  	t := JSONTarget{
   126  		Sources: target.AllSourcePaths(state.Graph),
   127  	}
   128  	for in := range core.IterSources(state.Graph, target) {
   129  		t.Inputs = append(t.Inputs, in.Src)
   130  	}
   131  	for _, out := range target.Outputs() {
   132  		t.Outputs = append(t.Outputs, path.Join(target.Label.PackageName, out))
   133  	}
   134  	for _, dep := range target.Dependencies() {
   135  		t.Deps = append(t.Deps, dep.Label.String())
   136  	}
   137  	for data := range core.IterRuntimeFiles(state.Graph, target, false) {
   138  		t.Data = append(t.Data, data.Src)
   139  	}
   140  	t.Labels = target.Labels
   141  	t.Requires = target.Requires
   142  	rawHash := append(build.RuleHash(state, target, true, false), state.Hashes.Config...)
   143  	t.Hash = base64.RawStdEncoding.EncodeToString(rawHash)
   144  	t.Test = target.IsTest
   145  	t.Binary = target.IsBinary
   146  	t.TestOnly = target.TestOnly
   147  	return t
   148  }