github.com/singlemusic/buffalo@v0.16.30/buffalo/cmd/fix/imports.go (about)

     1  package fix
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/parser"
     7  	"go/token"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"golang.org/x/tools/go/ast/astutil"
    14  )
    15  
    16  // ImportConverter will changes imports from a -> b
    17  type ImportConverter struct {
    18  	Data map[string]string
    19  }
    20  
    21  // Process will walk all the .go files in an application, excluding ./vendor.
    22  // It will then attempt to convert any old import paths to any new import paths
    23  // used by this version Buffalo.
    24  func (c ImportConverter) Process(r *Runner) error {
    25  	fmt.Println("~~~ Rewriting Imports ~~~")
    26  
    27  	return filepath.Walk(".", c.processFile)
    28  
    29  }
    30  
    31  func (c ImportConverter) processFile(p string, info os.FileInfo, err error) error {
    32  	er := onlyRelevantFiles(p, info, err, func(p string) error {
    33  		return c.rewriteFile(p)
    34  	})
    35  
    36  	return er
    37  }
    38  
    39  func (c ImportConverter) rewriteFile(name string) error {
    40  
    41  	// create an empty fileset.
    42  	fset := token.NewFileSet()
    43  
    44  	// parse the .go file.
    45  	// we are parsing the entire file with comments, so we don't lose anything
    46  	// if we need to write it back out.
    47  	f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
    48  	if err != nil {
    49  		e := err.Error()
    50  		msg := "expected 'package', found 'EOF'"
    51  		if e[len(e)-len(msg):] == msg {
    52  			return nil
    53  		}
    54  		return err
    55  	}
    56  
    57  	changed := false
    58  	for key, value := range c.Data {
    59  		if !astutil.DeleteImport(fset, f, key) {
    60  			continue
    61  		}
    62  
    63  		astutil.AddImport(fset, f, value)
    64  		changed = true
    65  	}
    66  
    67  	commentsChanged, err := c.handleFileComments(f)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	changed = changed || commentsChanged
    73  
    74  	// if no change occurred, then we don't need to write to disk, just return.
    75  	if !changed {
    76  		return nil
    77  	}
    78  
    79  	// since the imports changed, resort them.
    80  	ast.SortImports(fset, f)
    81  
    82  	// create a temporary file, this easily avoids conflicts.
    83  	temp, err := writeTempResult(name, fset, f)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	// rename the .temp to .go
    89  	return os.Rename(temp, name)
    90  }
    91  
    92  func (c ImportConverter) handleFileComments(f *ast.File) (bool, error) {
    93  	change := false
    94  
    95  	for _, cg := range f.Comments {
    96  		for _, cl := range cg.List {
    97  			if !strings.HasPrefix(cl.Text, "// import \"") {
    98  				continue
    99  			}
   100  
   101  			// trim off extra comment stuff
   102  			ctext := cl.Text
   103  			ctext = strings.TrimPrefix(ctext, "// import")
   104  			ctext = strings.TrimSpace(ctext)
   105  
   106  			// unquote the comment import path value
   107  			ctext, err := strconv.Unquote(ctext)
   108  			if err != nil {
   109  				return false, err
   110  			}
   111  
   112  			// match the comment import path with the given replacement map
   113  			if ctext, ok := c.match(ctext); ok {
   114  				cl.Text = "// import " + strconv.Quote(ctext)
   115  				change = true
   116  			}
   117  
   118  		}
   119  	}
   120  
   121  	return change, nil
   122  }
   123  
   124  // match takes an import path and replacement map.
   125  func (c ImportConverter) match(importpath string) (string, bool) {
   126  	for key, value := range c.Data {
   127  		if !strings.HasPrefix(importpath, key) {
   128  			continue
   129  		}
   130  
   131  		result := strings.Replace(importpath, key, value, 1)
   132  		return result, true
   133  	}
   134  
   135  	return importpath, false
   136  }