func Walk(root string, walkFn filepath.WalkFunc) error {
	return fsWalk(root, root, walkFn)
}
Shortcut to fsWalk
package utils
import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"fmt"
	"errors"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"golang.org/x/tools/go/packages"
)
func DirExists(filename string) bool {
	fileInfo, err := os.Stat(filename)
	return err == nil && fileInfo.IsDir()
}
func MustReadLines(filename string) []string {
	r, err := ReadLines(filename)
	if err != nil {
		panic(err)
	}
	return r
}
func ReadLines(filename string) ([]string, error) {
	dataBytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(dataBytes), "\n"), nil
}
func CopyFile(destFilename, srcFilename string) (err error) {
	destFile, err := os.Create(destFilename)
	if err != nil {
		return NewBuildIfError(err, "Failed to create file", "file", destFilename)
	}
	srcFile, err := os.Open(srcFilename)
	if err != nil {
		return NewBuildIfError(err, "Failed to open file", "file", srcFilename)
	}
	_, err = io.Copy(destFile, srcFile)
	if err != nil {
		return NewBuildIfError(err, "Failed to copy data", "fromfile", srcFilename, "tofile", destFilename)
	}
	err = destFile.Close()
	if err != nil {
		return NewBuildIfError(err, "Failed to close file", "file", destFilename)
	}
	err = srcFile.Close()
	if err != nil {
		return NewBuildIfError(err, "Failed to close file", "file", srcFilename)
	}
	return
}
func GenerateTemplate(filename, templateSource string, args map[string]interface{}) (err error) {
	tmpl := template.Must(template.New("").Parse(templateSource))
	var b bytes.Buffer
	if err = tmpl.Execute(&b, args); err != nil {
		return NewBuildIfError(err, "ExecuteTemplate: Execute failed")
	}
	sourceCode := b.String()
	filePath := filepath.Dir(filename)
	if !DirExists(filePath) {
		err = os.MkdirAll(filePath, 0777)
		if err != nil && !os.IsExist(err) {
			return NewBuildIfError(err, "Failed to make directory", "dir", filePath)
		}
	}
	file, err := os.Create(filename)
	if err != nil {
		Logger.Fatal("Failed to create file", "error", err)
		return
	}
	defer func() {
		_ = file.Close()
	}()
	if _, err = file.WriteString(sourceCode); err != nil {
		Logger.Fatal("Failed to write to file: ", "error", err)
	}
	return
}
func RenderTemplate(destPath, srcPath string, data interface{}) (err error) {
	tmpl, err := template.ParseFiles(srcPath)
	if err != nil {
		return NewBuildIfError(err, "Failed to parse template " + srcPath)
	}
	f, err := os.Create(destPath)
	if err != nil {
		return NewBuildIfError(err, "Failed to create  ", "path", destPath)
	}
	err = tmpl.Execute(f, data)
	if err != nil {
		return NewBuildIfError(err, "Failed to Render template " + srcPath)
	}
	err = f.Close()
	if err != nil {
		return NewBuildIfError(err, "Failed to close file stream " + destPath)
	}
	return
}
func RenderTemplateToStream(output io.Writer, srcPath []string, data interface{}) (err error) {
	tmpl, err := template.ParseFiles(srcPath...)
	if err != nil {
		return NewBuildIfError(err, "Failed to parse template " + srcPath[0])
	}
	err = tmpl.Execute(output, data)
	if err != nil {
		return NewBuildIfError(err, "Failed to render template " + srcPath[0])
	}
	return
}
func MustChmod(filename string, mode os.FileMode) {
	err := os.Chmod(filename, mode)
	PanicOnError(err, fmt.Sprintf("Failed to chmod %d %q", mode, filename))
}
func PanicOnError(err error, msg string) {
	if revErr, ok := err.(*SourceError); (ok && revErr != nil) || (!ok && err != nil) {
		Logger.Panicf("Abort: %s: %s %s", msg, revErr, err)
	}
}
func CopyDir(destDir, srcDir string, data map[string]interface{}) error {
	if !DirExists(srcDir) {
		return nil
	}
	return fsWalk(srcDir, srcDir, func(srcPath string, info os.FileInfo, err error) error {
		relSrcPath := strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator))
		destPath := filepath.Join(destDir, relSrcPath)
		if strings.HasPrefix(relSrcPath, ".") {
			if info.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}
		if info.IsDir() {
			err := os.MkdirAll(filepath.Join(destDir, relSrcPath), 0777)
			if !os.IsExist(err) {
				return NewBuildIfError(err, "Failed to create directory", "path", destDir + "/" + relSrcPath)
			}
			return nil
		}
		if strings.HasSuffix(relSrcPath, ".template") {
			return RenderTemplate(destPath[:len(destPath) - len(".template")], srcPath, data)
		}
		return CopyFile(destPath, srcPath)
	})
}