Commit c9762c3f authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 9081392f
...@@ -23,6 +23,8 @@ gotrace list package TODO ...@@ -23,6 +23,8 @@ gotrace list package TODO
XXX tracepoints this package defines XXX tracepoints this package defines
XXX tracepoints this package imports XXX tracepoints this package imports
TODO remove Fatal everywhere except main
*/ */
package main package main
...@@ -32,6 +34,7 @@ import ( ...@@ -32,6 +34,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
"go/build"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
...@@ -394,7 +397,6 @@ func checkCanWrite(path string) error { ...@@ -394,7 +397,6 @@ func checkCanWrite(path string) error {
} }
// writeFile writes data to a file at path after checking it is safe to write there // writeFile writes data to a file at path after checking it is safe to write there
// TODO check if content is the same and do not write then ? (XXX name -> updateFile ?)
func writeFile(path string, data []byte) error { func writeFile(path string, data []byte) error {
err := checkCanWrite(path) err := checkCanWrite(path)
if err != nil { if err != nil {
...@@ -404,6 +406,35 @@ func writeFile(path string, data []byte) error { ...@@ -404,6 +406,35 @@ func writeFile(path string, data []byte) error {
return ioutil.WriteFile(path, data, 0666) return ioutil.WriteFile(path, data, 0666)
} }
// removeFile removes file at path after checking it is safe to write to that file
func removeFile(path string) error {
err := checkCanWrite(path)
if err != nil {
return err
}
return os.Remove(path)
}
/*
// writer is interface for gotrace output operations
// made for testing
type writer interface {
writeFile(path string, data []byte) error
removeFile(path string) error
}
type fsWriter struct{}
func (fsWriter) writeFile(path string, data []byte) error {
return writeFile(path, data)
}
func (fsWriter) removeFile(path string) error {
return removeFile(path)
}
*/
type Buffer struct { type Buffer struct {
bytes.Buffer bytes.Buffer
} }
...@@ -437,13 +468,14 @@ func (s StrSet) Itemv() []string { ...@@ -437,13 +468,14 @@ func (s StrSet) Itemv() []string {
} }
// tracegen generates code according to tracing directives in a package @ pkgpath // tracegen generates code according to tracing directives in a package @ pkgpath
func tracegen(pkgpath string) error { func tracegen(pkgpath string, buildCtx *build.Context, w writer) error {
// XXX typechecking is much slower than parsing + we don't need to // XXX typechecking is much slower than parsing + we don't need to
// load anything except the package in question // load anything except the package in question
// TODO -> use just AST parsing for loading? // TODO -> use just AST parsing for loading?
conf := loader.Config{ conf := loader.Config{
ParserMode: parser.ParseComments, ParserMode: parser.ParseComments,
TypeCheckFuncBodies: func(path string) bool { return false }, TypeCheckFuncBodies: func(path string) bool { return false },
Build: buildCtx,
} }
conf.Import(pkgpath) conf.Import(pkgpath)
...@@ -532,31 +564,27 @@ func tracegen(pkgpath string) error { ...@@ -532,31 +564,27 @@ func tracegen(pkgpath string) error {
} }
prologue.emit(")") prologue.emit(")")
// write output to trace.go // write output to ztrace.go
fulltext := append(prologue.Bytes(), text.Bytes()...) fulltext := append(prologue.Bytes(), text.Bytes()...)
err = writeFile(filepath.Join(pkgdir, "trace.go"), fulltext) err = w.writeFile(filepath.Join(pkgdir, "ztrace.go"), fulltext)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// write empty trace.s so go:linkname works // write empty ztrace.s so go:linkname works, if there are trace imports
text.Reset() ztrace_s := filepath.Join(pkgdir, "ztrace.s")
text.WriteString(magic) if len(pkg.Importv) == 0 {
text.emit("// empty .s so `go build` does not use -complete for go:linkname to work") err = w.removeFile(ztrace_s)
} else {
text.Reset()
text.WriteString(magic)
text.emit("// empty .s so `go build` does not use -complete for go:linkname to work")
trace_s := filepath.Join(pkgdir, "trace.s") err = w.writeFile(ztrace_s, text.Bytes())
err = writeFile(trace_s, text.Bytes())
if err != nil {
log.Fatal(err)
} }
// trace.s is needed only if there are trace imports if err != nil {
// (but still we do want to verify ^^^ we can write to it) log.Fatal(err)
if len(pkg.Importv) == 0 {
err = os.Remove(trace_s)
if err != nil {
log.Fatal(err)
}
} }
return nil // XXX return nil // XXX
...@@ -582,7 +610,7 @@ TODO ... ...@@ -582,7 +610,7 @@ TODO ...
} }
pkgpath := argv[0] pkgpath := argv[0]
err := tracegen(pkgpath) err := tracegen(pkgpath, build.Default)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
......
package main
import (
"go/build"
"testing"
)
/*
// memWriter saves in memory filesystem modifications gotrace wanted to made
type memWriter struct {
wrote map[string]string // path -> data
removed StrSet
}
func (mw *memWriter) writeFile(path string, data []byte) error {
mw.wrote[path] = string(data)
return nil
}
func (mw *memWriter) removeFile(path) error {
mw.removed.Add(path)
return nil
}
*/
func xglob(t *testing.T, pattern string) []string {
t.Helper()
matchv, err := filepath.Glob(pattern)
if err != nil {
t.Fatal(err)
}
return matchv
}
type TreePrepareMode int
const (
TreePrepareGolden TreePrepareMode = iota // prepare golden tree - how `gotrace gen` result should look like
TreePrepareWork // prepare work tree - inital state for `gotrace gen` to run
)
// prepareTestTree copies files from src to dst recursively processing *.ok and *.rm depending on mode
// dst should not initially exist
func prepareTestTree(src, dst string, mode prepareMode) error {
err := os.MkdirAll(dst, 0777)
if err != nil {
return err
}
filepath.Walk(src, func(srcpath string, info os.FileInfo, err error) error {
dstpath := dst + "/" + strings.TrimPrefix(srcpath, src)
if info.IsDir() {
err := os.Mkdir(dstpath, 0777)
if err != nil {
return err
}
return cpR(srcpath, dstpath)
}
var isOk, isRm bool
if strings.HasSuffix(srcpath, ".ok") {
isOk = true
dstpath = strings.TrimSuffix(dstpath, ".ok")
}
if strings.hasSuffix(srcpath, ".rm") {
isRm = true
dstpath = strings.TrimSuffix(dstpath, ".rm")
}
data, err := ioutil.ReadFile(srcpath)
if err != nil {
return err
}
switch mode {
case prepareGolden:
// no removed files in golden tree
if isRm {
return nil
}
case prepareWork:
// no ok files initially in work tree
if isOk {
return nil
}
// files to remove - prepopulate with magic
if isRm {
data = []byte(magic)
}
}
err = ioutil.WriteFile(dstpath, data, info.Mode())
if err != nil {
return err
}
return nil
})
}
xprepareTree(t *testing.T, src, dst string, mode prepareMode) {
err := prepareTestTree(src, dst)
exc.Raiseif(err)
}
func TestGoTraceGen(t *testing.T) {
tmp, err := ioutil.TempDir("", "t-gotrace")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
good := tmp + "/good"
work := tmp + "/work"
xprepareTree("testdata", good, TreePrepareGolden)
xprepareTree("testdata", work, TreePrepareWork)
// test build context with GOPATH set to work tree
var tBuildCtx = build.Context{
GOARCH: "amd64",
GOOS: "linux",
GOROOT: runtime.GOROOT(),
GOPATH: work,
Compiler: runtime.Compiler(),
}
// XXX autodetect (go list ?)
testv := []string{"a/pkg1", "b/pkg2"}
for _, tpkg := range testv {
err = tracegen(tpkg, tBuildCtx)
if err != nil {
t.Errorf("%v: %v", tpkg, err)
}
err := diffR(good+"/"+tpkg, work+"/"+tpkg)
if err != nil {
t.Errorf("%v: %v", tpkg, err)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment