Commit dcf3f530 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent b6676718
...@@ -74,9 +74,20 @@ type traceImport struct { ...@@ -74,9 +74,20 @@ type traceImport struct {
// XXX back link to *Package? // XXX back link to *Package?
Pos token.Position Pos token.Position
PkgName string
PkgPath string PkgPath string
} }
// 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
}
// Package represents tracing-related information about a package // Package represents tracing-related information about a package
type Package struct { type Package struct {
Pkgi *loader.PackageInfo // original non-augmented package Pkgi *loader.PackageInfo // original non-augmented package
...@@ -186,6 +197,44 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st ...@@ -186,6 +197,44 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
return &traceEvent{Pkgt: p, FuncDecl: declf}, nil return &traceEvent{Pkgt: p, FuncDecl: declf}, nil
} }
// parseTraceImport parses trace import directive into traceImport
// text is text argument after "//trace:import "
func (p *Package) parseTraceImport(pos token.Position, text string) (*traceImport, error) {
// //trace:import "path/to/pkg"
// //traca:import name "path/to/pkg"
if len(text) == 0 {
return nil, fmt.Errorf("%v: empty trace-import spec", pos)
}
pkgname := ""
pkgqpath := text
if !(text[0] == '"' || text[0] == '\'') {
textv := strings.SplitN(text, " ", 2)
if len(textv) != 2 {
return nil, fmt.Errorf("%v: invalid trace-import spec %v", pos, text)
}
pkgname = textv[0]
pkgqpath = textv[1]
}
// Unqote pkgqpath as in regular import does
pkgpath, err := strconv.Unquote(pkgqpath)
if err != nil || pkgpath == "" || pkgpath[0] == '\'' {
return nil, fmt.Errorf("%v: invalid trace-import path %v", pos, pkgqpath)
}
// reject duplicate imports
for _, imported := range p.Importv {
if pkgpath == imported.PkgPath {
return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, pkgpath, imported.Pos)
}
}
return &traceImport{Pos: pos, PkgName: pkgname, PkgPath: pkgpath}, nil
}
// packageTrace returns tracing information about a package // packageTrace returns tracing information about a package
func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, error) { func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, error) {
// prepare Package with typechecker ready to typecheck trace files // prepare Package with typechecker ready to typecheck trace files
...@@ -263,19 +312,13 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err ...@@ -263,19 +312,13 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err
p.Eventv = append(p.Eventv, event) p.Eventv = append(p.Eventv, event)
case "//trace:import": case "//trace:import":
// Unqote arg as in regular import imported, err := p.parseTraceImport(pos, arg)
importPath, err := strconv.Unquote(arg) if err != nil {
if err != nil || arg[0] == '\'' { return nil, err
return nil, fmt.Errorf("%v: invalid trace-import path %v", pos, arg)
} }
// reject duplicate imports // XXX needed here? - better append in parseTraceEvent
for _, imported := range p.Importv { p.Importv = append(p.Importv, imported)
if importPath == imported.PkgPath {
return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, importPath, imported.Pos)
}
}
p.Importv = append(p.Importv, &traceImport{Pos: pos, PkgPath: importPath})
default: default:
return nil, fmt.Errorf("%v: unknown tracing directive %q", pos, directive) return nil, fmt.Errorf("%v: unknown tracing directive %q", pos, directive)
...@@ -322,11 +365,12 @@ func (te *traceEvent) Argv() string { ...@@ -322,11 +365,12 @@ func (te *traceEvent) Argv() string {
// ArgvTyped returns argument list with types // ArgvTyped returns argument list with types
// types are qualified relative to original package // types are qualified relative to original package
func (te *traceEvent) ArgvTyped() string { func (te *traceEvent) ArgvTyped() string {
return te.ArgvTypedRelativeTo(te.Pkgt.tracePkg) return te.ArgvTypedRelativeTo(te.Pkgt.tracePkg, nil)
} }
// ArgvTypedRelativeTo returns argument list with types qualified relative to specified package // ArgvTypedRelativeTo returns argument list with types qualified relative to specified package
func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string { // importedAs specifies under which name a package was imported, if name was explicitly set
func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package, importedAs map[string/*pkgpath*/]string/*pkgname*/) string {
argv := []string{} argv := []string{}
// default qualifier - relative to original package // default qualifier - relative to original package
...@@ -336,6 +380,12 @@ func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string { ...@@ -336,6 +380,12 @@ func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string {
return "" return ""
} }
// qualify as explicitly named
pkgname := importedAs[p.Path()]
if pkgname != "" {
return pkgname
}
// default qualification // default qualification
return p.Name() return p.Name()
} }
...@@ -415,8 +465,9 @@ func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.ArgvTyped}})) *traci ...@@ -415,8 +465,9 @@ func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.ArgvTyped}})) *traci
// traceEventImportTmpl is code template generated for importing one trace event // traceEventImportTmpl is code template generated for importing one trace event
var traceEventImportTmpl = template.Must(template.New("traceimport").Parse(` var traceEventImportTmpl = template.Must(template.New("traceimport").Parse(`
//go:linkname {{.Pkgt.Pkgi.Pkg.Name}}_{{.Name}}_Attach {{.Pkgt.Pkgi.Pkg.Path}}.{{.Name}}_Attach {{/* function to attach a probe to tracepoint imported via go:linkname */ -}}
func {{.Pkgt.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.ArgvTypedRelativeTo .ImporterPkg}})) *tracing.Probe //go:linkname {{.ImportSpec.PkgName}}_{{.Name}}_Attach {{.ImportSpec.PkgPath}}.{{.Name}}_Attach
func {{.ImportSpec.PkgName}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.ArgvTypedRelativeTo .ImporterPkg .ImportedAs}})) *tracing.Probe
`)) `))
// magic begins all files generated by gotrace // magic begins all files generated by gotrace
...@@ -592,9 +643,14 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -592,9 +643,14 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
prologue.emit("\nimport (") prologue.emit("\nimport (")
prologue.emit("\t%q", "lab.nexedi.com/kirr/neo/go/xcommon/tracing") prologue.emit("\t%q", "lab.nexedi.com/kirr/neo/go/xcommon/tracing")
prologue.emit("\t%q", "unsafe") prologue.emit("\t%q", "unsafe")
// import of all packages needed for used types will go here in the end
// import of all packages needed for used types
needPkg := StrSet{} needPkg := StrSet{}
// some packages are imported with explicit name
importedAs := map[string/*pkgpath*/]string/*pkgname*/{}
// code for trace:event definitions // code for trace:event definitions
text := &Buffer{} text := &Buffer{}
for _, event := range tpkg.Eventv { for _, event := range tpkg.Eventv {
...@@ -609,13 +665,20 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -609,13 +665,20 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
// code for trace:import imports // code for trace:import imports
for _, timport := range tpkg.Importv { for _, timport := range tpkg.Importv {
text.emit("\n// traceimport: %q", timport.PkgPath) text.emit("\n// traceimport: %s", timport.ImportSpec())
impProg, impPkgi, err := P.Import(timport.PkgPath) impProg, impPkgi, err := P.Import(timport.PkgPath)
if err != nil { if err != nil {
return fmt.Errorf("%v: error trace-importing %s: %v", timport.Pos, timport.PkgPath, err) return fmt.Errorf("%v: error trace-importing %s: %v", timport.Pos, timport.PkgPath, err)
} }
// set name of the package if it was not explicitly specified
if timport.PkgName == "" {
timport.PkgName = impPkgi.Pkg.Name()
} else {
importedAs[timport.PkgPath] = timport.PkgName
}
impPkg, err := packageTrace(impProg, impPkgi) impPkg, err := packageTrace(impProg, impPkgi)
if err != nil { if err != nil {
return err // XXX err ctx return err // XXX err ctx
...@@ -625,8 +688,10 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -625,8 +688,10 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
needPkg.Add(event.NeedPkgv()...) needPkg.Add(event.NeedPkgv()...)
importedEvent := struct{ importedEvent := struct{
*traceEvent *traceEvent
ImporterPkg *types.Package ImportSpec *traceImport
} {event, pkgi.Pkg } ImporterPkg *types.Package
ImportedAs map[string]string
} {event, timport, pkgi.Pkg, importedAs}
err = traceEventImportTmpl.Execute(text, importedEvent) err = traceEventImportTmpl.Execute(text, importedEvent)
if err != nil { if err != nil {
panic(err) // XXX panic(err) // XXX
...@@ -644,7 +709,11 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error { ...@@ -644,7 +709,11 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
} }
for _, needpkg := range needPkgv { for _, needpkg := range needPkgv {
prologue.emit("\t%q", needpkg) pkgname := importedAs[needpkg]
if pkgname != "" {
pkgname += " "
}
prologue.emit("\t%s%q", pkgname, needpkg)
} }
prologue.emit(")") prologue.emit(")")
......
...@@ -2,7 +2,10 @@ package pkg2 ...@@ -2,7 +2,10 @@ package pkg2
// trace-import another package // trace-import another package
// NOTE "a/pkg1" is not regularly imported // NOTE "a/pkg1" is not regularly imported
//trace:import "a/pkg1" ////trace:import "a/pkg1"
// XXX temp
//trace:import bbb "a/pkg1"
// additional tracepoint which pkg2 defines // additional tracepoint which pkg2 defines
//trace:event traceDoSomething(i, j int, q string) //trace:event traceDoSomething(i, j int, q string)
......
...@@ -2,8 +2,8 @@ package pkg3 ...@@ -2,8 +2,8 @@ package pkg3
import "testing" import "testing"
// trace import that should be added only to tests // trace import that should be added only to tests, and under specified package name
//trace:import "a/pkg1" //trace:import aaa1 "a/pkg1"
func TestZzz(t *testing.T) { func TestZzz(t *testing.T) {
if zzz() != 2 { if zzz() != 2 {
......
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