forked from goplus/gop
/
update.go
131 lines (115 loc) · 3.05 KB
/
update.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
package main
import (
"bytes"
"go/ast"
"go/build"
"go/format"
"go/token"
"go/types"
"io/ioutil"
"path/filepath"
"github.com/visualfc/gotools/pkgwalk"
)
type ObjectInfo struct {
kind pkgwalk.ObjKind
ident *ast.Ident
obj types.Object
}
type InsertInfo struct {
file *ast.File
decl ast.Decl
pos token.Position
specImportName string
importPos token.Position
}
type UpdateInfo struct {
fileset *token.FileSet
updataPkg string
usesMap map[string]*ObjectInfo
exportsInfo *InsertInfo
initsInfo []*InsertInfo
}
func insertData(org []byte, data []byte, offset int) []byte {
var out []byte
out = append(out, org[:offset-1]...)
out = append(out, data...)
out = append(out, org[offset-1:]...)
return out
}
func (i *InsertInfo) UpdateFile(outpath string, data []byte, hasTypeExport bool) error {
file := filepath.Join(outpath, i.pos.Filename)
all, err := ioutil.ReadFile(file)
if err != nil {
return err
}
if hasTypeExport && i.specImportName == "spec" {
data = bytes.Replace(data, []byte("qlang."), []byte("spec."), -1)
}
out := insertData(all, data, i.pos.Offset)
if hasTypeExport && i.specImportName == "" {
spec := []byte("\n\nqlang \"qlang.io/spec\"\n")
out = insertData(out, spec, i.importPos.Offset+1)
}
// format
fout, err := format.Source(out)
if err != nil {
return err
}
ioutil.WriteFile(file, fout, 0777)
return nil
}
//check has update package
func CheckUpdateInfo(pkgname string, pkg string) (*UpdateInfo, error) {
updatePkgPath := flagUpdatePath + "/" + pkg
bp, err := build.Import(updatePkgPath, "", 0)
if err != nil {
return nil, err
}
CopyDir(bp.Dir, flagExportPath+"/"+pkg, false)
conf := pkgwalk.DefaultPkgConfig()
w := pkgwalk.NewPkgWalker(&build.Default)
pkgx, err := pkgwalk.ImportPackage(w, updatePkgPath, conf)
if err != nil {
return nil, err
}
list := pkgwalk.LookupObjList(w, pkgx, conf)
ui := &UpdateInfo{}
ui.fileset = w.FileSet
ui.updataPkg = bp.ImportPath
ui.usesMap = make(map[string]*ObjectInfo)
for ident, obj := range conf.Info.Uses {
if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == pkg {
kind, _ := pkgwalk.ParserObjectKind(ident, obj, conf)
ui.usesMap[ident.Name] = &ObjectInfo{kind, ident, obj}
}
}
fnMakeInsertInfo := func(ident *ast.Ident) *InsertInfo {
file, decl := w.FindDeclForPos(ident.Pos())
if decl == nil {
return nil
}
specImport := w.FindImportName(file, "qlang.io/spec")
endImportPos := w.FindImportEndPos(file)
pos := w.FileSet.Position(decl.End())
_, pos.Filename = filepath.Split(pos.Filename)
ipos := w.FileSet.Position(endImportPos)
_, ipos.Filename = filepath.Split(pos.Filename)
return &InsertInfo{file, decl, pos, specImport, ipos}
}
for _, obj := range list {
if obj != nil && obj.Obj != nil {
if obj.Obj.Name() == "Exports" {
v := fnMakeInsertInfo(obj.Ident)
if v != nil {
ui.exportsInfo = v
}
} else if obj.Obj.Name() == "init" {
v := fnMakeInsertInfo(obj.Ident)
if v != nil {
ui.initsInfo = append(ui.initsInfo, v)
}
}
}
}
return ui, nil
}