github.com/gernest/nezuko@v0.1.2/internal/modcmd/graph.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // z mod graph
     6  
     7  package modcmd
     8  
     9  import (
    10  	"bufio"
    11  	"os"
    12  	"sort"
    13  
    14  	"github.com/gernest/nezuko/internal/base"
    15  	"github.com/gernest/nezuko/internal/modload"
    16  	"github.com/gernest/nezuko/internal/module"
    17  	"github.com/gernest/nezuko/internal/par"
    18  )
    19  
    20  var cmdGraph = &base.Command{
    21  	UsageLine: "z mod graph",
    22  	Short:     "print module requirement graph",
    23  	Long: `
    24  Graph prints the module requirement graph (with replacements applied)
    25  in text form. Each line in the output has two space-separated fields: a module
    26  and one of its requirements. Each module is identified as a string of the form
    27  path@version, except for the main module, which has no @version suffix.
    28  	`,
    29  	Run: runGraph,
    30  }
    31  
    32  func runGraph(cmd *base.Command, args []string) {
    33  	if len(args) > 0 {
    34  		base.Fatalf("z mod graph: graph takes no arguments")
    35  	}
    36  	modload.LoadBuildList()
    37  
    38  	reqs := modload.MinReqs()
    39  	format := func(m module.Version) string {
    40  		if m.Version == "" {
    41  			return m.Path
    42  		}
    43  		return m.Path + "@" + m.Version
    44  	}
    45  
    46  	// Note: using par.Work only to manage work queue.
    47  	// No parallelism here, so no locking.
    48  	var out []string
    49  	var deps int // index in out where deps start
    50  	var work par.Work
    51  	work.Add(modload.Target)
    52  	work.Do(1, func(item interface{}) {
    53  		m := item.(module.Version)
    54  		list, _ := reqs.Required(m)
    55  		for _, r := range list {
    56  			work.Add(r)
    57  			out = append(out, format(m)+" "+format(r)+"\n")
    58  		}
    59  		if m == modload.Target {
    60  			deps = len(out)
    61  		}
    62  	})
    63  
    64  	sort.Slice(out[deps:], func(i, j int) bool {
    65  		return out[deps+i][0] < out[deps+j][0]
    66  	})
    67  
    68  	w := bufio.NewWriter(os.Stdout)
    69  	for _, line := range out {
    70  		w.WriteString(line)
    71  	}
    72  	w.Flush()
    73  }