goldsmith/file.go

207 lines
3.3 KiB
Go
Raw Normal View History

2015-12-18 04:14:39 +00:00
package goldsmith
import (
"bytes"
2018-12-08 19:18:51 +00:00
"hash/crc32"
2015-12-18 04:14:39 +00:00
"io"
"io/ioutil"
"os"
"path"
2016-01-13 04:12:50 +00:00
"path/filepath"
2018-12-08 19:18:51 +00:00
"strings"
2016-06-11 23:24:06 +00:00
"time"
2015-12-18 04:14:39 +00:00
)
2018-12-08 19:18:51 +00:00
type File struct {
sourcePath string
dataPath string
2016-01-01 08:47:28 +00:00
Meta map[string]interface{}
2015-12-18 07:06:28 +00:00
2018-12-08 19:18:51 +00:00
hashValue uint32
hashValid bool
2016-06-11 23:24:06 +00:00
reader *bytes.Reader
size int64
modTime time.Time
2018-12-08 19:18:51 +00:00
}
2016-06-11 23:24:06 +00:00
2018-12-08 19:18:51 +00:00
func (f *File) Path() string {
return f.sourcePath
2015-12-18 04:14:39 +00:00
}
2018-12-08 19:18:51 +00:00
func (f *File) Name() string {
return path.Base(f.sourcePath)
}
func (f *File) Dir() string {
return path.Dir(f.sourcePath)
}
func (f *File) Ext() string {
return path.Ext(f.sourcePath)
}
func (f *File) Size() int64 {
return f.size
}
func (f *File) ModTime() time.Time {
return f.modTime
}
func (f *File) Read(data []byte) (int, error) {
if err := f.load(); err != nil {
return 0, err
}
return f.reader.Read(data)
}
func (f *File) WriteTo(writer io.Writer) (int64, error) {
if err := f.load(); err != nil {
return 0, err
}
return f.reader.WriteTo(writer)
}
func (f *File) Seek(offset int64, whence int) (int64, error) {
if f.reader == nil && offset == 0 && (whence == os.SEEK_SET || whence == os.SEEK_CUR) {
return 0, nil
}
if err := f.load(); err != nil {
return 0, err
}
return f.reader.Seek(offset, whence)
}
type FilesByPath []*File
func (f FilesByPath) Len() int {
return len(f)
}
func (f FilesByPath) Swap(i, j int) {
f[i], f[j] = f[j], f[i]
}
func (f FilesByPath) Less(i, j int) bool {
return strings.Compare(f[i].Path(), f[j].Path()) < 0
}
func (f *File) export(targetDir string) error {
targetPath := filepath.Join(targetDir, f.sourcePath)
if targetInfo, err := os.Stat(targetPath); err == nil && targetInfo.ModTime().After(f.ModTime()) {
return nil
}
2018-12-08 19:18:51 +00:00
if err := os.MkdirAll(path.Dir(targetPath), 0755); err != nil {
2015-12-18 04:14:39 +00:00
return err
}
2018-12-08 19:18:51 +00:00
fw, err := os.Create(targetPath)
2015-12-18 04:14:39 +00:00
if err != nil {
return err
}
2015-12-18 10:49:52 +00:00
defer fw.Close()
if f.reader == nil {
2018-12-08 19:18:51 +00:00
fr, err := os.Open(f.dataPath)
2015-12-18 10:49:52 +00:00
if err != nil {
return err
}
defer fr.Close()
if _, err := io.Copy(fw, fr); err != nil {
return err
}
} else {
2015-12-20 14:18:58 +00:00
if _, err := f.Seek(0, os.SEEK_SET); err != nil {
return err
}
2018-12-08 19:18:51 +00:00
2015-12-18 10:49:52 +00:00
if _, err := f.WriteTo(fw); err != nil {
return err
}
2015-12-18 04:14:39 +00:00
}
return nil
}
2018-12-08 19:18:51 +00:00
func (f *File) load() error {
2015-12-18 10:19:43 +00:00
if f.reader != nil {
2015-12-18 04:14:39 +00:00
return nil
}
2018-12-08 19:18:51 +00:00
data, err := ioutil.ReadFile(f.dataPath)
2015-12-18 04:14:39 +00:00
if err != nil {
return err
}
2015-12-20 08:38:53 +00:00
f.reader = bytes.NewReader(data)
2015-12-18 04:14:39 +00:00
return nil
}
2018-12-08 19:18:51 +00:00
func (f *File) hash() (uint32, error) {
if f.hashValid {
return f.hashValue, nil
}
2016-06-11 23:24:06 +00:00
2018-12-08 19:18:51 +00:00
if err := f.load(); err != nil {
return 0, err
}
2016-06-11 23:24:06 +00:00
2018-12-08 19:18:51 +00:00
offset, err := f.Seek(0, os.SEEK_CUR)
if err != nil {
return 0, err
}
2015-12-18 04:14:39 +00:00
2018-12-08 19:18:51 +00:00
if _, err := f.Seek(0, os.SEEK_SET); err != nil {
return 0, err
}
2015-12-29 12:08:41 +00:00
2018-12-08 19:18:51 +00:00
hasher := crc32.NewIEEE()
if _, err := io.Copy(hasher, f.reader); err != nil {
return 0, err
2015-12-19 12:14:16 +00:00
}
2018-12-08 19:18:51 +00:00
if _, err := f.Seek(offset, os.SEEK_SET); err != nil {
2015-12-18 04:14:39 +00:00
return 0, err
}
2018-12-08 19:18:51 +00:00
f.hashValue = hasher.Sum32()
f.hashValid = true
return f.hashValue, nil
2015-12-18 07:06:28 +00:00
}
2018-12-08 19:18:51 +00:00
type fileInfo struct {
os.FileInfo
path string
}
func cleanPath(path string) string {
if filepath.IsAbs(path) {
var err error
if path, err = filepath.Rel("/", path); err != nil {
panic(err)
}
2015-12-18 07:06:28 +00:00
}
2018-12-08 19:18:51 +00:00
return filepath.Clean(path)
2015-12-18 07:06:28 +00:00
}
2015-12-20 14:18:58 +00:00
2018-12-08 19:18:51 +00:00
func scanDir(rootDir string, infos chan fileInfo) {
defer close(infos)
2015-12-20 14:18:58 +00:00
2018-12-08 19:18:51 +00:00
filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if err == nil {
infos <- fileInfo{FileInfo: info, path: path}
}
2015-12-20 14:18:58 +00:00
2018-12-08 19:18:51 +00:00
return err
})
2015-12-20 14:18:58 +00:00
}