code.gitea.io/gitea@v1.19.3/modules/git/foreachref/format.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package foreachref 5 6 import ( 7 "encoding/hex" 8 "fmt" 9 "io" 10 "strings" 11 ) 12 13 var ( 14 nullChar = []byte("\x00") 15 dualNullChar = []byte("\x00\x00") 16 ) 17 18 // Format supports specifying and parsing an output format for 'git 19 // for-each-ref'. See See git-for-each-ref(1) for available fields. 20 type Format struct { 21 // fieldNames hold %(fieldname)s to be passed to the '--format' flag of 22 // for-each-ref. See git-for-each-ref(1) for available fields. 23 fieldNames []string 24 25 // fieldDelim is the character sequence that is used to separate fields 26 // for each reference. fieldDelim and refDelim should be selected to not 27 // interfere with each other and to not be present in field values. 28 fieldDelim []byte 29 // fieldDelimStr is a string representation of fieldDelim. Used to save 30 // us from repetitive reallocation whenever we need the delimiter as a 31 // string. 32 fieldDelimStr string 33 // refDelim is the character sequence used to separate reference from 34 // each other in the output. fieldDelim and refDelim should be selected 35 // to not interfere with each other and to not be present in field 36 // values. 37 refDelim []byte 38 } 39 40 // NewFormat creates a forEachRefFormat using the specified fieldNames. See 41 // git-for-each-ref(1) for available fields. 42 func NewFormat(fieldNames ...string) Format { 43 return Format{ 44 fieldNames: fieldNames, 45 fieldDelim: nullChar, 46 fieldDelimStr: string(nullChar), 47 refDelim: dualNullChar, 48 } 49 } 50 51 // Flag returns a for-each-ref --format flag value that captures the fieldNames. 52 func (f Format) Flag() string { 53 var formatFlag strings.Builder 54 for i, field := range f.fieldNames { 55 // field key and field value 56 formatFlag.WriteString(fmt.Sprintf("%s %%(%s)", field, field)) 57 58 if i < len(f.fieldNames)-1 { 59 // note: escape delimiters to allow control characters as 60 // delimiters. For example, '%00' for null character or '%0a' 61 // for newline. 62 formatFlag.WriteString(f.hexEscaped(f.fieldDelim)) 63 } 64 } 65 formatFlag.WriteString(f.hexEscaped(f.refDelim)) 66 return formatFlag.String() 67 } 68 69 // Parser returns a Parser capable of parsing 'git for-each-ref' output produced 70 // with this Format. 71 func (f Format) Parser(r io.Reader) *Parser { 72 return NewParser(r, f) 73 } 74 75 // hexEscaped produces hex-escpaed characters from a string. For example, "\n\0" 76 // would turn into "%0a%00". 77 func (f Format) hexEscaped(delim []byte) string { 78 escaped := "" 79 for i := 0; i < len(delim); i++ { 80 escaped += "%" + hex.EncodeToString([]byte{delim[i]}) 81 } 82 return escaped 83 }