Commit 48043365 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 48c03e87
...@@ -32,6 +32,7 @@ package main ...@@ -32,6 +32,7 @@ package main
import ( import (
"bufio" "bufio"
"crypto/sha1"
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
...@@ -74,21 +75,17 @@ type traceEvent struct { ...@@ -74,21 +75,17 @@ type traceEvent struct {
// traceImport represents 1 trace:import directive // traceImport represents 1 trace:import directive
type traceImport struct { type traceImport struct {
// XXX back link to *Package?
Pos token.Position Pos token.Position
PkgName string PkgName string // "" if import name was not explicitly specified
PkgPath string PkgPath string
} }
// ImportSpec returns string representation of import spec // traceImported represents 1 imported trace:event
func (ti *traceImport) ImportSpec() string { type traceImported struct {
t := ti.PkgName *traceEvent // original event
if t != "" { ImportSpec *traceImport // imported via this spec
t += " " ImporterPkg *types.Package // from this package
} ImportedAs map[string]string // where some packages are imported as named (pkgpath -> pkgname)
t += fmt.Sprintf("%q", ti.PkgPath)
return t
} }
// Package represents tracing-related information about a package // Package represents tracing-related information about a package
...@@ -110,21 +107,6 @@ type Package struct { ...@@ -110,21 +107,6 @@ type Package struct {
} }
// progImporter is types.Importer that imports packages from loaded loader.Program
type progImporter struct {
prog *loader.Program
}
func (pi *progImporter) Import(path string) (*types.Package, error) {
pkgi := pi.prog.Package(path)
if pkgi == nil {
return nil, fmt.Errorf("package %q not found", path)
}
return pkgi.Pkg, nil
}
// parseTraceEvent parses trace event definition into traceEvent // parseTraceEvent parses trace event definition into traceEvent
// text is text argument after "//trace:event " // text is text argument after "//trace:event "
func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text string) (*traceEvent, error) { func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text string) (*traceEvent, error) {
...@@ -236,36 +218,18 @@ func (p *Package) parseTraceImport(pos token.Position, text string) (*traceImpor ...@@ -236,36 +218,18 @@ func (p *Package) parseTraceImport(pos token.Position, text string) (*traceImpor
return &traceImport{Pos: pos, PkgName: pkgname, PkgPath: pkgpath}, nil return &traceImport{Pos: pos, PkgName: pkgname, PkgPath: pkgpath}, nil
} }
// SplitTests splits package into main and test parts, each covering trace-related things accordingly // progImporter is types.Importer that imports packages from loaded loader.Program
func (p *Package) SplitTests() (testPkg *Package) { type progImporter struct {
__ := *p prog *loader.Program
testPkg = &__ }
// for tracing what is relevant is: we need to split only .Eventv & .Importv
eventv := p.Eventv
importv := p.Importv
p.Eventv = nil
p.Importv = nil
testPkg.Eventv = nil
testPkg.Importv = nil
for _, e := range eventv {
if strings.HasSuffix(e.Pos.Filename, "_test.go") {
testPkg.Eventv = append(testPkg.Eventv, e)
} else {
p.Eventv = append(p.Eventv, e)
}
}
for _, i := range importv { func (pi *progImporter) Import(path string) (*types.Package, error) {
if strings.HasSuffix(i.Pos.Filename, "_test.go") { pkgi := pi.prog.Package(path)
testPkg.Importv = append(testPkg.Importv, i) if pkgi == nil {
} else { return nil, fmt.Errorf("package %q not found", path)
p.Importv = append(p.Importv, i)
}
} }
return testPkg return pkgi.Pkg, nil
} }
// packageTrace returns tracing information about a package // packageTrace returns tracing information about a package
...@@ -380,6 +344,40 @@ func (v byPkgPath) Swap(i, j int) { v[i], v[j] = v[j], v[i] } ...@@ -380,6 +344,40 @@ func (v byPkgPath) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v byPkgPath) Len() int { return len(v) } func (v byPkgPath) Len() int { return len(v) }
// SplitTests splits package into main and test parts, each covering trace-related things accordingly
func (p *Package) SplitTests() (testPkg *Package) {
__ := *p
testPkg = &__
// relevant for tracing are only: .Eventv & .Importv
eventv := p.Eventv
importv := p.Importv
p.Eventv = nil
p.Importv = nil
testPkg.Eventv = nil
testPkg.Importv = nil
for _, e := range eventv {
if strings.HasSuffix(e.Pos.Filename, "_test.go") {
testPkg.Eventv = append(testPkg.Eventv, e)
} else {
p.Eventv = append(p.Eventv, e)
}
}
for _, i := range importv {
if strings.HasSuffix(i.Pos.Filename, "_test.go") {
testPkg.Importv = append(testPkg.Importv, i)
} else {
p.Importv = append(p.Importv, i)
}
}
return testPkg
}
// ---------------------------------------- // ----------------------------------------
// Argv returns comma-separated argument-list // Argv returns comma-separated argument-list
...@@ -457,6 +455,17 @@ func (te *traceEvent) NeedPkgv() []string { ...@@ -457,6 +455,17 @@ func (te *traceEvent) NeedPkgv() []string {
return pkgset.Itemv() return pkgset.Itemv()
} }
// ImportSpec returns string representation of import spec
func (ti *traceImport) ImportSpec() string {
t := ti.PkgName
if t != "" {
t += " "
}
t += fmt.Sprintf("%q", ti.PkgPath)
return t
}
// traceEventCodeTmpl is code template generated for one trace event // traceEventCodeTmpl is code template generated for one trace event
var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(` var traceEventCodeTmpl = template.Must(template.New("traceevent").Parse(`
// traceevent: {{.Name}}({{.ArgvTyped}}) // traceevent: {{.Name}}({{.ArgvTyped}})
...@@ -562,7 +571,7 @@ type Program struct { ...@@ -562,7 +571,7 @@ type Program struct {
// original program. // original program.
// //
// Since go/loader does not support incrementally augmenting loaded // Since go/loader does not support incrementally augmenting loaded
// program with more packages we work-around it with having several // program with more packages, we work-around it with having several
// progs. // progs.
progv []*loader.Program progv []*loader.Program
...@@ -570,6 +579,7 @@ type Program struct { ...@@ -570,6 +579,7 @@ type Program struct {
loaderConf *loader.Config loaderConf *loader.Config
} }
// NewProgram constructs new empty Program ready to load packages according to specified build context
func NewProgram(ctxt *build.Context, cwd string) *Program { func NewProgram(ctxt *build.Context, cwd string) *Program {
// adjust build context to filter-out ztrace* files when disovering packages // adjust build context to filter-out ztrace* files when disovering packages
// //
...@@ -605,7 +615,8 @@ func NewProgram(ctxt *build.Context, cwd string) *Program { ...@@ -605,7 +615,8 @@ func NewProgram(ctxt *build.Context, cwd string) *Program {
return p return p
} }
// Import imports a package and returns associated package info and program under which it was loaded // Import imports a package and returns associated package info and program
// under which it was loaded
func (p *Program) Import(pkgpath string) (prog *loader.Program, pkgi *loader.PackageInfo, err error) { func (p *Program) Import(pkgpath string) (prog *loader.Program, pkgi *loader.PackageInfo, err error) {
// let's see - maybe it is already there // let's see - maybe it is already there
for _, prog := range p.progv { for _, prog := range p.progv {
...@@ -634,9 +645,9 @@ func (p *Program) Import(pkgpath string) (prog *loader.Program, pkgi *loader.Pac ...@@ -634,9 +645,9 @@ func (p *Program) Import(pkgpath string) (prog *loader.Program, pkgi *loader.Pac
} }
// ImportWithTests imports a package augmented with code from _test.go files + // ImportWithTests imports a package augmented with code from _test.go files +
// imports external test package (if any) // imports external test package (if present)
func (p *Program) ImportWithTests(pkgpath string) (prog *loader.Program, pkgi *loader.PackageInfo, xtestPkgi *loader.PackageInfo, err error) { func (p *Program) ImportWithTests(pkgpath string) (prog *loader.Program, pkgi *loader.PackageInfo, xtestPkgi *loader.PackageInfo, err error) {
// XXX always reimporting not to interfere with regular imports // NOTE always reimporting not to interfere with regular imports
p.loaderConf.ImportPkgs = nil p.loaderConf.ImportPkgs = nil
p.loaderConf.ImportWithTests(pkgpath) p.loaderConf.ImportWithTests(pkgpath)
...@@ -662,15 +673,9 @@ func (p *Program) ImportWithTests(pkgpath string) (prog *loader.Program, pkgi *l ...@@ -662,15 +673,9 @@ func (p *Program) ImportWithTests(pkgpath string) (prog *loader.Program, pkgi *l
// ctxt is build context for discovering packages // ctxt is build context for discovering packages
// cwd is "current" directory for resolving local imports (e.g. packages like "./some/package") // cwd is "current" directory for resolving local imports (e.g. packages like "./some/package")
func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
// TODO test-only with .TestGoFiles .XTestGoFiles
P := NewProgram(ctxt, cwd) P := NewProgram(ctxt, cwd)
lprog, pkgi, xtestPkgi, err := P.ImportWithTests(pkgpath) lprog, pkgi, xtestPkgi, err := P.ImportWithTests(pkgpath)
//fmt.Println(pkgpath)
//fmt.Printf("%#p\n", pkgi)
//fmt.Printf("%#p\n", xtestPkgi)
//panic(0)
if err != nil { if err != nil {
return err return err
} }
...@@ -681,10 +686,6 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -681,10 +686,6 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
} }
pkgdir := filepath.Dir(lprog.Fset.File(pkgi.Files[0].Pos()).Name()) pkgdir := filepath.Dir(lprog.Fset.File(pkgi.Files[0].Pos()).Name())
pkgpath = pkgi.Pkg.Path()
//println("pkgpath", pkgpath)
//println("pkgdir", pkgdir)
//return nil
// tracing info for this specified package // tracing info for this specified package
tpkg, err := packageTrace(lprog, pkgi) tpkg, err := packageTrace(lprog, pkgi)
...@@ -698,6 +699,7 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -698,6 +699,7 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
err1 := tracegen1(P, tpkg, pkgdir, "") err1 := tracegen1(P, tpkg, pkgdir, "")
err2 := tracegen1(P, testTpkg, pkgdir, "_test") err2 := tracegen1(P, testTpkg, pkgdir, "_test")
// also handle xtest package
xtestTpkg := &Package{} // dummy package with empty .Eventv & .Importv xtestTpkg := &Package{} // dummy package with empty .Eventv & .Importv
if xtestPkgi != nil { if xtestPkgi != nil {
xtestTpkg, err = packageTrace(lprog, xtestPkgi) xtestTpkg, err = packageTrace(lprog, xtestPkgi)
...@@ -709,10 +711,11 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -709,10 +711,11 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
err3 := tracegen1(P, xtestTpkg, pkgdir, "_x_test") err3 := tracegen1(P, xtestTpkg, pkgdir, "_x_test")
return xerr.Merge(err1, err2, err3) return xerr.Merge(err1, err2, err3)
// return xerr.First(err1, err2, err3)
} }
// tracegen1 generates code according to tracing directives for a (sub)package @pkgpath
// subpackage is either original package, testing code, or external test package
func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error { func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error {
var err error var err error
...@@ -734,11 +737,11 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error { ...@@ -734,11 +737,11 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error {
prologue.emit("\t%q", "unsafe") prologue.emit("\t%q", "unsafe")
// import of all packages needed for used types // pkgpaths of all packages needed for used types
needPkg := StrSet{} needPkg := StrSet{}
// some packages are imported with explicit name // some packages are imported with explicit name
importedAs := map[string/*pkgpath*/]string/*pkgname*/{} importedAs := map[string]string{} // pkgpath -> pkgname
// code for trace:event definitions // code for trace:event definitions
text := &Buffer{} text := &Buffer{}
...@@ -746,7 +749,7 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error { ...@@ -746,7 +749,7 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error {
needPkg.Add(event.NeedPkgv()...) needPkg.Add(event.NeedPkgv()...)
err = traceEventCodeTmpl.Execute(text, event) err = traceEventCodeTmpl.Execute(text, event)
if err != nil { if err != nil {
panic(err) // XXX panic(err)
} }
} }
...@@ -775,15 +778,15 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error { ...@@ -775,15 +778,15 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error {
for _, event := range impPkg.Eventv { for _, event := range impPkg.Eventv {
needPkg.Add(event.NeedPkgv()...) needPkg.Add(event.NeedPkgv()...)
importedEvent := struct{ importedEvent := traceImported{
*traceEvent traceEvent: event,
ImportSpec *traceImport ImportSpec: timport,
ImporterPkg *types.Package ImporterPkg: tpkg.Pkgi.Pkg,
ImportedAs map[string]string ImportedAs: importedAs,
} {event, timport, tpkg.Pkgi.Pkg, importedAs} }
err = traceEventImportTmpl.Execute(text, importedEvent) err = traceEventImportTmpl.Execute(text, importedEvent)
if err != nil { if err != nil {
panic(err) // XXX panic(err)
} }
} }
} }
...@@ -833,6 +836,33 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error { ...@@ -833,6 +836,33 @@ func tracegen1(P *Program, tpkg *Package, pkgdir string, kind string) error {
return nil return nil
} }
// traceExportHash computes signature of tracing-related exports of a package
func traceExportHash(tpkg *Package, kind string) string {
// implementation: it is sha1 of associated header + importing code as
// if it was executed from universe scope
pkgpath := tpkg.Pkgi.Pkg.Path()
pkgname := tpkg.Pkgi.Pkg.Name()
exported := &Buffer{}
exported.emit("%q %q", pkgpath, kind)
for _, event := range tpkg.Eventv {
importedEvent := traceImported{
traceEvent: event,
ImportSpec: &traceImport{PkgName: pkgname, PkgPath: pkgpath},
ImporterPkg: nil, // from nowhere
ImportedAs: nil, // no naming for imports
}
err := traceEventImportTmpl.Execute(exported, importedEvent)
if err != nil {
panic(err)
}
}
return fmt.Sprintf("%x", sha1.Sum(exported.Bytes()))
}
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
log.SetPrefix("gotrace: ") log.SetPrefix("gotrace: ")
......
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