GoPLS Viewer

Home|gopls/cmd/eg/eg.go
1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// The eg command performs example-based refactoring.
6// For documentation, run the command, or see Help in
7// golang.org/x/tools/refactor/eg.
8package main // import "golang.org/x/tools/cmd/eg"
9
10import (
11    "flag"
12    "fmt"
13    "go/ast"
14    "go/format"
15    "go/parser"
16    "go/token"
17    "go/types"
18    "io/ioutil"
19    "os"
20    "path/filepath"
21    "strings"
22
23    exec "golang.org/x/sys/execabs"
24    "golang.org/x/tools/go/packages"
25    "golang.org/x/tools/refactor/eg"
26)
27
28var (
29    beforeeditFlag = flag.String("beforeedit""""A command to exec before each file is edited (e.g. chmod, checkout).  Whitespace delimits argument words.  The string '{}' is replaced by the file name.")
30    helpFlag       = flag.Bool("help"false"show detailed help message")
31    templateFlag   = flag.String("t""""template.go file specifying the refactoring")
32    transitiveFlag = flag.Bool("transitive"false"apply refactoring to all dependencies too")
33    writeFlag      = flag.Bool("w"false"rewrite input files in place (by default, the results are printed to standard output)")
34    verboseFlag    = flag.Bool("v"false"show verbose matcher diagnostics")
35)
36
37const usage = `eg: an example-based refactoring tool.
38
39Usage: eg -t template.go [-w] [-transitive] <packages>
40
41-help            show detailed help message
42-t template.go     specifies the template file (use -help to see explanation)
43-w               causes files to be re-written in place.
44-transitive      causes all dependencies to be refactored too.
45-v               show verbose matcher diagnostics
46-beforeedit cmd  a command to exec before each file is modified.
47                 "{}" represents the name of the file.
48`
49
50func main() {
51    if err := doMain(); err != nil {
52        fmt.Fprintf(os.Stderr"eg: %s\n"err)
53        os.Exit(1)
54    }
55}
56
57func doMain() error {
58    flag.Parse()
59    args := flag.Args()
60
61    if *helpFlag {
62        help := eg.Help // hide %s from vet
63        fmt.Fprint(os.Stderrhelp)
64        os.Exit(2)
65    }
66
67    if len(args) == 0 {
68        fmt.Fprint(os.Stderrusage)
69        os.Exit(1)
70    }
71
72    if *templateFlag == "" {
73        return fmt.Errorf("no -t template.go file specified")
74    }
75
76    tAbserr := filepath.Abs(*templateFlag)
77    if err != nil {
78        return err
79    }
80    templateerr := ioutil.ReadFile(tAbs)
81    if err != nil {
82        return err
83    }
84
85    cfg := &packages.Config{
86        Fset:  token.NewFileSet(),
87        Mode:  packages.NeedTypesInfo | packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedImports | packages.NeedDeps | packages.NeedCompiledGoFiles,
88        Teststrue,
89    }
90
91    pkgserr := packages.Load(cfgargs...)
92    if err != nil {
93        return err
94    }
95
96    tFileerr := parser.ParseFile(cfg.FsettAbstemplateparser.ParseComments)
97    if err != nil {
98        return err
99    }
100
101    // Type-check the template.
102    tInfo := types.Info{
103        Types:      make(map[ast.Expr]types.TypeAndValue),
104        Defs:       make(map[*ast.Ident]types.Object),
105        Uses:       make(map[*ast.Ident]types.Object),
106        Implicits:  make(map[ast.Node]types.Object),
107        Selectionsmake(map[*ast.SelectorExpr]*types.Selection),
108        Scopes:     make(map[ast.Node]*types.Scope),
109    }
110    conf := types.Config{
111        ImporterpkgsImporter(pkgs),
112    }
113    tPkgerr := conf.Check("egtemplate"cfg.Fset, []*ast.File{tFile}, &tInfo)
114    if err != nil {
115        return err
116    }
117
118    // Analyze the template.
119    xformerr := eg.NewTransformer(cfg.FsettPkgtFile, &tInfo, *verboseFlag)
120    if err != nil {
121        return err
122    }
123
124    // Apply it to the input packages.
125    var all []*packages.Package
126    if *transitiveFlag {
127        packages.Visit(pkgsnil, func(p *packages.Package) { all = append(allp) })
128    } else {
129        all = pkgs
130    }
131    var hadErrors bool
132    for _pkg := range pkgs {
133        for ifilename := range pkg.CompiledGoFiles {
134            if filename == tAbs {
135                // Don't rewrite the template file.
136                continue
137            }
138            file := pkg.Syntax[i]
139            n := xform.Transform(pkg.TypesInfopkg.Typesfile)
140            if n == 0 {
141                continue
142            }
143            fmt.Fprintf(os.Stderr"=== %s (%d matches)\n"filenamen)
144            if *writeFlag {
145                // Run the before-edit command (e.g. "chmod +w",  "checkout") if any.
146                if *beforeeditFlag != "" {
147                    args := strings.Fields(*beforeeditFlag)
148                    // Replace "{}" with the filename, like find(1).
149                    for i := range args {
150                        if i > 0 {
151                            args[i] = strings.Replace(args[i], "{}"filename, -1)
152                        }
153                    }
154                    cmd := exec.Command(args[0], args[1:]...)
155                    cmd.Stdout = os.Stdout
156                    cmd.Stderr = os.Stderr
157                    if err := cmd.Run(); err != nil {
158                        fmt.Fprintf(os.Stderr"Warning: edit hook %q failed (%s)\n",
159                            argserr)
160                    }
161                }
162                if err := eg.WriteAST(cfg.Fsetfilenamefile); err != nil {
163                    fmt.Fprintf(os.Stderr"eg: %s\n"err)
164                    hadErrors = true
165                }
166            } else {
167                format.Node(os.Stdoutcfg.Fsetfile)
168            }
169        }
170    }
171    if hadErrors {
172        os.Exit(1)
173    }
174
175    return nil
176}
177
178type pkgsImporter []*packages.Package
179
180func (p pkgsImporterImport(path string) (tpkg *types.Packageerr error) {
181    packages.Visit([]*packages.Package(p), func(pkg *packages.Packagebool {
182        if pkg.PkgPath == path {
183            tpkg = pkg.Types
184            return false
185        }
186        return true
187    }, nil)
188    if tpkg != nil {
189        return tpkgnil
190    }
191    return nilfmt.Errorf("package %q not found"path)
192}
193
MembersX
doMain
doMain.BlockStmt.help
doMain.tFile
doMain.RangeStmt_3666.pkg
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.BlockStmt.BlockStmt.args
usage
doMain.err
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.BlockStmt.BlockStmt.cmd
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.BlockStmt.err
pkgsImporter.Import.err
flag
token
ioutil
doMain.args
doMain.tAbs
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.filename
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.BlockStmt.BlockStmt.err
pkgsImporter
pkgsImporter.Import.p
pkgsImporter.Import
pkgsImporter.Import.path
parser
os
strings
eg
doMain.cfg
doMain.conf
doMain.xform
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.i
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.BlockStmt.BlockStmt.RangeStmt_4231.i
filepath
exec
doMain.tInfo
doMain.tPkg
doMain.hadErrors
pkgsImporter.Import.tpkg
fmt
ast
types
packages
main
main.err
doMain.template
doMain.pkgs
format
doMain.all
doMain.RangeStmt_3666.BlockStmt.RangeStmt_3695.BlockStmt.n
Members
X