aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/errors.go35
-rw-r--r--core/hash.go40
-rw-r--r--core/hash_test.go35
-rw-r--r--core/object.go113
4 files changed, 223 insertions, 0 deletions
diff --git a/core/errors.go b/core/errors.go
new file mode 100644
index 0000000..fd1133e
--- /dev/null
+++ b/core/errors.go
@@ -0,0 +1,35 @@
+package core
+
+import "fmt"
+
+type PermanentError struct {
+ err error
+}
+
+func NewPermanentError(err error) *PermanentError {
+ if err == nil {
+ return nil
+ }
+
+ return &PermanentError{err: err}
+}
+
+func (e *PermanentError) Error() string {
+ return fmt.Sprintf("permanent client error: %s", e.err.Error())
+}
+
+type UnexpectedError struct {
+ err error
+}
+
+func NewUnexpectedError(err error) *UnexpectedError {
+ if err == nil {
+ return nil
+ }
+
+ return &UnexpectedError{err: err}
+}
+
+func (e *UnexpectedError) Error() string {
+ return fmt.Sprintf("unexpected client error: %s", e.err.Error())
+}
diff --git a/core/hash.go b/core/hash.go
new file mode 100644
index 0000000..0b6f274
--- /dev/null
+++ b/core/hash.go
@@ -0,0 +1,40 @@
+package core
+
+import (
+ "crypto/sha1"
+ "encoding/hex"
+ "strconv"
+)
+
+// Hash SHA1 hased content
+type Hash [20]byte
+
+// ComputeHash compute the hash for a given ObjectType and content
+func ComputeHash(t ObjectType, content []byte) Hash {
+ h := t.Bytes()
+ h = append(h, ' ')
+ h = strconv.AppendInt(h, int64(len(content)), 10)
+ h = append(h, 0)
+ h = append(h, content...)
+
+ return Hash(sha1.Sum(h))
+}
+
+// NewHash return a new Hash from a hexadecimal hash representation
+func NewHash(s string) Hash {
+ b, _ := hex.DecodeString(s)
+
+ var h Hash
+ copy(h[:], b)
+
+ return h
+}
+
+func (h Hash) IsZero() bool {
+ var empty Hash
+ return h == empty
+}
+
+func (h Hash) String() string {
+ return hex.EncodeToString(h[:])
+}
diff --git a/core/hash_test.go b/core/hash_test.go
new file mode 100644
index 0000000..8c4ed67
--- /dev/null
+++ b/core/hash_test.go
@@ -0,0 +1,35 @@
+package core
+
+import (
+ "testing"
+
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type HashSuite struct{}
+
+var _ = Suite(&HashSuite{})
+
+func (s *HashSuite) TestComputeHash(c *C) {
+ hash := ComputeHash(BlobObject, []byte(""))
+ c.Assert(hash.String(), Equals, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391")
+
+ hash = ComputeHash(BlobObject, []byte("Hello, World!\n"))
+ c.Assert(hash.String(), Equals, "8ab686eafeb1f44702738c8b0f24f2567c36da6d")
+}
+
+func (s *HashSuite) TestNewHash(c *C) {
+ hash := ComputeHash(BlobObject, []byte("Hello, World!\n"))
+
+ c.Assert(hash, Equals, NewHash(hash.String()))
+}
+
+func (s *HashSuite) TestIsZero(c *C) {
+ hash := NewHash("foo")
+ c.Assert(hash.IsZero(), Equals, true)
+
+ hash = NewHash("8ab686eafeb1f44702738c8b0f24f2567c36da6d")
+ c.Assert(hash.IsZero(), Equals, false)
+}
diff --git a/core/object.go b/core/object.go
new file mode 100644
index 0000000..4e8a587
--- /dev/null
+++ b/core/object.go
@@ -0,0 +1,113 @@
+package core
+
+import (
+ "bytes"
+ "io"
+)
+
+// Object is a generic representation of any git object
+type Object interface {
+ Type() ObjectType
+ SetType(ObjectType)
+ Size() int64
+ SetSize(int64)
+ Hash() Hash
+ Reader() io.Reader
+ Writer() io.Writer
+}
+
+// ObjectStorage generic storage of objects
+type ObjectStorage interface {
+ New() Object
+ Set(Object) Hash
+ Get(Hash) (Object, bool)
+}
+
+// ObjectType internal object type's
+type ObjectType int8
+
+const (
+ CommitObject ObjectType = 1
+ TreeObject ObjectType = 2
+ BlobObject ObjectType = 3
+ TagObject ObjectType = 4
+ OFSDeltaObject ObjectType = 6
+ REFDeltaObject ObjectType = 7
+)
+
+func (t ObjectType) String() string {
+ switch t {
+ case CommitObject:
+ return "commit"
+ case TreeObject:
+ return "tree"
+ case BlobObject:
+ return "blob"
+ default:
+ return "-"
+ }
+}
+
+func (t ObjectType) Bytes() []byte {
+ return []byte(t.String())
+}
+
+type RAWObject struct {
+ b []byte
+ t ObjectType
+ s int64
+}
+
+func (o *RAWObject) Type() ObjectType { return o.t }
+func (o *RAWObject) SetType(t ObjectType) { o.t = t }
+func (o *RAWObject) Size() int64 { return o.s }
+func (o *RAWObject) SetSize(s int64) { o.s = s }
+func (o *RAWObject) Reader() io.Reader { return bytes.NewBuffer(o.b) }
+func (o *RAWObject) Hash() Hash { return ComputeHash(o.t, o.b) }
+func (o *RAWObject) Writer() io.Writer { return o }
+func (o *RAWObject) Write(p []byte) (n int, err error) {
+ o.b = append(o.b, p...)
+ return len(p), nil
+}
+
+type RAWObjectStorage struct {
+ Objects map[Hash]Object
+ Commits map[Hash]Object
+ Trees map[Hash]Object
+ Blobs map[Hash]Object
+}
+
+func NewRAWObjectStorage() *RAWObjectStorage {
+ return &RAWObjectStorage{
+ Objects: make(map[Hash]Object, 0),
+ Commits: make(map[Hash]Object, 0),
+ Trees: make(map[Hash]Object, 0),
+ Blobs: make(map[Hash]Object, 0),
+ }
+}
+
+func (o *RAWObjectStorage) New() Object {
+ return &RAWObject{}
+}
+
+func (o *RAWObjectStorage) Set(obj Object) Hash {
+ h := obj.Hash()
+ o.Objects[h] = obj
+
+ switch obj.Type() {
+ case CommitObject:
+ o.Commits[h] = o.Objects[h]
+ case TreeObject:
+ o.Trees[h] = o.Objects[h]
+ case BlobObject:
+ o.Blobs[h] = o.Objects[h]
+ }
+
+ return h
+}
+
+func (o *RAWObjectStorage) Get(h Hash) (Object, bool) {
+ obj, ok := o.Objects[h]
+
+ return obj, ok
+}