208 lines
3.8 KiB
Go
208 lines
3.8 KiB
Go
package template
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"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/mattn/go-zglob"
|
|
"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 := zglob.Match(p, strings.TrimPrefix(srcPath, "./"))
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not match ignored file")
|
|
}
|
|
if match {
|
|
fmt.Printf("Ignoring %s.\n", srcPath)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
relSrcPath, err := filepath.Rel(baseDir, srcPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dstPath := filepath.Join(dst, relSrcPath)
|
|
|
|
if info.IsDir() {
|
|
fmt.Printf("Creating dir '%s'.\n", 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{}
|
|
}
|
|
|
|
stat, err := os.Stat(dst)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
|
|
// If dst exists
|
|
if stat != nil {
|
|
strategy := opts.PreferredStrategy
|
|
|
|
if opts.Unnattended && opts.PreferredStrategy == -1 {
|
|
strategy = defaultStrategy
|
|
}
|
|
|
|
if opts.PreferredStrategy == -1 {
|
|
var useAsPreferredStrategy bool
|
|
|
|
strategy, useAsPreferredStrategy, err = askOverwriteStrategy(dst)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not ask for overwrite strategy")
|
|
}
|
|
|
|
if useAsPreferredStrategy {
|
|
opts.PreferredStrategy = strategy
|
|
}
|
|
}
|
|
|
|
switch strategy {
|
|
case CopyAsDist:
|
|
fmt.Printf("Using '%s.dist' as destination file.\n", dst)
|
|
dst += ".dist"
|
|
case DoNotCopy:
|
|
fmt.Printf("Skipping existing file '%s'.\n", dst)
|
|
return nil
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
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)
|
|
|
|
fmt.Printf("Templating file from '%s' to '%s'.\n", 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) {
|
|
fmt.Printf("Copying file '%s' to '%s'.\n", 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
|
|
}
|