--- /dev/null
+// The eg command performs example-based refactoring.
+// For documentation, run the command, or see Help in
+// golang.org/x/tools/refactor/eg.
+package main // import "golang.org/x/tools/cmd/eg"
+
+import (
+ "flag"
+ "fmt"
+ "go/build"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "os"
+ "os/exec"
+ "strings"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/refactor/eg"
+)
+
+var (
+ 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.")
+ helpFlag = flag.Bool("help", false, "show detailed help message")
+ templateFlag = flag.String("t", "", "template.go file specifying the refactoring")
+ transitiveFlag = flag.Bool("transitive", false, "apply refactoring to all dependencies too")
+ writeFlag = flag.Bool("w", false, "rewrite input files in place (by default, the results are printed to standard output)")
+ verboseFlag = flag.Bool("v", false, "show verbose matcher diagnostics")
+)
+
+func init() {
+ flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const usage = `eg: an example-based refactoring tool.
+
+Usage: eg -t template.go [-w] [-transitive] <args>...
+
+-help show detailed help message
+-t template.go specifies the template file (use -help to see explanation)
+-w causes files to be re-written in place.
+-transitive causes all dependencies to be refactored too.
+-v show verbose matcher diagnostics
+-beforeedit cmd a command to exec before each file is modified.
+ "{}" represents the name of the file.
+` + loader.FromArgsUsage
+
+func main() {
+ if err := doMain(); err != nil {
+ fmt.Fprintf(os.Stderr, "eg: %s\n", err)
+ os.Exit(1)
+ }
+}
+
+func doMain() error {
+ flag.Parse()
+ args := flag.Args()
+
+ if *helpFlag {
+ fmt.Fprint(os.Stderr, eg.Help)
+ os.Exit(2)
+ }
+
+ if len(args) == 0 {
+ fmt.Fprint(os.Stderr, usage)
+ os.Exit(1)
+ }
+
+ if *templateFlag == "" {
+ return fmt.Errorf("no -t template.go file specified")
+ }
+
+ conf := loader.Config{
+ Fset: token.NewFileSet(),
+ ParserMode: parser.ParseComments,
+ }
+
+ // The first Created package is the template.
+ conf.CreateFromFilenames("template", *templateFlag)
+
+ if _, err := conf.FromArgs(args, true); err != nil {
+ return err
+ }
+
+ // Load, parse and type-check the whole program.
+ iprog, err := conf.Load()
+ if err != nil {
+ return err
+ }
+
+ // Analyze the template.
+ template := iprog.Created[0]
+ xform, err := eg.NewTransformer(iprog.Fset, template.Pkg, template.Files[0], &template.Info, *verboseFlag)
+ if err != nil {
+ return err
+ }
+
+ // Apply it to the input packages.
+ var pkgs []*loader.PackageInfo
+ if *transitiveFlag {
+ for _, info := range iprog.AllPackages {
+ pkgs = append(pkgs, info)
+ }
+ } else {
+ pkgs = iprog.InitialPackages()
+ }
+ var hadErrors bool
+ for _, pkg := range pkgs {
+ if pkg == template {
+ continue
+ }
+ for _, file := range pkg.Files {
+ n := xform.Transform(&pkg.Info, pkg.Pkg, file)
+ if n == 0 {
+ continue
+ }
+ filename := iprog.Fset.File(file.Pos()).Name()
+ fmt.Fprintf(os.Stderr, "=== %s (%d matches)\n", filename, n)
+ if *writeFlag {
+ // Run the before-edit command (e.g. "chmod +w", "checkout") if any.
+ if *beforeeditFlag != "" {
+ args := strings.Fields(*beforeeditFlag)
+ // Replace "{}" with the filename, like find(1).
+ for i := range args {
+ if i > 0 {
+ args[i] = strings.Replace(args[i], "{}", filename, -1)
+ }
+ }
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ fmt.Fprintf(os.Stderr, "Warning: edit hook %q failed (%s)\n",
+ args, err)
+ }
+ }
+ if err := eg.WriteAST(iprog.Fset, filename, file); err != nil {
+ fmt.Fprintf(os.Stderr, "eg: %s\n", err)
+ hadErrors = true
+ }
+ } else {
+ format.Node(os.Stdout, iprog.Fset, file)
+ }
+ }
+ }
+ if hadErrors {
+ os.Exit(1)
+ }
+ return nil
+}