162 lines
3.2 KiB
Go
162 lines
3.2 KiB
Go
package filetree
|
|
|
|
import (
|
|
"archive/tar"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/cespare/xxhash"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
Unchanged DiffType = iota
|
|
Changed
|
|
Added
|
|
Removed
|
|
)
|
|
|
|
var GlobalFileTreeCollapse bool
|
|
|
|
// NewNodeData creates an empty NodeData struct for a FileNode
|
|
func NewNodeData() *NodeData {
|
|
return &NodeData{
|
|
ViewInfo: *NewViewInfo(),
|
|
FileInfo: FileInfo{},
|
|
DiffType: Unchanged,
|
|
}
|
|
}
|
|
|
|
// Copy duplicates a NodeData
|
|
func (data *NodeData) Copy() *NodeData {
|
|
return &NodeData{
|
|
ViewInfo: *data.ViewInfo.Copy(),
|
|
FileInfo: *data.FileInfo.Copy(),
|
|
DiffType: data.DiffType,
|
|
}
|
|
}
|
|
|
|
// NewViewInfo creates a default ViewInfo
|
|
func NewViewInfo() (view *ViewInfo) {
|
|
return &ViewInfo{
|
|
Collapsed: GlobalFileTreeCollapse,
|
|
Hidden: false,
|
|
}
|
|
}
|
|
|
|
// Copy duplicates a ViewInfo
|
|
func (view *ViewInfo) Copy() (newView *ViewInfo) {
|
|
newView = NewViewInfo()
|
|
*newView = *view
|
|
return newView
|
|
}
|
|
|
|
func getHashFromReader(reader io.Reader) uint64 {
|
|
h := xxhash.New()
|
|
|
|
buf := make([]byte, 1024)
|
|
for {
|
|
n, err := reader.Read(buf)
|
|
if err != nil && err != io.EOF {
|
|
logrus.Panic(err)
|
|
}
|
|
if n == 0 {
|
|
break
|
|
}
|
|
|
|
_, err = h.Write(buf[:n])
|
|
if err != nil {
|
|
logrus.Panic(err)
|
|
}
|
|
}
|
|
|
|
return h.Sum64()
|
|
}
|
|
|
|
// NewFileInfo extracts the metadata from a tar header and file contents and generates a new FileInfo object.
|
|
func NewFileInfo(reader *tar.Reader, header *tar.Header, path string) FileInfo {
|
|
if header.Typeflag == tar.TypeDir {
|
|
return FileInfo{
|
|
Path: path,
|
|
TypeFlag: header.Typeflag,
|
|
Linkname: header.Linkname,
|
|
hash: 0,
|
|
Size: header.FileInfo().Size(),
|
|
Mode: header.FileInfo().Mode(),
|
|
Uid: header.Uid,
|
|
Gid: header.Gid,
|
|
IsDir: header.FileInfo().IsDir(),
|
|
}
|
|
}
|
|
|
|
hash := getHashFromReader(reader)
|
|
|
|
return FileInfo{
|
|
Path: path,
|
|
TypeFlag: header.Typeflag,
|
|
Linkname: header.Linkname,
|
|
hash: hash,
|
|
Size: header.FileInfo().Size(),
|
|
Mode: header.FileInfo().Mode(),
|
|
Uid: header.Uid,
|
|
Gid: header.Gid,
|
|
IsDir: header.FileInfo().IsDir(),
|
|
}
|
|
}
|
|
|
|
// Copy duplicates a FileInfo
|
|
func (data *FileInfo) Copy() *FileInfo {
|
|
if data == nil {
|
|
return nil
|
|
}
|
|
return &FileInfo{
|
|
Path: data.Path,
|
|
TypeFlag: data.TypeFlag,
|
|
Linkname: data.Linkname,
|
|
hash: data.hash,
|
|
Size: data.Size,
|
|
Mode: data.Mode,
|
|
Uid: data.Uid,
|
|
Gid: data.Gid,
|
|
IsDir: data.IsDir,
|
|
}
|
|
}
|
|
|
|
// Compare determines the DiffType between two FileInfos based on the type and contents of each given FileInfo
|
|
func (data *FileInfo) Compare(other FileInfo) DiffType {
|
|
if data.TypeFlag == other.TypeFlag {
|
|
if data.hash == other.hash &&
|
|
data.Mode == other.Mode &&
|
|
data.Uid == other.Uid &&
|
|
data.Gid == other.Gid {
|
|
return Unchanged
|
|
}
|
|
}
|
|
return Changed
|
|
}
|
|
|
|
// String of a DiffType
|
|
func (diff DiffType) String() string {
|
|
switch diff {
|
|
case Unchanged:
|
|
return "Unchanged"
|
|
case Changed:
|
|
return "Changed"
|
|
case Added:
|
|
return "Added"
|
|
case Removed:
|
|
return "Removed"
|
|
default:
|
|
return fmt.Sprintf("%d", int(diff))
|
|
}
|
|
}
|
|
|
|
// merge two DiffTypes into a single result. Essentially, return the given value unless they two values differ,
|
|
// in which case we can only determine that there is "a change".
|
|
func (diff DiffType) merge(other DiffType) DiffType {
|
|
if diff == other {
|
|
return diff
|
|
}
|
|
return Changed
|
|
}
|