Skip to content

Commit ca40821

Browse files
committed
gotext: implement go modules support (from ssoroka commit 059a5b1)
1 parent 30a2840 commit ca40821

File tree

4 files changed

+97
-82
lines changed

4 files changed

+97
-82
lines changed

message/pipeline/extract.go

+55-41
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@ import (
1414
"go/token"
1515
"go/types"
1616
"path/filepath"
17-
"sort"
1817
"strings"
1918
"unicode"
2019
"unicode/utf8"
2120

22-
fmtparser "golang.org/x/text/internal/format"
2321
"golang.org/x/tools/go/callgraph"
2422
"golang.org/x/tools/go/callgraph/cha"
25-
"golang.org/x/tools/go/loader"
23+
"golang.org/x/tools/go/packages"
2624
"golang.org/x/tools/go/ssa"
27-
"golang.org/x/tools/go/ssa/ssautil"
25+
26+
fmtparser "golang.org/x/text/internal/format"
2827
)
2928

3029
const debug = false
@@ -50,8 +49,7 @@ func Extract(c *Config) (*State, error) {
5049
x.extractMessages()
5150

5251
return &State{
53-
Config: *c,
54-
program: x.iprog,
52+
Config: *c,
5553
Extracted: Messages{
5654
Language: c.SourceLanguage,
5755
Messages: x.messages,
@@ -60,8 +58,8 @@ func Extract(c *Config) (*State, error) {
6058
}
6159

6260
type extracter struct {
63-
conf loader.Config
64-
iprog *loader.Program
61+
conf packages.Config
62+
pkgs []*packages.Package
6563
prog *ssa.Program
6664
callGraph *callgraph.Graph
6765

@@ -73,17 +71,20 @@ type extracter struct {
7371

7472
func newExtracter(c *Config) (x *extracter, err error) {
7573
x = &extracter{
76-
conf: loader.Config{},
74+
conf: packages.Config{
75+
Fset: token.NewFileSet(),
76+
},
7777
globals: map[token.Pos]*constData{},
7878
funcs: map[token.Pos]*callData{},
7979
}
8080

81-
x.iprog, err = loadPackages(&x.conf, c.Packages)
81+
prog, pkgs, err := loadPackages(&x.conf, c.Packages)
8282
if err != nil {
8383
return nil, wrap(err, "")
8484
}
85+
x.prog = prog
86+
x.pkgs = pkgs
8587

86-
x.prog = ssautil.CreateProgram(x.iprog, ssa.GlobalDebug|ssa.BareInits)
8788
x.prog.Build()
8889

8990
x.callGraph = cha.CallGraph(x.prog)
@@ -101,26 +102,46 @@ func (x *extracter) globalData(pos token.Pos) *constData {
101102
}
102103

103104
func (x *extracter) seedEndpoints() error {
104-
pkgInfo := x.iprog.Package("golang.org/x/text/message")
105-
if pkgInfo == nil {
106-
return errors.New("pipeline: golang.org/x/text/message is not imported")
105+
var pkg *packages.Package
106+
imports := ""
107+
for _, p := range x.pkgs {
108+
for k := range p.Imports {
109+
imports = imports + k + "\n"
110+
}
111+
if p2, ok := p.Imports["golang.org/x/text/message"]; ok {
112+
pkg = p2
113+
break
114+
}
115+
}
116+
if pkg == nil {
117+
return errors.New("pipeline: golang.org/x/text/message is not imported.\n" + imports)
118+
}
119+
120+
var typ *types.Pointer
121+
for _, typeAndVal := range pkg.TypesInfo.Types {
122+
if typeAndVal.Type.String() == "golang.org/x/text/message.Printer" {
123+
typ = types.NewPointer(typeAndVal.Type)
124+
break
125+
}
126+
}
127+
128+
if typ == nil {
129+
return errors.New("pipeline: golang.org/x/text/message.Printer was not found")
107130
}
108-
pkg := x.prog.Package(pkgInfo.Pkg)
109-
typ := types.NewPointer(pkg.Type("Printer").Type())
110131

111132
x.processGlobalVars()
112133

113-
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Printf"), &callData{
134+
x.handleFunc(x.prog.LookupMethod(typ, pkg.Types, "Printf"), &callData{
114135
formatPos: 1,
115136
argPos: 2,
116137
isMethod: true,
117138
})
118-
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Sprintf"), &callData{
139+
x.handleFunc(x.prog.LookupMethod(typ, pkg.Types, "Sprintf"), &callData{
119140
formatPos: 1,
120141
argPos: 2,
121142
isMethod: true,
122143
})
123-
x.handleFunc(x.prog.LookupMethod(typ, pkg.Pkg, "Fprintf"), &callData{
144+
x.handleFunc(x.prog.LookupMethod(typ, pkg.Types, "Fprintf"), &callData{
124145
formatPos: 2,
125146
argPos: 3,
126147
isMethod: true,
@@ -489,14 +510,14 @@ func (x *extracter) visitArgs(fd *callData, v ssa.Value) {
489510
// print returns Go syntax for the specified node.
490511
func (x *extracter) print(n ast.Node) string {
491512
var buf bytes.Buffer
492-
format.Node(&buf, x.conf.Fset, n)
513+
_ = format.Node(&buf, x.conf.Fset, n)
493514
return buf.String()
494515
}
495516

496517
type packageExtracter struct {
497518
f *ast.File
498519
x *extracter
499-
info *loader.PackageInfo
520+
pkg *packages.Package
500521
cmap ast.CommentMap
501522
}
502523

@@ -509,20 +530,13 @@ func (px packageExtracter) getComment(n ast.Node) string {
509530
}
510531

511532
func (x *extracter) extractMessages() {
512-
prog := x.iprog
513-
keys := make([]*types.Package, 0, len(x.iprog.AllPackages))
514-
for k := range x.iprog.AllPackages {
515-
keys = append(keys, k)
516-
}
517-
sort.Slice(keys, func(i, j int) bool { return keys[i].Path() < keys[j].Path() })
518533
files := []packageExtracter{}
519-
for _, k := range keys {
520-
info := x.iprog.AllPackages[k]
521-
for _, f := range info.Files {
534+
for _, pkg := range x.pkgs {
535+
for _, f := range pkg.Syntax {
522536
// Associate comments with nodes.
523537
px := packageExtracter{
524-
f, x, info,
525-
ast.NewCommentMap(prog.Fset, f, f.Comments),
538+
f, x, pkg,
539+
ast.NewCommentMap(pkg.Fset, f, f.Comments),
526540
}
527541
files = append(files, px)
528542
}
@@ -616,13 +630,13 @@ func (px packageExtracter) handleCall(call *ast.CallExpr) bool {
616630
func (px packageExtracter) getArguments(data *callData) []argument {
617631
arguments := []argument{}
618632
x := px.x
619-
info := px.info
633+
pkg := px.pkg
620634
if data.callArgsStart() >= 0 {
621635
args := data.expr.Args[data.callArgsStart():]
622636
for i, arg := range args {
623637
expr := x.print(arg)
624638
val := ""
625-
if v := info.Types[arg].Value; v != nil {
639+
if v := pkg.TypesInfo.Types[arg].Value; v != nil {
626640
val = v.ExactString()
627641
switch arg.(type) {
628642
case *ast.BinaryExpr, *ast.UnaryExpr:
@@ -631,12 +645,12 @@ func (px packageExtracter) getArguments(data *callData) []argument {
631645
}
632646
arguments = append(arguments, argument{
633647
ArgNum: i + 1,
634-
Type: info.Types[arg].Type.String(),
635-
UnderlyingType: info.Types[arg].Type.Underlying().String(),
648+
Type: pkg.TypesInfo.Types[arg].Type.String(),
649+
UnderlyingType: pkg.TypesInfo.Types[arg].Type.Underlying().String(),
636650
Expr: expr,
637651
Value: val,
638652
Comment: px.getComment(arg),
639-
Position: posString(&x.conf, info.Pkg, arg.Pos()),
653+
Position: posString(&x.conf, pkg.Types, arg.Pos()),
640654
// TODO report whether it implements
641655
// interfaces plural.Interface,
642656
// gender.Interface.
@@ -682,7 +696,7 @@ func (px packageExtracter) addMessage(
682696
case fmtparser.StatusBadArgNum, fmtparser.StatusMissingArg:
683697
arg = &argument{
684698
ArgNum: p.ArgNum,
685-
Position: posString(&x.conf, px.info.Pkg, pos),
699+
Position: posString(&x.conf, px.pkg.Types, pos),
686700
}
687701
name, arg.UnderlyingType = verbToPlaceholder(p.Text(), p.ArgNum)
688702
}
@@ -711,11 +725,11 @@ func (px packageExtracter) addMessage(
711725
// TODO(fix): this doesn't get the before comment.
712726
Comment: comment,
713727
Placeholders: ph.slice,
714-
Position: posString(&x.conf, px.info.Pkg, pos),
728+
Position: posString(&x.conf, px.pkg.Types, pos),
715729
})
716730
}
717731

718-
func posString(conf *loader.Config, pkg *types.Package, pos token.Pos) string {
732+
func posString(conf *packages.Config, pkg *types.Package, pos token.Pos) string {
719733
p := conf.Fset.Position(pos)
720734
file := fmt.Sprintf("%s:%d:%d", filepath.Base(p.Filename), p.Line, p.Column)
721735
return filepath.Join(pkg.Path(), file)
@@ -818,4 +832,4 @@ func isMsg(s string) bool {
818832
}
819833
}
820834
return false
821-
}
835+
}

message/pipeline/generate.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import (
1414
"strings"
1515
"text/template"
1616

17+
"golang.org/x/tools/go/packages"
18+
1719
"golang.org/x/text/collate"
1820
"golang.org/x/text/feature/plural"
1921
"golang.org/x/text/internal"
2022
"golang.org/x/text/internal/catmsg"
2123
"golang.org/x/text/internal/gen"
2224
"golang.org/x/text/language"
23-
"golang.org/x/tools/go/loader"
2425
)
2526

2627
var transRe = regexp.MustCompile(`messages\.(.*)\.json`)
@@ -34,30 +35,28 @@ func (s *State) Generate() error {
3435
path = "."
3536
}
3637
isDir := path[0] == '.'
37-
prog, err := loadPackages(&loader.Config{}, []string{path})
38+
_, pkgs, err := loadPackages(&packages.Config{}, []string{path})
3839
if err != nil {
3940
return wrap(err, "could not load package")
4041
}
41-
pkgs := prog.InitialPackages()
4242
if len(pkgs) != 1 {
4343
return errorf("more than one package selected: %v", pkgs)
4444
}
45-
pkg := pkgs[0].Pkg.Name()
4645

4746
cw, err := s.generate()
4847
if err != nil {
4948
return err
5049
}
5150
if !isDir {
5251
gopath := filepath.SplitList(build.Default.GOPATH)[0]
53-
path = filepath.Join(gopath, "src", filepath.FromSlash(pkgs[0].Pkg.Path()))
52+
path = filepath.Join(gopath, "src", filepath.FromSlash(pkgs[0].PkgPath))
5453
}
5554
if filepath.IsAbs(s.Config.GenFile) {
5655
path = s.Config.GenFile
5756
} else {
5857
path = filepath.Join(path, s.Config.GenFile)
5958
}
60-
cw.WriteGoFile(path, pkg) // TODO: WriteGoFile should return error.
59+
cw.WriteGoFile(path, pkgs[0].Name) // TODO: WriteGoFile should return error.
6160
return err
6261
}
6362

@@ -321,4 +320,4 @@ func init() {
321320
message.DefaultCatalog = cat
322321
}
323322
324-
`))
323+
`))

message/pipeline/pipeline.go

+17-14
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"bytes"
1212
"encoding/json"
1313
"fmt"
14-
"go/build"
15-
"go/parser"
1614
"io/ioutil"
1715
"log"
1816
"os"
@@ -22,10 +20,13 @@ import (
2220
"text/template"
2321
"unicode"
2422

23+
"golang.org/x/tools/go/packages"
24+
"golang.org/x/tools/go/ssa"
25+
"golang.org/x/tools/go/ssa/ssautil"
26+
2527
"golang.org/x/text/internal"
2628
"golang.org/x/text/language"
2729
"golang.org/x/text/runes"
28-
"golang.org/x/tools/go/loader"
2930
)
3031

3132
const (
@@ -125,7 +126,6 @@ type State struct {
125126
Config Config
126127

127128
Package string
128-
program *loader.Program
129129

130130
Extracted Messages `json:"messages"`
131131

@@ -403,20 +403,23 @@ func warnf(format string, args ...interface{}) {
403403
log.Printf(format, args...)
404404
}
405405

406-
func loadPackages(conf *loader.Config, args []string) (*loader.Program, error) {
406+
func loadPackages(conf *packages.Config, args []string) (*ssa.Program, []*packages.Package, error) {
407407
if len(args) == 0 {
408408
args = []string{"."}
409409
}
410410

411-
conf.Build = &build.Default
412-
conf.ParserMode = parser.ParseComments
413-
414-
// Use the initial packages from the command line.
415-
args, err := conf.FromArgs(args, false)
411+
conf.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
412+
packages.NeedImports |
413+
packages.NeedTypes | packages.NeedTypesSizes |
414+
packages.NeedSyntax | packages.NeedTypesInfo |
415+
packages.NeedDeps
416+
pkgs, err := packages.Load(conf, args...)
416417
if err != nil {
417-
return nil, wrap(err, "loading packages failed")
418+
packages.PrintErrors(pkgs)
419+
return nil, nil, err
418420
}
419421

420-
// Load, parse and type-check the whole program.
421-
return conf.Load()
422-
}
422+
prog, _ := ssautil.Packages(pkgs, 0)
423+
424+
return prog, pkgs, nil
425+
}

0 commit comments

Comments
 (0)