package pkger import ( "encoding/json" "fmt" "os" "strings" "time" ) type FileInfo struct { name string size int64 mode os.FileMode modTime time.Time isDir bool virtual bool sys interface{} } func (f *FileInfo) String() string { b, _ := json.MarshalIndent(f, "", " ") return string(b) } func (f *FileInfo) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]interface{}{ "name": f.name, "size": f.size, "mode": f.mode, "modTime": f.modTime.Format(timeFmt), "isDir": f.isDir, "virtual": true, "sys": f.sys, }) } func (f *FileInfo) UnmarshalJSON(b []byte) error { m := map[string]interface{}{} if err := json.Unmarshal(b, &m); err != nil { return err } var ok bool f.name, ok = m["name"].(string) if !ok { return fmt.Errorf("could not determine name %q", m["name"]) } size, ok := m["size"].(float64) if !ok { return fmt.Errorf("could not determine size %q", m["size"]) } f.size = int64(size) mode, ok := m["mode"].(float64) if !ok { return fmt.Errorf("could not determine mode %q", m["mode"]) } f.mode = os.FileMode(mode) modTime, ok := m["modTime"].(string) if !ok { return fmt.Errorf("could not determine modTime %q", m["modTime"]) } t, err := time.Parse(timeFmt, modTime) if err != nil { return err } f.modTime = t f.isDir, ok = m["isDir"].(bool) if !ok { return fmt.Errorf("could not determine isDir %q", m["isDir"]) } f.sys = m["sys"] f.virtual = true return nil } func (f *FileInfo) Name() string { return f.name } func (f *FileInfo) Size() int64 { return f.size } func (f *FileInfo) Mode() os.FileMode { return f.mode } func (f *FileInfo) ModTime() time.Time { return f.modTime } func (f *FileInfo) IsDir() bool { return f.isDir } func (f *FileInfo) Sys() interface{} { return f.sys } var _ os.FileInfo = &FileInfo{} func NewFileInfo(info os.FileInfo) *FileInfo { fi := &FileInfo{ name: cleanName(info.Name()), size: info.Size(), mode: info.Mode(), modTime: info.ModTime(), isDir: info.IsDir(), sys: info.Sys(), } return fi } func WithName(name string, info os.FileInfo) *FileInfo { if ft, ok := info.(*FileInfo); ok { ft.name = cleanName(name) return ft } fo := NewFileInfo(info) fo.name = cleanName(name) return fo } func cleanName(s string) string { if strings.Contains(s, "\\") { s = strings.Replace(s, "\\", "/", -1) } if !strings.HasPrefix(s, "/") { s = "/" + s } return s }