aboutsummaryrefslogtreecommitdiff
path: root/objects/object_tree.go
diff options
context:
space:
mode:
Diffstat (limited to 'objects/object_tree.go')
-rw-r--r--objects/object_tree.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/objects/object_tree.go b/objects/object_tree.go
new file mode 100644
index 0000000..07c265c
--- /dev/null
+++ b/objects/object_tree.go
@@ -0,0 +1,191 @@
+package objects
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "sort"
+)
+
+type TreeEntryType string
+
+const (
+ TETFile TreeEntryType = "file"
+ TETDir TreeEntryType = "dir"
+ TETSymlink TreeEntryType = "symlink"
+)
+
+var treeEntryTypes = map[TreeEntryType]struct{}{
+ TETFile: {},
+ TETDir: {},
+ TETSymlink: {},
+}
+
+type TreeEntry interface {
+ Type() TreeEntryType
+ equalContent(TreeEntry) bool
+ toProperties() properties
+}
+
+func compareTreeEntries(a, b TreeEntry) bool {
+ return a.Type() == b.Type() && a.equalContent(b)
+}
+
+type TreeEntryFile ObjectId
+
+func (tef TreeEntryFile) Type() TreeEntryType {
+ return TETFile
+}
+
+func (tef TreeEntryFile) toProperties() properties {
+ return properties{"ref": ObjectId(tef).String()}
+}
+
+func (a TreeEntryFile) equalContent(_b TreeEntry) bool {
+ b, ok := _b.(TreeEntryFile)
+ return ok && ObjectId(b).Equals(ObjectId(a))
+}
+
+type TreeEntryDir ObjectId
+
+func (ted TreeEntryDir) Type() TreeEntryType {
+ return TETDir
+}
+
+func (ted TreeEntryDir) toProperties() properties {
+ return properties{"ref": ObjectId(ted).String()}
+}
+
+func (a TreeEntryDir) equalContent(_b TreeEntry) bool {
+ b, ok := _b.(TreeEntryDir)
+ return ok && ObjectId(b).Equals(ObjectId(a))
+}
+
+type TreeEntrySymlink string
+
+func (tes TreeEntrySymlink) Type() TreeEntryType {
+ return TETSymlink
+}
+
+func (tes TreeEntrySymlink) toProperties() properties {
+ return properties{"target": string(tes)}
+}
+
+func (a TreeEntrySymlink) equalContent(_b TreeEntry) bool {
+ b, ok := _b.(TreeEntrySymlink)
+ return ok && b == a
+}
+
+type Tree map[string]TreeEntry
+
+func (t Tree) Type() ObjectType {
+ return OTTree
+}
+
+func (t Tree) Payload() (out []byte) {
+ lines := []string{}
+ for name, entry := range t {
+ props := entry.toProperties()
+ props["type"] = string(entry.Type())
+ props["name"] = name
+
+ line, err := props.MarshalText()
+ if err != nil {
+ panic(err)
+ }
+
+ lines = append(lines, string(line)+"\n")
+ }
+
+ sort.Strings(lines)
+
+ for _, line := range lines {
+ out = append(out, line...)
+ }
+
+ return
+}
+
+func getObjectIdFromProps(p properties, key string) (ObjectId, error) {
+ raw, ok := p[key]
+ if !ok {
+ return ObjectId{}, fmt.Errorf("Missing key: %s", key)
+ }
+
+ oid, err := ParseObjectId(raw)
+ return oid, err
+}
+
+func (t Tree) FromPayload(payload []byte) error {
+ sc := bufio.NewScanner(bytes.NewReader(payload))
+
+ for sc.Scan() {
+ line := sc.Bytes()
+ if len(line) == 0 {
+ continue
+ }
+
+ props := make(properties)
+ if err := props.UnmarshalText(line); err != nil {
+ return nil
+ }
+
+ entry_type, ok := props["type"]
+ if !ok {
+ return errors.New("Missing property: type")
+ }
+
+ var entry TreeEntry
+ switch TreeEntryType(entry_type) {
+ case TETFile:
+ ref, err := getObjectIdFromProps(props, "ref")
+ if err != nil {
+ return err
+ }
+ entry = TreeEntryFile(ref)
+ case TETDir:
+ ref, err := getObjectIdFromProps(props, "ref")
+ if err != nil {
+ return err
+ }
+ entry = TreeEntryDir(ref)
+ case TETSymlink:
+ target, ok := props["target"]
+ if !ok {
+ return errors.New("Missing key: target")
+ }
+ entry = TreeEntrySymlink(target)
+ default:
+ // TODO: Or should we just ignore this entry? There might be more types in the future...
+ return fmt.Errorf("Unknown tree entry type: %s", entry_type)
+ }
+
+ name, ok := props["name"]
+ if !ok {
+ return errors.New("Missing property: name")
+ }
+
+ t[name] = entry
+ }
+
+ return sc.Err()
+}
+
+func (a Tree) Equals(b Tree) bool {
+ for k, va := range a {
+ vb, ok := b[k]
+ if !ok || va.Type() != vb.Type() || !va.equalContent(vb) {
+ return false
+ }
+ }
+
+ for k := range b {
+ _, ok := a[k]
+ if !ok {
+ return false
+ }
+ }
+
+ return true
+}