This repository has been archived by the owner on Sep 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.go
168 lines (151 loc) · 4.16 KB
/
build.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
)
func main() {
local := flag.Bool("l", false, "Build local packages")
help := flag.Bool("h", false, "Print help")
// FIXME This should come from the extension, and all of the extensions should match major revisions
rev := flag.String("r", "v3.5.1", "Tagged gotop version")
flag.Parse()
if *help {
fmt.Printf("USAGE: %s -r <tag> <extension-URL>...\n", os.Args[0])
flag.Usage()
fmt.Print(`
This program creates the files necessary to compile gotop with selected
extensions. You need:
1. The tagged version of gotop to compile (e.g., "v3.5.1")
2. One (or more) extensions to enable (e.g. "github.com/xxxserxxx/gotop-nvidia")
Example:
$ go run ./build.go -r v3.5.1 github.com/xxxserxxx/gotop-dummy
$ go build -o gotop ./gotop.go
$ sudo cp gotop /usr/local/bin
`)
os.Exit(0)
}
major := strings.Split(*rev, ".")[0]
var bs []byte
var replace string
if *local {
var err error
bs, err = ioutil.ReadFile(filepath.Join("..", "gotop", "cmd", "gotop", "main.go"))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
replace = fmt.Sprintf("replace github.com/xxxserxxx/gotop/%s => %s\n", major, "../gotop")
for _, ext := range flag.Args() {
bases := strings.Split(ext, "/")
base := bases[len(bases)-1]
replace = replace + fmt.Sprintf("replace %s => ../%s\n", ext, base)
}
} else {
//////////////////////////////////
// fetch gotop's main.go
resp, err := http.Get("https://raw.githubusercontent.com/xxxserxxx/gotop/" + *rev + "/cmd/gotop/main.go")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer resp.Body.Close()
bs, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
//////////////////////////////////
// add imports for the extensions
fset := token.NewFileSet() // positions are relative to fset
// Parse src but stop after processing the imports.
f, err := parser.ParseFile(fset, "gotop.go", string(bs), parser.ParseComments)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, k := range flag.Args() {
AddNamedImport(fset, f, "_", k)
}
//////////////////////////////////
// write out the program and go mod file
fout, err := os.Create("gotop.go")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer fout.Close()
err = printer.Fprint(fout, fset, f)
mods := `module gotop
require github.com/xxxserxxx/gotop/%s %s
%s
go 1.14
`
gm, err := os.Create("go.mod")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer gm.Close()
fmt.Fprintf(gm, mods, major, *rev, replace)
}
// Most of this copied from
// https://github.com/golang/tools/blob/master/go/ast/astutil/imports.go
// That had features not needed for this job; this is greatly trimmed down.
// A little copying is better than a little dependency.
func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) {
newImport := &ast.ImportSpec{
Name: &ast.Ident{Name: name},
Path: &ast.BasicLit{
Kind: token.STRING,
Value: strconv.Quote(path),
},
}
var (
lastImport = -1 // index in f.Decls of the file's final import decl
impDecl *ast.GenDecl // import decl containing the best match
)
for i, decl := range f.Decls {
gen, ok := decl.(*ast.GenDecl)
if ok && gen.Tok == token.IMPORT {
lastImport = i
impDecl = gen
break
}
}
impDecl = &ast.GenDecl{
Tok: token.IMPORT,
}
impDecl.TokPos = f.Decls[lastImport].End()
f.Decls = append(f.Decls, nil)
copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
f.Decls[lastImport+1] = impDecl
// Insert new import at insertAt.
insertAt := 0
impDecl.Specs = append(impDecl.Specs, nil)
copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
impDecl.Specs[insertAt] = newImport
pos := impDecl.Pos()
newImport.Name.NamePos = pos
newImport.Path.ValuePos = pos
newImport.EndPos = pos
// Clean up parens. impDecl contains at least one spec.
if len(impDecl.Specs) == 1 {
// Remove unneeded parens.
impDecl.Lparen = token.NoPos
} else if !impDecl.Lparen.IsValid() {
// impDecl needs parens added.
impDecl.Lparen = impDecl.Specs[0].Pos()
}
f.Imports = append(f.Imports, newImport)
}