github.com/aminjam/goflat@v0.4.1-0.20160331105230-ec639fc0d5b3/goflat.go (about) 1 package goflat 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "math/rand" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strings" 13 "time" 14 ) 15 16 //go:generate go run scripts/embed_runtime.go 17 18 //Flat struct 19 type Flat struct { 20 MainGo string 21 GoTemplate string 22 GoInputs []goInput 23 DefaultPipes string 24 CustomPipes string 25 26 goPath string 27 cmdEnv []string 28 } 29 30 //GoRun runs go on the dynamically created main.go with a given stdout and stderr pipe 31 func (f *Flat) GoRun(outWriter io.Writer, errWriter io.Writer) error { 32 err := f.validate() 33 if err != nil { 34 return err 35 } 36 f.setEnv() 37 err = f.goGetImports() 38 if err != nil { 39 return err 40 } 41 out := []string{"run", f.MainGo, f.DefaultPipes} 42 43 if f.CustomPipes != "" { 44 out = append(out, f.CustomPipes) 45 } 46 for _, v := range f.GoInputs { 47 out = append(out, v.Path) 48 } 49 cmd := exec.Command("go", out...) 50 cmd.Env = f.cmdEnv 51 cmd.Stdout = outWriter 52 cmd.Stderr = errWriter 53 54 return cmd.Run() 55 } 56 57 func (f *Flat) goGetImports() error { 58 out := []string{"get", "./..."} 59 cmd := exec.Command("go", out...) 60 cmd.Dir = f.goPath 61 cmd.Env = f.cmdEnv 62 63 writer := bytes.NewBufferString("") 64 cmd.Stdout = writer 65 cmd.Stderr = writer 66 err := cmd.Run() 67 if err != nil { 68 return errors.New(fmt.Sprintf("%s:%s", err.Error(), writer.String())) 69 } 70 return nil 71 } 72 73 func (f *Flat) setEnv() { 74 env := environ(os.Environ()) 75 old_gopath := os.Getenv("GOPATH") 76 if old_gopath != "" { 77 old_gopath = ":" + old_gopath 78 } 79 env.Unset("GOPATH") 80 gopath := fmt.Sprintf("GOPATH=%s%s", f.goPath, old_gopath) 81 f.cmdEnv = append(env, gopath) 82 } 83 84 func (f *Flat) validate() error { 85 msgs := []string{} 86 if f.MainGo == "" { 87 msgs = append(msgs, ErrMainGoUndefined) 88 } 89 if f.DefaultPipes == "" { 90 msgs = append(msgs, ErrDefaultPipesUndefined) 91 } 92 93 if len(msgs) > 0 { 94 return errors.New(strings.Join(msgs, ",")) 95 } 96 return nil 97 } 98 99 //goInput struct has the needed structure when parsing the `MainGotempl` 100 type goInput struct{ Path, StructName, VarName string } 101 102 //goInput initializer for a given path 103 func newGoInput(input string) goInput { 104 //optionally the structname can be passed via commandline with ":" seperator 105 if strings.Contains(input, ":") { 106 s := strings.Split(input, ":") 107 return goInput{Path: s[0], StructName: s[1]} 108 } 109 //goflat convention is to build a structname based on filename using strings Title convention 110 name := filepath.Base(input) 111 name = strings.Title(strings.Split(name, ".")[0]) 112 name = strings.Replace(name, "-", "", -1) 113 name = strings.Replace(name, "_", "", -1) 114 return goInput{ 115 Path: input, 116 StructName: name, 117 VarName: strings.ToLower(name), 118 } 119 } 120 121 // environ is a slice of strings representing the environment, in the form "key=value". 122 type environ []string 123 124 // Unset a single environment variable. 125 func (e *environ) Unset(key string) { 126 for i := range *e { 127 if strings.HasPrefix((*e)[i], key+"=") { 128 (*e)[i] = (*e)[len(*e)-1] 129 *e = (*e)[:len(*e)-1] 130 break 131 } 132 } 133 } 134 135 const ( 136 ErrMainGoUndefined = "(main func is missing)" 137 ErrDefaultPipesUndefined = "(default pipes file is missing)" 138 ) 139 140 func init() { 141 rand.Seed(time.Now().UTC().UnixNano()) 142 }