github.com/bketelsen/buffalo@v0.9.5/generators/helpers.go (about)

     1  package generators
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"go/ast"
     7  	"go/parser"
     8  	"go/token"
     9  	"io/ioutil"
    10  	"strings"
    11  )
    12  
    13  // AddRoute adds a new route inside the `action/app.go` file.
    14  func AddRoute(method, path, handlerName string) error {
    15  	routeDefinition := fmt.Sprintf(`app.%v("%v", %v)`, method, path, handlerName)
    16  	return AddInsideAppBlock(routeDefinition)
    17  }
    18  
    19  // AddInsideAppBlock will add anything inside of the app declaration block inside of `actions/app.go`
    20  func AddInsideAppBlock(expressions ...string) error {
    21  	src, err := ioutil.ReadFile("actions/app.go")
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	fset := token.NewFileSet()
    27  	f, err := parser.ParseFile(fset, "actions/app.go", string(src), 0)
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	srcContent := string(src)
    33  	fileLines := strings.Split(srcContent, "\n")
    34  
    35  	end := findClosingRouteBlockEnd(f, fset, fileLines)
    36  	if end < 0 {
    37  		return errors.New("could not find desired block on the app.go file")
    38  	}
    39  
    40  	for i := 0; i < len(expressions); i++ {
    41  		expressions[i] = fmt.Sprintf("\t\t%s", expressions[i])
    42  	}
    43  	fileLines = append(fileLines[:end], append(expressions, fileLines[end:]...)...)
    44  
    45  	fileContent := strings.Join(fileLines, "\n")
    46  	err = ioutil.WriteFile("actions/app.go", []byte(fileContent), 0755)
    47  	return err
    48  }
    49  
    50  func findClosingRouteBlockEnd(f *ast.File, fset *token.FileSet, fileLines []string) int {
    51  	var end = -1
    52  
    53  	ast.Inspect(f, func(n ast.Node) bool {
    54  		switch x := n.(type) {
    55  		case *ast.BlockStmt:
    56  			start := fset.Position(x.Lbrace).Line
    57  			blockDeclaration := fmt.Sprintf("%s\n", fileLines[start-1])
    58  
    59  			if strings.Contains(blockDeclaration, "if app == nil {") {
    60  				end = fset.Position(x.Rbrace).Line - 1
    61  			}
    62  
    63  		}
    64  		return true
    65  	})
    66  
    67  	return end
    68  }
    69  
    70  // AddImport adds n number of import statements into the path provided
    71  func AddImport(path string, imports ...string) error {
    72  	src, err := ioutil.ReadFile(path)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	fset := token.NewFileSet()
    78  	f, err := parser.ParseFile(fset, path, string(src), 0)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	srcContent := string(src)
    84  	fileLines := strings.Split(srcContent, "\n")
    85  
    86  	end := findLastImport(f, fset, fileLines)
    87  
    88  	x := make([]string, len(imports), len(imports)+2)
    89  	for _, i := range imports {
    90  		x = append(x, fmt.Sprintf("\t\"%s\"", i))
    91  
    92  	}
    93  	if end < 0 {
    94  		x = append([]string{"import ("}, x...)
    95  		x = append(x, ")")
    96  	}
    97  
    98  	fileLines = append(fileLines[:end], append(x, fileLines[end:]...)...)
    99  
   100  	fileContent := strings.Join(fileLines, "\n")
   101  	err = ioutil.WriteFile(path, []byte(fileContent), 0755)
   102  	return err
   103  }
   104  
   105  func findLastImport(f *ast.File, fset *token.FileSet, fileLines []string) int {
   106  	var end = -1
   107  
   108  	ast.Inspect(f, func(n ast.Node) bool {
   109  		switch x := n.(type) {
   110  		case *ast.ImportSpec:
   111  			end = fset.Position(x.End()).Line
   112  			return true
   113  		}
   114  		return true
   115  	})
   116  
   117  	return end
   118  }