github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/tag.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  // Copyright 2015 The Gogs Authors. All rights reserved.
     7  // Use of this source code is governed by a MIT-style
     8  // license that can be found in the LICENSE file.
     9  
    10  package git
    11  
    12  import (
    13  	"bytes"
    14  	"sort"
    15  	"strings"
    16  )
    17  
    18  const (
    19  	beginpgp = "\n-----BEGIN PGP SIGNATURE-----\n"
    20  	endpgp   = "\n-----END PGP SIGNATURE-----"
    21  )
    22  
    23  // Tag represents a Git tag.
    24  type Tag struct {
    25  	Name      string
    26  	ID        SHA1
    27  	Object    SHA1 // The id of this commit object
    28  	Type      string
    29  	Tagger    *Signature
    30  	Message   string
    31  	Signature *CommitGPGSignature
    32  }
    33  
    34  // Commit return the commit of the tag reference
    35  func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) {
    36  	return gitRepo.getCommit(tag.Object)
    37  }
    38  
    39  // Parse commit information from the (uncompressed) raw
    40  // data from the commit object.
    41  // \n\n separate headers from message
    42  func parseTagData(data []byte) (*Tag, error) {
    43  	tag := new(Tag)
    44  	tag.Tagger = &Signature{}
    45  	// we now have the contents of the commit object. Let's investigate...
    46  	nextline := 0
    47  l:
    48  	for {
    49  		eol := bytes.IndexByte(data[nextline:], '\n')
    50  		switch {
    51  		case eol > 0:
    52  			line := data[nextline : nextline+eol]
    53  			spacepos := bytes.IndexByte(line, ' ')
    54  			reftype := line[:spacepos]
    55  			switch string(reftype) {
    56  			case "object":
    57  				id, err := NewIDFromString(string(line[spacepos+1:]))
    58  				if err != nil {
    59  					return nil, err
    60  				}
    61  				tag.Object = id
    62  			case "type":
    63  				// A commit can have one or more parents
    64  				tag.Type = string(line[spacepos+1:])
    65  			case "tagger":
    66  				sig, err := newSignatureFromCommitline(line[spacepos+1:])
    67  				if err != nil {
    68  					return nil, err
    69  				}
    70  				tag.Tagger = sig
    71  			}
    72  			nextline += eol + 1
    73  		case eol == 0:
    74  			tag.Message = string(data[nextline+1:])
    75  			break l
    76  		default:
    77  			break l
    78  		}
    79  	}
    80  	idx := strings.LastIndex(tag.Message, beginpgp)
    81  	if idx > 0 {
    82  		endSigIdx := strings.Index(tag.Message[idx:], endpgp)
    83  		if endSigIdx > 0 {
    84  			tag.Signature = &CommitGPGSignature{
    85  				Signature: tag.Message[idx+1 : idx+endSigIdx+len(endpgp)],
    86  				Payload:   string(data[:bytes.LastIndex(data, []byte(beginpgp))+1]),
    87  			}
    88  			tag.Message = tag.Message[:idx+1]
    89  		}
    90  	}
    91  	return tag, nil
    92  }
    93  
    94  type tagSorter []*Tag
    95  
    96  func (ts tagSorter) Len() int {
    97  	return len([]*Tag(ts))
    98  }
    99  
   100  func (ts tagSorter) Less(i, j int) bool {
   101  	return []*Tag(ts)[i].Tagger.When.After([]*Tag(ts)[j].Tagger.When)
   102  }
   103  
   104  func (ts tagSorter) Swap(i, j int) {
   105  	[]*Tag(ts)[i], []*Tag(ts)[j] = []*Tag(ts)[j], []*Tag(ts)[i]
   106  }
   107  
   108  // sortTagsByTime
   109  func sortTagsByTime(tags []*Tag) {
   110  	sorter := tagSorter(tags)
   111  	sort.Sort(sorter)
   112  }