github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/git/odb/tag.go (about) 1 package odb 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/hex" 7 "fmt" 8 "io" 9 "strings" 10 11 "github.com/git-lfs/git-lfs/errors" 12 ) 13 14 type Tag struct { 15 Object []byte 16 ObjectType ObjectType 17 Name string 18 Tagger string 19 20 Message string 21 } 22 23 // Decode implements Object.Decode and decodes the uncompressed tag being 24 // read. It returns the number of uncompressed bytes being consumed off of the 25 // stream, which should be strictly equal to the size given. 26 // 27 // If any error was encountered along the way it will be returned, and the 28 // receiving *Tag is considered invalid. 29 func (t *Tag) Decode(r io.Reader, size int64) (int, error) { 30 scanner := bufio.NewScanner(io.LimitReader(r, size)) 31 32 var ( 33 finishedHeaders bool 34 message []string 35 ) 36 37 for scanner.Scan() { 38 if finishedHeaders { 39 message = append(message, scanner.Text()) 40 } else { 41 if len(scanner.Bytes()) == 0 { 42 finishedHeaders = true 43 continue 44 } 45 46 parts := strings.SplitN(scanner.Text(), " ", 2) 47 if len(parts) < 2 { 48 return 0, errors.Errorf("git/odb: invalid tag header: %s", scanner.Text()) 49 } 50 51 switch parts[0] { 52 case "object": 53 sha, err := hex.DecodeString(parts[1]) 54 if err != nil { 55 return 0, errors.Wrap(err, "git/odb: unable to decode SHA-1") 56 } 57 58 t.Object = sha 59 case "type": 60 t.ObjectType = ObjectTypeFromString(parts[1]) 61 case "tag": 62 t.Name = parts[1] 63 case "tagger": 64 t.Tagger = parts[1] 65 default: 66 return 0, errors.Errorf("git/odb: unknown tag header: %s", parts[0]) 67 } 68 } 69 } 70 71 if err := scanner.Err(); err != nil { 72 return 0, err 73 } 74 75 t.Message = strings.Join(message, "\n") 76 77 return int(size), nil 78 } 79 80 // Encode encodes the Tag's contents to the given io.Writer, "w". If there was 81 // any error copying the Tag's contents, that error will be returned. 82 // 83 // Otherwise, the number of bytes written will be returned. 84 func (t *Tag) Encode(w io.Writer) (int, error) { 85 headers := []string{ 86 fmt.Sprintf("object %s", hex.EncodeToString(t.Object)), 87 fmt.Sprintf("type %s", t.ObjectType), 88 fmt.Sprintf("tag %s", t.Name), 89 fmt.Sprintf("tagger %s", t.Tagger), 90 } 91 92 return fmt.Fprintf(w, "%s\n\n%s", strings.Join(headers, "\n"), t.Message) 93 } 94 95 // Equal returns whether the receiving and given Tags are equal, or in other 96 // words, whether they are represented by the same SHA-1 when saved to the 97 // object database. 98 func (t *Tag) Equal(other *Tag) bool { 99 if (t == nil) != (other == nil) { 100 return false 101 } 102 103 if t != nil { 104 return bytes.Equal(t.Object, other.Object) && 105 t.ObjectType == other.ObjectType && 106 t.Name == other.Name && 107 t.Tagger == other.Tagger && 108 t.Message == other.Message 109 } 110 111 return true 112 } 113 114 // Type implements Object.ObjectType by returning the correct object type for 115 // Tags, TagObjectType. 116 func (t *Tag) Type() ObjectType { 117 return TagObjectType 118 }