github.com/goonzoid/gcli@v0.2.3-0.20150926213610-155587606ea1/skeleton/template.go (about)

     1  package skeleton
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"text/template"
    10  
    11  	"github.com/tcnksm/gcli/helper"
    12  )
    13  
    14  // Template stores meta data of template
    15  type Template struct {
    16  	// Path is the path to this template.
    17  	Path string
    18  
    19  	// OutputPathTmpl is the template for outputPath.
    20  	OutputPathTmpl string
    21  }
    22  
    23  // Exec evaluate this template and write it to provided file.
    24  // At First, it reads template content.
    25  // Then, it generates output file path from output path template and its data.
    26  // Then, it creates directory if not exist from output path.
    27  // Then, it opens output file.
    28  // Finally, it evaluates template contents and generate it to output file.
    29  // If output file is gocode, run go fmt.
    30  //
    31  // It returns an error if any.
    32  func (t *Template) Exec(data interface{}) (string, error) {
    33  	// Asset function is generated by go-bindata
    34  	contents, err := Asset(t.Path)
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  
    39  	outputPath, err := processPathTmpl(t.OutputPathTmpl, data)
    40  	if err != nil {
    41  		return "", err
    42  	}
    43  
    44  	// Create directory if necessary
    45  	dir, _ := filepath.Split(outputPath)
    46  	if dir != "" {
    47  		if err := mkdir(dir); err != nil {
    48  			return "", err
    49  		}
    50  	}
    51  
    52  	wr, err := os.Create(outputPath)
    53  	if err != nil {
    54  		return "", err
    55  	}
    56  
    57  	if err := execute(string(contents), wr, data); err != nil {
    58  		return "", err
    59  	}
    60  
    61  	if strings.HasSuffix(outputPath, ".go") {
    62  		helper.GoFmt(outputPath, nil)
    63  	}
    64  
    65  	return outputPath, nil
    66  }
    67  
    68  // processPathTmpl evaluates output path template string
    69  // and generate real absolute path. Any errors that occur are returned.
    70  func processPathTmpl(pathTmpl string, data interface{}) (string, error) {
    71  	var outputPathBuf bytes.Buffer
    72  	if err := execute(pathTmpl, &outputPathBuf, data); err != nil {
    73  		return "", err
    74  	}
    75  
    76  	return outputPathBuf.String(), nil
    77  }
    78  
    79  // mkdir makes the named directory.
    80  func mkdir(dir string) error {
    81  	if _, err := os.Stat(dir); err == nil {
    82  		return nil
    83  	}
    84  
    85  	return os.MkdirAll(dir, 0777)
    86  }
    87  
    88  // execute evaluates template content with data
    89  // and write them to writer.
    90  func execute(content string, wr io.Writer, data interface{}) error {
    91  	name := ""
    92  	funcs := funcMap()
    93  
    94  	tmpl, err := template.New(name).Funcs(funcs).Parse(content)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	if err := tmpl.Execute(wr, data); err != nil {
   100  		return err
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  func funcMap() template.FuncMap {
   107  	return template.FuncMap{
   108  		"date":    dateFunc(),
   109  		"title":   strings.Title,
   110  		"toUpper": strings.ToUpper,
   111  	}
   112  }