package template import ( "io" "io/ioutil" "log" "os" "path/filepath" "strings" "text/template" "forge.cadoles.com/wpetit/scaffold/internal/fs" "gopkg.in/src-d/go-billy.v4" "github.com/Masterminds/sprig" "github.com/pkg/errors" ) func CopyDir(vfs billy.Filesystem, baseDir string, dst string, opts *Option) error { if opts == nil { opts = &Option{} } baseDir = filepath.Clean(baseDir) dst = filepath.Clean(dst) _, err := os.Stat(dst) if err != nil && !os.IsNotExist(err) { return err } if err := os.MkdirAll(dst, 0755); err != nil { return errors.Wrapf(err, "could not create directory '%s'", dst) } err = fs.Walk(vfs, baseDir, func(srcPath string, info os.FileInfo, err error) error { if err != nil { return err } if srcPath == baseDir { return nil } for _, p := range opts.IgnorePatterns { match, err := filepath.Match(p, srcPath) if err != nil { return errors.Wrap(err, "could not match ignored file") } if match { log.Printf("Ignoring %s.", srcPath) return nil } } relSrcPath, err := filepath.Rel(baseDir, srcPath) if err != nil { return err } dstPath := filepath.Join(dst, relSrcPath) if info.IsDir() { log.Printf("creating dir '%s'", dstPath) if err := os.MkdirAll(dstPath, 0755); err != nil { return errors.Wrapf(err, "could not create directory '%s'", dstPath) } return nil } err = CopyFile(vfs, srcPath, dstPath, opts) if err != nil { return errors.Wrapf(err, "could not copy file '%s'", srcPath) } return nil }) if err != nil { return errors.Wrapf(err, "could not walk source directory '%s'", baseDir) } return nil } func CopyFile(vfs billy.Filesystem, src, dst string, opts *Option) (err error) { if opts == nil { opts = &Option{} } if !strings.HasSuffix(src, opts.TemplateExt) { return copyFile(vfs, src, dst) } in, err := vfs.Open(src) if err != nil { return err } defer in.Close() templateData, err := ioutil.ReadAll(in) if err != nil { return err } tmpl, err := template.New(filepath.Base(src)).Funcs(sprig.TxtFuncMap()).Parse(string(templateData)) if err != nil { return err } dst = strings.TrimSuffix(dst, opts.TemplateExt) log.Printf("templating file from '%s' to '%s'", src, dst) out, err := os.Create(dst) if err != nil { return err } defer func() { if e := out.Close(); e != nil { err = e } }() opts.TemplateData["SourceFile"] = src opts.TemplateData["DestFile"] = dst if err := tmpl.Execute(out, opts.TemplateData); err != nil { return err } return nil } func copyFile(vfs billy.Filesystem, src, dst string) (err error) { log.Printf("copying file '%s' to '%s'", src, dst) in, err := vfs.Open(src) if err != nil { return err } defer in.Close() out, err := os.Create(dst) if err != nil { return err } defer func() { if e := out.Close(); e != nil { err = e } }() _, err = io.Copy(out, in) if err != nil { return err } err = out.Sync() if err != nil { return err } return nil }