git-lfs/pointer/pointer.go

162 lines
3.2 KiB
Go
Raw Normal View History

package pointer
2013-09-27 17:08:19 +00:00
import (
2014-07-24 21:23:02 +00:00
"bufio"
2013-09-27 17:08:19 +00:00
"bytes"
"errors"
2014-07-24 22:02:27 +00:00
"fmt"
2014-08-07 14:53:13 +00:00
"github.com/github/git-media/gitmedia"
2013-09-27 17:08:19 +00:00
"io"
"regexp"
2014-07-24 21:23:02 +00:00
"strconv"
"strings"
2013-09-27 17:08:19 +00:00
)
var (
2014-07-24 20:49:47 +00:00
MediaWarning = []byte("# git-media\n")
alpha = "http://git-media.io/v/1"
latest = "http://git-media.io/v/2"
oidType = "sha256"
alphaHeaderRE = regexp.MustCompile(`\A# (.*git-media|external)`)
2014-08-14 17:15:22 +00:00
template = `version %s
oid sha256:%s
size %d
2014-07-24 22:02:27 +00:00
`
matcher = []byte("git-media")
pointerKeys = []string{"version", "oid", "size"}
)
type Pointer struct {
Version string
Oid string
Size int64
2014-07-24 20:49:47 +00:00
OidType string
}
2013-09-27 17:08:53 +00:00
func NewPointer(oid string, size int64) *Pointer {
2014-07-24 21:23:02 +00:00
return &Pointer{latest, oid, size, oidType}
}
2014-08-07 14:53:13 +00:00
func (p *Pointer) Smudge(writer io.Writer, cb gitmedia.CopyCallback) error {
return Smudge(writer, p, cb)
}
func (p *Pointer) Encode(writer io.Writer) (int, error) {
return Encode(writer, p)
}
2014-09-18 18:38:10 +00:00
func (p *Pointer) Encoded() string {
return fmt.Sprintf(template, latest, p.Oid, p.Size)
}
func Encode(writer io.Writer, pointer *Pointer) (int, error) {
2014-09-18 18:38:10 +00:00
return writer.Write([]byte(pointer.Encoded()))
2013-09-27 17:08:19 +00:00
}
func Decode(reader io.Reader) (*Pointer, error) {
2014-07-24 20:49:47 +00:00
buf := make([]byte, 200)
2013-10-04 13:48:02 +00:00
written, err := reader.Read(buf)
if err != nil {
return nil, err
2013-10-04 13:48:02 +00:00
}
2013-09-27 17:08:19 +00:00
2014-07-24 20:49:47 +00:00
data := bytes.TrimSpace(buf[0:written])
2013-09-27 17:08:19 +00:00
2014-07-24 20:49:47 +00:00
if alphaHeaderRE.Match(data) {
return decodeAlpha(data)
} else {
2014-08-14 17:15:22 +00:00
return decodeKV(data)
}
2014-07-24 20:49:47 +00:00
}
2014-08-14 17:15:22 +00:00
func decodeKV(data []byte) (*Pointer, error) {
parsed, err := decodeKVData(data)
2014-07-24 21:23:02 +00:00
if err != nil {
return nil, err
}
2014-08-14 17:15:22 +00:00
v, ok := parsed["version"]
2014-07-24 21:23:02 +00:00
if !ok || v != latest {
if len(v) == 0 {
v = "--"
}
return nil, errors.New("Invalid version: " + v)
}
2014-08-14 17:15:22 +00:00
oidValue, ok := parsed["oid"]
2014-07-24 21:23:02 +00:00
if !ok {
return nil, errors.New("Invalid Oid")
}
oidParts := strings.SplitN(oidValue, ":", 2)
if len(oidParts) != 2 {
return nil, errors.New("Invalid Oid type in" + oidValue)
}
if oidParts[0] != oidType {
return nil, errors.New("Invalid Oid type: " + oidParts[0])
}
oid := oidParts[1]
var size int64
2014-08-14 17:15:22 +00:00
sizeStr, ok := parsed["size"]
2014-07-24 21:23:02 +00:00
if !ok {
return nil, errors.New("Invalid Oid")
} else {
size, err = strconv.ParseInt(sizeStr, 10, 0)
if err != nil {
return nil, errors.New("Invalid size: " + sizeStr)
}
}
return NewPointer(oid, size), nil
}
2014-08-14 17:15:22 +00:00
func decodeKVData(data []byte) (map[string]string, error) {
m := make(map[string]string)
2014-08-14 20:23:19 +00:00
if !bytes.Contains(data, matcher) {
return m, fmt.Errorf("Not a valid Git Media pointer file.")
}
2014-08-14 17:15:22 +00:00
scanner := bufio.NewScanner(bytes.NewBuffer(data))
2014-08-14 20:23:19 +00:00
line := 0
2014-08-14 20:30:33 +00:00
numKeys := len(pointerKeys)
2014-08-14 17:15:22 +00:00
for scanner.Scan() {
2014-08-14 20:30:33 +00:00
text := scanner.Text()
if len(text) == 0 {
continue
}
parts := strings.SplitN(text, " ", 2)
key := parts[0]
if numKeys <= line {
return m, fmt.Errorf("Extra line: %s", text)
}
if expected := pointerKeys[line]; key != expected {
return m, fmt.Errorf("Expected key %s, got %s", expected, key)
}
2014-08-14 20:23:19 +00:00
line += 1
if len(parts) < 2 {
2014-08-14 20:30:33 +00:00
return m, fmt.Errorf("Error reading line %d: %s", line, text)
2014-08-14 17:15:22 +00:00
}
2014-08-14 20:30:33 +00:00
m[key] = parts[1]
2014-08-14 17:15:22 +00:00
}
return m, scanner.Err()
}
2014-07-24 20:49:47 +00:00
func decodeAlpha(data []byte) (*Pointer, error) {
2014-07-24 21:23:02 +00:00
lines := bytes.Split(data, []byte("\n"))
2014-07-24 20:49:47 +00:00
last := len(lines) - 1
if last == 0 {
2014-08-14 20:23:19 +00:00
return nil, errors.New("No OID in pointer file")
2013-10-04 13:48:02 +00:00
}
2014-07-24 20:49:47 +00:00
return &Pointer{alpha, string(lines[last]), 0, oidType}, nil
2013-09-27 17:08:19 +00:00
}