github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/cmd/gstack/utils/utils.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/parser" 7 "go/token" 8 "io" 9 "io/fs" 10 "os" 11 "path/filepath" 12 13 "github.com/ydb-platform/ydb-go-sdk/v3/internal/version" 14 ) 15 16 type FunctionIDArg struct { 17 FuncDecl *ast.FuncDecl 18 ArgPos token.Pos 19 ArgEnd token.Pos 20 } 21 22 func ReadFile(filename string, info fs.FileInfo) ([]byte, error) { 23 f, err := os.Open(filename) 24 if err != nil { 25 return nil, err 26 } 27 defer f.Close() 28 size := int(info.Size()) 29 src := make([]byte, size) 30 n, err := io.ReadFull(f, src) 31 if err != nil { 32 return nil, err 33 } 34 if n < size { 35 return nil, fmt.Errorf("error: size of %q changed during reading (from %d to %d bytes)", filename, size, n) 36 } else if n > size { 37 return nil, fmt.Errorf("error: size of %q changed during reading (from %d to >=%d bytes)", filename, size, len(src)) 38 } 39 40 return src, nil 41 } 42 43 func FixSource(fset *token.FileSet, path string, src []byte, listOfArgs []FunctionIDArg) ([]byte, error) { 44 var fixed []byte 45 var previousArgEnd int 46 for _, arg := range listOfArgs { 47 argPosOffset := fset.Position(arg.ArgPos).Offset 48 argEndOffset := fset.Position(arg.ArgEnd).Offset 49 argument, err := makeCall(fset, path, arg) 50 if err != nil { 51 return nil, err 52 } 53 fixed = append(fixed, src[previousArgEnd:argPosOffset]...) 54 fixed = append(fixed, fmt.Sprintf("%q", argument)...) 55 previousArgEnd = argEndOffset 56 } 57 fixed = append(fixed, src[previousArgEnd:]...) 58 59 return fixed, nil 60 } 61 62 func WriteFile(filename string, formatted []byte, perm fs.FileMode) error { 63 fout, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, perm) 64 if err != nil { 65 return err 66 } 67 68 defer fout.Close() 69 70 _, err = fout.Write(formatted) 71 if err != nil { 72 return err 73 } 74 75 return nil 76 } 77 78 func makeCall(fset *token.FileSet, path string, arg FunctionIDArg) (string, error) { 79 basePath := filepath.Join("github.com", "ydb-platform", version.Package, "v"+version.Major, "") 80 packageName, err := getPackageName(fset, arg) 81 if err != nil { 82 return "", err 83 } 84 filePath := filepath.Dir(filepath.Dir(path)) 85 funcName, err := getFuncName(arg.FuncDecl) 86 if err != nil { 87 return "", err 88 } 89 90 return filepath.Join(basePath, filePath, packageName) + "." + funcName, nil 91 } 92 93 func getFuncName(funcDecl *ast.FuncDecl) (string, error) { 94 if funcDecl.Recv != nil { 95 recvType := funcDecl.Recv.List[0].Type 96 prefix, err := getIdentNameFromExpr(recvType) 97 if err != nil { 98 return "", err 99 } 100 101 return prefix + "." + funcDecl.Name.Name, nil 102 } 103 104 return funcDecl.Name.Name, nil 105 } 106 107 func getIdentNameFromExpr(expr ast.Expr) (string, error) { 108 switch expr := expr.(type) { 109 case *ast.Ident: 110 return expr.Name, nil 111 case *ast.StarExpr: 112 prefix, err := getIdentNameFromExpr(expr.X) 113 if err != nil { 114 return "", err 115 } 116 117 return "(*" + prefix + ")", nil 118 case *ast.IndexExpr: 119 return getIdentNameFromExpr(expr.X) 120 case *ast.IndexListExpr: 121 return getIdentNameFromExpr(expr.X) 122 default: 123 return "", fmt.Errorf("error during getting ident from expr") 124 } 125 } 126 127 func getPackageName(fset *token.FileSet, arg FunctionIDArg) (string, error) { 128 file := fset.File(arg.ArgPos) 129 parsedFile, err := parser.ParseFile(fset, file.Name(), nil, parser.PackageClauseOnly) 130 if err != nil { 131 return "", fmt.Errorf("error during get package name function") 132 } 133 134 return parsedFile.Name.Name, nil 135 }