Commit 21423963 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 32038ac4
...@@ -26,14 +26,18 @@ XXX tracepoints this package imports ...@@ -26,14 +26,18 @@ XXX tracepoints this package imports
package main package main
import ( import (
"bufio"
"bytes"
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
"io/ioutil"
"log" "log"
"os" "os"
"path/filepath"
"sort" "sort"
"strings" "strings"
"text/template" "text/template"
...@@ -68,7 +72,7 @@ type traceImport struct { ...@@ -68,7 +72,7 @@ type traceImport struct {
// Package represents tracing-related information about a package // Package represents tracing-related information about a package
type Package struct { type Package struct {
PkgPath string Pkgi *loader.PackageInfo
Eventv []*traceEvent // trace events this package defines Eventv []*traceEvent // trace events this package defines
Importv []*traceImport // packages this package trace imports Importv []*traceImport // packages this package trace imports
} }
...@@ -173,7 +177,7 @@ func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package { ...@@ -173,7 +177,7 @@ func packageTrace(lprog *loader.Program, pkgi *loader.PackageInfo) *Package {
sort.Sort(byEventName(eventv)) sort.Sort(byEventName(eventv))
sort.Sort(byPkgPath(importv)) sort.Sort(byPkgPath(importv))
return &Package{PkgPath: pkgi.Pkg.Path(), Eventv: eventv, Importv: importv} return &Package{Pkgi: pkgi, Eventv: eventv, Importv: importv}
} }
// ---------------------------------------- // ----------------------------------------
...@@ -260,12 +264,43 @@ func {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.TypedArgv} ...@@ -260,12 +264,43 @@ func {{.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.TypedArgv}
// XXX go123 in magic // XXX go123 in magic
const magic = "// Code generated by lab.nexedi.com/kirr/go123/tracing/cmd/gotrace; DO NOT EDIT.\n" const magic = "// Code generated by lab.nexedi.com/kirr/go123/tracing/cmd/gotrace; DO NOT EDIT.\n"
struct Buffer { // checkCanWrite check whether it is safe to write at path
// it is safe to write when either
// - the file does not exist, or
// - it exits but was previously generated by us
func checkCanWrite(path string) error {
f, err := os.Open(path)
if e, ok := err.(*os.PathError); ok && os.IsNotExist(e.Err) {
return nil
}
defer f.Close()
bf := bufio.NewReader(f)
headline, err := bf.ReadString('\n')
if err != nil || headline != magic {
return fmt.Errorf("refusing to make output: %v exists but was not generated by gotrace", path)
}
return nil
}
// writeFile writes data to a file at path after checking it is safe to write there
func writeFile(path string, data []byte) error {
err := checkCanWrite(path)
if err != nil {
return err
}
return ioutil.WriteFile(path, data, 0666)
}
type Buffer struct {
bytes.Buffer bytes.Buffer
} }
func (b *Buffer) emit(format string, argv ...interface{}) { func (b *Buffer) emit(format string, argv ...interface{}) {
fmt.Fprintf(b, format + "\n", ...argv) fmt.Fprintf(b, format + "\n", argv...)
} }
// tracegen generates code according to tracing directives in a package @ pkgpath // tracegen generates code according to tracing directives in a package @ pkgpath
...@@ -285,22 +320,34 @@ func tracegen(pkgpath string) error { ...@@ -285,22 +320,34 @@ func tracegen(pkgpath string) error {
log.Fatal(err) log.Fatal(err)
} }
// tracing info for this specified package
pkgi := lprog.InitialPackages()[0] pkgi := lprog.InitialPackages()[0]
// determine package directory
if len(pkgi.Files) == 0 {
log.Fatalf("package %s is empty", pkgi.Pkg.Path)
}
pkgdir := filepath.Dir(lprog.Fset.File(pkgi.Files[0].Pos()).Name())
//println("pkgpath", pkgpath)
//println("pkgdir", pkgdir)
//return nil
// tracing info for this specified package
pkg := packageTrace(lprog, pkgi) pkg := packageTrace(lprog, pkgi)
buf := &bytes.Buffer{} buf := &Buffer{}
// prologue // prologue
buf.Write(magic) buf.WriteString(magic)
buf.emit("\npackage %v", pkg.Pkg.Name) buf.emit("\npackage %v", pkg.Pkgi.Pkg.Name)
buf.emit("\nimport (") buf.emit("\nimport (")
buf.emit("\t\tlab.nexedi.com/kirr/neo/go/xcommon/tracing") buf.emit("\t\tlab.nexedi.com/kirr/neo/go/xcommon/tracing")
// TODO import all packages for used types
buf.emit(")")
// code for trace:event definitions
// generate code for trace:event definitions
for _, event := range pkg.Eventv { for _, event := range pkg.Eventv {
err = traceEventCodeTmpl.Execute(os.Stdout, event) err = traceEventCodeTmpl.Execute(buf, event)
if err != nil { if err != nil {
panic(err) // XXX panic(err) // XXX
} }
...@@ -308,10 +355,10 @@ func tracegen(pkgpath string) error { ...@@ -308,10 +355,10 @@ func tracegen(pkgpath string) error {
// TODO export hash // TODO export hash
// generate code for trace:import imports // code for trace:import imports
fmt.Println() buf.emit("")
for _, timport := range pkg.Importv { for _, timport := range pkg.Importv {
fmt.Printf("// traceimport: %v\n", timport.PkgPath) buf.emit("// traceimport: %v", timport.PkgPath)
pkgi = lprog.Package(timport.PkgPath) pkgi = lprog.Package(timport.PkgPath)
if pkgi == nil { if pkgi == nil {
...@@ -322,7 +369,7 @@ func tracegen(pkgpath string) error { ...@@ -322,7 +369,7 @@ func tracegen(pkgpath string) error {
pkg = packageTrace(lprog, pkgi) pkg = packageTrace(lprog, pkgi)
for _, event := range pkg.Eventv { for _, event := range pkg.Eventv {
err = traceEventImportTmpl.Execute(os.Stdout, event) err = traceEventImportTmpl.Execute(buf, event)
if err != nil { if err != nil {
panic(err) // XXX panic(err) // XXX
} }
...@@ -331,12 +378,30 @@ func tracegen(pkgpath string) error { ...@@ -331,12 +378,30 @@ func tracegen(pkgpath string) error {
// TODO check export hash // TODO check export hash
// TODO trace.s with "// empty .s so `go build` does not use -complete for go:linkname to work"
// before flushing check we can write to trace.{go,s}
err = writeFile(filepath.Join(pkgdir, "trace.go"), buf.Bytes())
if err != nil {
log.Fatal(err)
}
// write trace.s so go:linkname works
buf.Reset()
buf.WriteString(magic)
buf.emit("// empty .s so `go build` does not use -complete for go:linkname to work")
err = writeFile(filepath.Join(pkgdir, "trace.s"), buf.Bytes())
if err != nil {
log.Fatal(err)
}
return nil // XXX return nil // XXX
} }
func main() { func main() {
log.SetFlags(0)
log.SetPrefix("gotrace: ")
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, fmt.Fprintf(os.Stderr,
`gotracegen [options] [package] `gotracegen [options] [package]
......
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