github.com/aminjam/goflat@v0.4.1-0.20160331105230-ec639fc0d5b3/goflatbuilder.go (about)

     1  package goflat
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"math/rand"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"text/template"
    12  )
    13  
    14  //Builder pattern seems to be the most appropriate structure for building a `Flat` struct
    15  type FlatBuilder interface {
    16  	EvalGoInputs(files []string) error
    17  	EvalGoPipes(file string) error
    18  	EvalMainGo() error
    19  	Flat() *Flat
    20  }
    21  
    22  type flatBuilder struct {
    23  	flat    *Flat
    24  	baseDir string
    25  }
    26  
    27  func (builder *flatBuilder) cp(file string) (string, error) {
    28  	outFile := filepath.Join(builder.baseDir, nameGenerator())
    29  	in, err := os.Open(file)
    30  	if err != nil {
    31  		return "", err
    32  	}
    33  	defer in.Close()
    34  	out, err := os.Create(outFile)
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  	defer out.Close()
    39  	_, err = io.Copy(out, in)
    40  	cerr := out.Close()
    41  	if err != nil {
    42  		return "", err
    43  	}
    44  	return outFile, cerr
    45  }
    46  
    47  func (builder *flatBuilder) EvalGoInputs(files []string) error {
    48  	builder.flat.GoInputs = make([]goInput, len(files))
    49  	for k, v := range files {
    50  		gi := newGoInput(v)
    51  		file, err := builder.cp(gi.Path)
    52  		if err != nil {
    53  			return fmt.Errorf("%s:%s", ErrMissingOnDisk, err.Error())
    54  		}
    55  		gi.Path = file
    56  		builder.flat.GoInputs[k] = gi
    57  	}
    58  	return nil
    59  }
    60  
    61  func (builder *flatBuilder) EvalGoPipes(file string) error {
    62  	defaultPipes, err := builder.defaultPipes()
    63  	if err != nil {
    64  		return err
    65  	}
    66  	builder.flat.DefaultPipes = defaultPipes
    67  
    68  	if file != "" {
    69  		customPipes, err := builder.cp(file)
    70  		if err != nil {
    71  			return fmt.Errorf("%s:%s", ErrMissingOnDisk, err.Error())
    72  		}
    73  		builder.flat.CustomPipes = customPipes
    74  	}
    75  	return nil
    76  }
    77  
    78  func (builder *flatBuilder) EvalMainGo() error {
    79  	outFile := filepath.Join(builder.baseDir, nameGenerator())
    80  	main, err := os.Create(outFile)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer main.Close()
    85  
    86  	var tmpl = template.Must(template.New("main").Parse(MainGotempl))
    87  	if err := tmpl.Execute(main, builder.flat); err != nil {
    88  		return err
    89  	}
    90  	builder.flat.MainGo = outFile
    91  	return nil
    92  }
    93  
    94  func (builder *flatBuilder) Flat() *Flat {
    95  	return builder.flat
    96  }
    97  
    98  //NewFlatBuilder initializes a new instance of `FlatBuilder` interface
    99  func NewFlatBuilder(baseDir, template string) (FlatBuilder, error) {
   100  	if _, err := os.Stat(baseDir); err != nil {
   101  		return nil, fmt.Errorf("%s:%s", ErrMissingOnDisk, err.Error())
   102  	}
   103  	if _, err := os.Stat(template); err != nil {
   104  		return nil, fmt.Errorf("%s:%s", ErrMissingOnDisk, err.Error())
   105  	}
   106  
   107  	src_dir := filepath.Join(baseDir, "src")
   108  	os.MkdirAll(src_dir, 0777)
   109  
   110  	goflatDir, _ := ioutil.TempDir(src_dir, "goflat")
   111  	goPath, _ := filepath.Abs(baseDir)
   112  	builder := &flatBuilder{
   113  		baseDir: goflatDir,
   114  		flat: &Flat{
   115  			GoTemplate: template,
   116  			goPath:     goPath,
   117  		},
   118  	}
   119  
   120  	return builder, nil
   121  }
   122  
   123  func (builder *flatBuilder) defaultPipes() (string, error) {
   124  	content := strings.Replace(PipesGo, "package runtime", "package main", -1)
   125  	outFile := filepath.Join(builder.baseDir, nameGenerator())
   126  	err := ioutil.WriteFile(outFile, []byte(content), 0666)
   127  	if err != nil {
   128  		return "", err
   129  	}
   130  	return outFile, nil
   131  }
   132  
   133  func nameGenerator() string {
   134  	var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
   135  
   136  	size := 10
   137  	buf := make([]byte, size)
   138  	for i := 0; i < size; i++ {
   139  		buf[i] = alpha[rand.Intn(len(alpha))]
   140  	}
   141  	return string(buf) + ".go"
   142  }
   143  
   144  const (
   145  	//ErrMissingOnDisk Expected error for accessing invalid file or directory
   146  	ErrMissingOnDisk = "(file or directory is missing)"
   147  )