-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
119 lines (98 loc) · 2.18 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main
import (
"bytes"
"flag"
"fmt"
"github.com/goccy/go-graphviz"
"github.com/goccy/go-graphviz/cgraph"
"log"
"os/exec"
"path"
"sort"
"strings"
)
func main() {
flag.Parse()
file := flag.Arg(0)
cmd := exec.Command("nix-instantiate", file)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
log.Println(err.Error())
log.Printf("%s", stderr.String())
return
}
drvs := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
nargs := []string{"--query", "--graph"}
cmd2 := exec.Command("nix-store", append(nargs, drvs...)...)
var stdout2 bytes.Buffer
var stderr2 bytes.Buffer
cmd2.Stdout = &stdout2
cmd2.Stderr = &stderr2
err = cmd2.Run()
if err != nil {
log.Println(err.Error())
log.Printf("%s", stderr2.String())
return
}
graph, err := graphviz.ParseBytes(stdout2.Bytes())
if err != nil {
log.Println(err.Error())
return
}
m, err := deps(graph, drvs)
if err != nil {
log.Println(err.Error())
return
}
fmt.Println("{")
for drv, deps := range m {
fmt.Printf(" \"%s\" = [\n", drv)
for _, drv := range deps {
fmt.Printf(" \"%s\"\n", drv)
}
fmt.Println(" ];")
}
fmt.Println("}")
}
func deps(graph *cgraph.Graph, allowed []string) (map[string][]string, error) {
m := make(map[string][]string)
for _, drv := range allowed {
node, err := graph.Node(path.Base(drv))
if err != nil {
return nil, err
}
m[drv] = []string{}
for k, v := range depsOf(graph, node, allowed, path.Dir(drv), map[string]bool{}) {
if v {
m[drv] = append(m[drv], k)
}
}
sort.Strings(m[drv])
}
return m, nil
}
func depsOf(graph *cgraph.Graph, node *cgraph.Node, allowed []string, store string, deps map[string]bool) map[string]bool {
for e := graph.FirstIn(node); e != nil; e = graph.NextIn(e) {
drv := path.Join(store, e.Node().Name())
if _, ok := deps[drv]; ok {
continue
}
deps[drv] = contains(drv, allowed)
for drv, v := range depsOf(graph, e.Node(), allowed, store, deps) {
deps[drv] = v
}
}
return deps
}
func contains(val string, list []string) bool {
for _, v := range list {
if v == val {
return true
}
}
return false
}