git/odb: add implementation of annotated Tag object
This commit is contained in:
parent
1e239fe699
commit
b78fa93988
118
git/odb/tag.go
Normal file
118
git/odb/tag.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package odb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tag struct {
|
||||||
|
Object []byte
|
||||||
|
ObjectType ObjectType
|
||||||
|
Name string
|
||||||
|
Tagger string
|
||||||
|
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode implements Object.Decode and decodes the uncompressed tag being
|
||||||
|
// read. It returns the number of uncompressed bytes being consumed off of the
|
||||||
|
// stream, which should be strictly equal to the size given.
|
||||||
|
//
|
||||||
|
// If any error was encountered along the way it will be returned, and the
|
||||||
|
// receiving *Tag is considered invalid.
|
||||||
|
func (t *Tag) Decode(r io.Reader, size int64) (int, error) {
|
||||||
|
scanner := bufio.NewScanner(io.LimitReader(r, size))
|
||||||
|
|
||||||
|
var (
|
||||||
|
finishedHeaders bool
|
||||||
|
message []string
|
||||||
|
)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
if finishedHeaders {
|
||||||
|
message = append(message, scanner.Text())
|
||||||
|
} else {
|
||||||
|
if len(scanner.Bytes()) == 0 {
|
||||||
|
finishedHeaders = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitN(scanner.Text(), " ", 2)
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return 0, errors.Errorf("git/odb: invalid tag header: %s", scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch parts[0] {
|
||||||
|
case "object":
|
||||||
|
sha, err := hex.DecodeString(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "git/odb: unable to decode SHA-1")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Object = sha
|
||||||
|
case "type":
|
||||||
|
t.ObjectType = ObjectTypeFromString(parts[1])
|
||||||
|
case "tag":
|
||||||
|
t.Name = parts[1]
|
||||||
|
case "tagger":
|
||||||
|
t.Tagger = parts[1]
|
||||||
|
default:
|
||||||
|
return 0, errors.Errorf("git/odb: unknown tag header: %s", parts[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Message = strings.Join(message, "\n")
|
||||||
|
|
||||||
|
return int(size), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes the Tag's contents to the given io.Writer, "w". If there was
|
||||||
|
// any error copying the Tag's contents, that error will be returned.
|
||||||
|
//
|
||||||
|
// Otherwise, the number of bytes written will be returned.
|
||||||
|
func (t *Tag) Encode(w io.Writer) (int, error) {
|
||||||
|
headers := []string{
|
||||||
|
fmt.Sprintf("object %s", hex.EncodeToString(t.Object)),
|
||||||
|
fmt.Sprintf("type %s", t.ObjectType),
|
||||||
|
fmt.Sprintf("tag %s", t.Name),
|
||||||
|
fmt.Sprintf("tagger %s", t.Tagger),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Fprintf(w, "%s\n\n%s\n", strings.Join(headers, "\n"), t.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns whether the receiving and given Tags are equal, or in other
|
||||||
|
// words, whether they are represented by the same SHA-1 when saved to the
|
||||||
|
// object database.
|
||||||
|
func (t *Tag) Equal(other *Tag) bool {
|
||||||
|
if (t == nil) != (other == nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if t != nil {
|
||||||
|
return bytes.Equal(t.Object, other.Object) &&
|
||||||
|
t.ObjectType == other.ObjectType &&
|
||||||
|
t.Name == other.Name &&
|
||||||
|
t.Tagger == other.Tagger &&
|
||||||
|
t.Message == other.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements Object.ObjectType by returning the correct object type for
|
||||||
|
// Tags, TagObjectType.
|
||||||
|
func (t *Tag) Type() ObjectType {
|
||||||
|
return TagObjectType
|
||||||
|
}
|
65
git/odb/tag_test.go
Normal file
65
git/odb/tag_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package odb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTagTypeReturnsCorrectObjectType(t *testing.T) {
|
||||||
|
assert.Equal(t, TagObjectType, new(Tag).Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTagEncode(t *testing.T) {
|
||||||
|
tag := &Tag{
|
||||||
|
Object: []byte("aaaaaaaaaaaaaaaaaaaa"),
|
||||||
|
ObjectType: CommitObjectType,
|
||||||
|
Name: "v2.4.0",
|
||||||
|
Tagger: "A U Thor <author@example.com>",
|
||||||
|
|
||||||
|
Message: "The quick brown fox jumps over the lazy dog.",
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
n, err := tag.Encode(buf)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.EqualValues(t, buf.Len(), n)
|
||||||
|
|
||||||
|
assertLine(t, buf, "object 6161616161616161616161616161616161616161")
|
||||||
|
assertLine(t, buf, "type commit")
|
||||||
|
assertLine(t, buf, "tag v2.4.0")
|
||||||
|
assertLine(t, buf, "tagger A U Thor <author@example.com>")
|
||||||
|
assertLine(t, buf, "")
|
||||||
|
assertLine(t, buf, "The quick brown fox jumps over the lazy dog.")
|
||||||
|
|
||||||
|
assert.Equal(t, 0, buf.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTagDecode(t *testing.T) {
|
||||||
|
from := new(bytes.Buffer)
|
||||||
|
|
||||||
|
fmt.Fprintf(from, "object 6161616161616161616161616161616161616161\n")
|
||||||
|
fmt.Fprintf(from, "type commit\n")
|
||||||
|
fmt.Fprintf(from, "tag v2.4.0\n")
|
||||||
|
fmt.Fprintf(from, "tagger A U Thor <author@example.com>\n")
|
||||||
|
fmt.Fprintf(from, "\n")
|
||||||
|
fmt.Fprintf(from, "The quick brown fox jumps over the lazy dog.\n")
|
||||||
|
|
||||||
|
flen := from.Len()
|
||||||
|
|
||||||
|
tag := new(Tag)
|
||||||
|
n, err := tag.Decode(from, int64(flen))
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, n, flen)
|
||||||
|
|
||||||
|
assert.Equal(t, []byte("aaaaaaaaaaaaaaaaaaaa"), tag.Object)
|
||||||
|
assert.Equal(t, CommitObjectType, tag.ObjectType)
|
||||||
|
assert.Equal(t, "v2.4.0", tag.Name)
|
||||||
|
assert.Equal(t, "A U Thor <author@example.com>", tag.Tagger)
|
||||||
|
assert.Equal(t, "The quick brown fox jumps over the lazy dog.", tag.Message)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user