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  }