github.com/fedir/buffalo@v0.11.1/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  	el := fileLines[end:]
    41  	sl := []string{}
    42  	sf := []string{}
    43  	for _, l := range fileLines[:end] {
    44  		// if there's a app.ServeFiles("/", foo) line it needs to be the last added to the router
    45  		if strings.Contains(l, "ServeFiles(\"/\"") {
    46  			sf = append(sf, l)
    47  			continue
    48  		}
    49  		sl = append(sl, l)
    50  	}
    51  
    52  	for i := 0; i < len(expressions); i++ {
    53  		expressions[i] = fmt.Sprintf("\t\t%s", expressions[i])
    54  	}
    55  
    56  	el = append(sf, el...)
    57  	fileLines = append(sl, append(expressions, el...)...)
    58  
    59  	fileContent := strings.Join(fileLines, "\n")
    60  	err = ioutil.WriteFile("actions/app.go", []byte(fileContent), 0755)
    61  	return err
    62  }
    63  
    64  func findClosingRouteBlockEnd(f *ast.File, fset *token.FileSet, fileLines []string) int {
    65  	var end = -1
    66  
    67  	ast.Inspect(f, func(n ast.Node) bool {
    68  		switch x := n.(type) {
    69  		case *ast.BlockStmt:
    70  			start := fset.Position(x.Lbrace).Line
    71  			blockDeclaration := fmt.Sprintf("%s\n", fileLines[start-1])
    72  
    73  			if strings.Contains(blockDeclaration, "if app == nil {") {
    74  				end = fset.Position(x.Rbrace).Line - 1
    75  			}
    76  
    77  		}
    78  		return true
    79  	})
    80  
    81  	return end
    82  }
    83  
    84  // AddImport adds n number of import statements into the path provided
    85  func AddImport(path string, imports ...string) error {
    86  	src, err := ioutil.ReadFile(path)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	fset := token.NewFileSet()
    92  	f, err := parser.ParseFile(fset, path, string(src), 0)
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	srcContent := string(src)
    98  	fileLines := strings.Split(srcContent, "\n")
    99  
   100  	end := findLastImport(f, fset, fileLines)
   101  
   102  	x := make([]string, len(imports), len(imports)+2)
   103  	for _, i := range imports {
   104  		x = append(x, fmt.Sprintf("\t\"%s\"", i))
   105  
   106  	}
   107  	if end < 0 {
   108  		x = append([]string{"import ("}, x...)
   109  		x = append(x, ")")
   110  	}
   111  
   112  	fileLines = append(fileLines[:end], append(x, fileLines[end:]...)...)
   113  
   114  	fileContent := strings.Join(fileLines, "\n")
   115  	err = ioutil.WriteFile(path, []byte(fileContent), 0755)
   116  	return err
   117  }
   118  
   119  func findLastImport(f *ast.File, fset *token.FileSet, fileLines []string) int {
   120  	var end = -1
   121  
   122  	ast.Inspect(f, func(n ast.Node) bool {
   123  		switch x := n.(type) {
   124  		case *ast.ImportSpec:
   125  			end = fset.Position(x.End()).Line
   126  			return true
   127  		}
   128  		return true
   129  	})
   130  
   131  	return end
   132  }