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  }