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