gitea源码

format.go 2.5KB

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