github.com/furusax0621/goa-v1@v1.4.3/goagen/codegen/helpers.go (about) 1 package codegen 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/build" 7 "os" 8 "path/filepath" 9 "strings" 10 "unicode" 11 12 "github.com/goadesign/goa/design" 13 "github.com/goadesign/goa/version" 14 ) 15 16 // CheckVersion returns an error if the ver is empty, contains an incorrect value or 17 // a version number that is not compatible with the version of this repo. 18 func CheckVersion(ver string) error { 19 compat, err := version.Compatible(ver) 20 if err != nil { 21 return err 22 } 23 if !compat { 24 return fmt.Errorf("version mismatch: using goagen %s to generate code that compiles with goa %s", 25 ver, version.String()) 26 } 27 return nil 28 } 29 30 // CommandLine return the command used to run this process. 31 func CommandLine() string { 32 // We don't use the full path to the tool so that running goagen multiple times doesn't 33 // end up creating different command line comments (because of the temporary directory it 34 // runs in). 35 var param string 36 37 if len(os.Args) > 1 { 38 args := make([]string, len(os.Args)-1) 39 gopaths := filepath.SplitList(envOr("GOPATH", build.Default.GOPATH)) 40 for i, a := range os.Args[1:] { 41 for _, p := range gopaths { 42 p = "=" + p 43 if strings.Contains(a, p) { 44 args[i] = strings.Replace(a, p, "=$(GOPATH)", 1) 45 break 46 } 47 } 48 if args[i] == "" { 49 args[i] = a 50 } 51 } 52 param = strings.Join(args, " ") 53 } 54 rawcmd := filepath.Base(os.Args[0]) 55 // Remove possible .exe suffix to not create different ouptut just because 56 // you ran goagen on Windows. 57 rawcmd = strings.TrimSuffix(rawcmd, ".exe") 58 59 cmd := fmt.Sprintf("$ %s %s", rawcmd, param) 60 return strings.Replace(cmd, " --", "\n\t--", -1) 61 } 62 63 // Copied from go/build/build.go 64 func envOr(name, def string) string { 65 s := os.Getenv(name) 66 if s == "" { 67 return def 68 } 69 return s 70 } 71 72 // Comment produces line comments by concatenating the given strings and producing 80 characters 73 // long lines starting with "//" 74 func Comment(elems ...string) string { 75 var lines []string 76 for _, e := range elems { 77 lines = append(lines, strings.Split(e, "\n")...) 78 } 79 var trimmed = make([]string, len(lines)) 80 for i, l := range lines { 81 trimmed[i] = strings.TrimLeft(l, " \t") 82 } 83 t := strings.Join(trimmed, "\n") 84 85 return Indent(t, "// ") 86 } 87 88 // Indent inserts prefix at the beginning of each non-empty line of s. The 89 // end-of-line marker is NL. 90 func Indent(s, prefix string) string { 91 return string(IndentBytes([]byte(s), []byte(prefix))) 92 } 93 94 // IndentBytes inserts prefix at the beginning of each non-empty line of b. 95 // The end-of-line marker is NL. 96 func IndentBytes(b, prefix []byte) []byte { 97 var res []byte 98 bol := true 99 for _, c := range b { 100 if bol && c != '\n' { 101 res = append(res, prefix...) 102 } 103 res = append(res, c) 104 bol = c == '\n' 105 } 106 return res 107 } 108 109 // Tabs returns a string made of depth tab characters. 110 func Tabs(depth int) string { 111 var tabs string 112 for i := 0; i < depth; i++ { 113 tabs += "\t" 114 } 115 // return fmt.Sprintf("%d%s", depth, tabs) 116 return tabs 117 } 118 119 // Add adds two integers and returns the sum of the two. 120 func Add(a, b int) int { return a + b } 121 122 // CanonicalTemplate returns the resource URI template as a format string suitable for use in the 123 // fmt.Printf function family. 124 func CanonicalTemplate(r *design.ResourceDefinition) string { 125 return design.WildcardRegex.ReplaceAllLiteralString(r.URITemplate(), "/%v") 126 } 127 128 // CanonicalParams returns the list of parameter names needed to build the canonical href to the 129 // resource. It returns nil if the resource does not have a canonical action. 130 func CanonicalParams(r *design.ResourceDefinition) []string { 131 var params []string 132 if ca := r.CanonicalAction(); ca != nil { 133 if len(ca.Routes) > 0 { 134 params = ca.Routes[0].Params() 135 } 136 for i, p := range params { 137 params[i] = Goify(p, false) 138 } 139 } 140 return params 141 } 142 143 // Casing exceptions 144 var toLower = map[string]string{"OAuth": "oauth"} 145 146 // SnakeCase produces the snake_case version of the given CamelCase string. 147 func SnakeCase(name string) string { 148 for u, l := range toLower { 149 name = strings.Replace(name, u, l, -1) 150 } 151 var b bytes.Buffer 152 var lastUnderscore bool 153 ln := len(name) 154 if ln == 0 { 155 return "" 156 } 157 b.WriteRune(unicode.ToLower(rune(name[0]))) 158 for i := 1; i < ln; i++ { 159 r := rune(name[i]) 160 nextIsLower := false 161 if i < ln-1 { 162 n := rune(name[i+1]) 163 nextIsLower = unicode.IsLower(n) && unicode.IsLetter(n) 164 } 165 if unicode.IsUpper(r) { 166 if !lastUnderscore && nextIsLower { 167 b.WriteRune('_') 168 lastUnderscore = true 169 } 170 b.WriteRune(unicode.ToLower(r)) 171 } else { 172 b.WriteRune(r) 173 lastUnderscore = false 174 } 175 } 176 return b.String() 177 } 178 179 // KebabCase produces the kebab-case version of the given CamelCase string. 180 func KebabCase(name string) string { 181 name = SnakeCase(name) 182 return strings.Replace(name, "_", "-", -1) 183 }