srcinfo.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Package srcinfo is a parser for srcinfo files. Typically generated by
  2. // makepkg, part of the pacman package manager.
  3. //
  4. // Split packages and architecture dependent fields are fully supported.
  5. //
  6. // This Package aimes to parse srcinfos but not interpret them in any way.
  7. // All values are fundamentally strings, other tools should be used for
  8. // things such as dependency parsing, validity checking etc.
  9. package srcinfo
  10. import (
  11. "fmt"
  12. )
  13. // ArchString describes string values that may be architecture dependent.
  14. // For Example depends_x86_64.
  15. // If Arch is an empty string then the field is not architecture dependent.
  16. type ArchString struct {
  17. Arch string // Architecture name
  18. Value string // Value
  19. }
  20. // Package describes the fields of a pkgbuild that may be overwritten by
  21. // in build_<pkgname> function.
  22. type Package struct {
  23. Pkgname string
  24. Pkgdesc string
  25. Arch []string
  26. URL string
  27. License []string
  28. Groups []string
  29. Depends []ArchString
  30. OptDepends []ArchString
  31. Provides []ArchString
  32. Conflicts []ArchString
  33. Replaces []ArchString
  34. Backup []string
  35. Options []string
  36. Install string
  37. Changelog string
  38. }
  39. // PackageBase describes the fields of a pkgbuild that may not be overwritten
  40. // in package_<pkgname> function.
  41. type PackageBase struct {
  42. Pkgbase string
  43. Pkgver string
  44. Pkgrel string
  45. Epoch string
  46. Source []ArchString
  47. ValidPGPKeys []string
  48. NoExtract []string
  49. MD5Sums []ArchString
  50. SHA1Sums []ArchString
  51. SHA224Sums []ArchString
  52. SHA256Sums []ArchString
  53. SHA384Sums []ArchString
  54. SHA512Sums []ArchString
  55. B2Sums []ArchString
  56. MakeDepends []ArchString
  57. CheckDepends []ArchString
  58. }
  59. // Srcinfo represents a full srcinfo. All global fields are defined here while
  60. // fields overwritten in the package_<pkgname> function are defined in the
  61. // Packages field.
  62. //
  63. // Note: The Packages field only contains the values that each package
  64. // overrides, global fields will be missing. A Package containing both global
  65. // and overwritten fields can be generated using the SplitPackage function.
  66. type Srcinfo struct {
  67. PackageBase // Fields that only apply to the package base
  68. Package // Fields that apply to the package globally
  69. Packages []Package // Fields for each package this package base contains
  70. }
  71. // EmptyOverride is used to signal when a value has been overridden with an
  72. // empty value. An empty ovrride is when a value is defined in the pkgbuild but
  73. // then overridden inside the package function to be empty.
  74. //
  75. // For example "pkgdesc=''" is an empty override on the pkgdesc which would
  76. // lead to the line "pkgdesc=" in the srcinfo.
  77. //
  78. // This value is used internally to store empty overrides, mainly to avoid
  79. // using string pointers. It is possible to check for empty overrides using
  80. // the Packages slice in Packagebase.
  81. //
  82. // During normal use with the SplitPackage function this value will be
  83. // converted back to an empty string, or removed entirely for slice values.
  84. // This means the this value can be completley ignored unless you are
  85. // explicitly looking for empty overrides.
  86. const EmptyOverride = "\x00"
  87. // Version formats a version string from the epoch, pkgver and pkgrel of the
  88. // srcinfo. In the format [epoch:]pkgver-pkgrel.
  89. func (si *Srcinfo) Version() string {
  90. if si.Epoch == "" {
  91. return si.Pkgver + "-" + si.Pkgrel
  92. }
  93. return si.Epoch + ":" + si.Pkgver + "-" + si.Pkgrel
  94. }
  95. // SplitPackages generates a splice of all packages that are part of this
  96. // srcinfo. This is equivalent to calling SplitPackage on every pkgname.
  97. func (si *Srcinfo) SplitPackages() []*Package {
  98. pkgs := make([]*Package, 0, len(si.Packages))
  99. for _, pkg := range si.Packages {
  100. pkgs = append(pkgs, mergeSplitPackage(&si.Package, &pkg))
  101. }
  102. return pkgs
  103. }
  104. // SplitPackage generates a Package that contains all fields that the specified
  105. // pkgname has. But will fall back on global fields if they are not defined in
  106. // the Package.
  107. //
  108. // Note slice values will be passed by reference, it is not recommended you
  109. // modify this struct after it is returned.
  110. func (si *Srcinfo) SplitPackage(pkgname string) (*Package, error) {
  111. for n := range si.Packages {
  112. if si.Packages[n].Pkgname == pkgname {
  113. return mergeSplitPackage(&si.Package, &si.Packages[n]), nil
  114. }
  115. }
  116. return nil, fmt.Errorf("Package \"%s\" is not part of the package base \"%s\"", pkgname, si.Pkgbase)
  117. }
  118. func mergeArchSlice(global, override []ArchString) []ArchString {
  119. overridden := make(map[string]struct{})
  120. merged := make([]ArchString, 0, len(override))
  121. for _, v := range override {
  122. overridden[v.Arch] = struct{}{}
  123. if v.Value == EmptyOverride {
  124. continue
  125. }
  126. merged = append(merged, v)
  127. }
  128. for _, v := range global {
  129. if _, ok := overridden[v.Arch]; !ok {
  130. merged = append(merged, v)
  131. }
  132. }
  133. return merged
  134. }
  135. func mergeSplitPackage(base, split *Package) *Package {
  136. pkg := &Package{}
  137. *pkg = *base
  138. pkg.Pkgname = split.Pkgname
  139. if split.Pkgdesc != "" {
  140. pkg.Pkgdesc = split.Pkgdesc
  141. }
  142. if len(split.Arch) != 0 {
  143. pkg.Arch = split.Arch
  144. }
  145. if split.URL != "" {
  146. pkg.URL = split.URL
  147. }
  148. if len(split.License) != 0 {
  149. pkg.License = split.License
  150. }
  151. if len(split.Groups) != 0 {
  152. pkg.Groups = split.Groups
  153. }
  154. if len(split.Depends) != 0 {
  155. pkg.Depends = mergeArchSlice(pkg.Depends, split.Depends)
  156. }
  157. if len(split.OptDepends) != 0 {
  158. pkg.OptDepends = mergeArchSlice(pkg.OptDepends, split.OptDepends)
  159. }
  160. if len(split.Provides) != 0 {
  161. pkg.Provides = mergeArchSlice(pkg.Provides, split.Provides)
  162. }
  163. if len(split.Conflicts) != 0 {
  164. pkg.Conflicts = mergeArchSlice(pkg.Conflicts, split.Conflicts)
  165. }
  166. if len(split.Replaces) != 0 {
  167. pkg.Replaces = mergeArchSlice(pkg.Replaces, split.Replaces)
  168. }
  169. if len(split.Backup) != 0 {
  170. pkg.Backup = split.Backup
  171. }
  172. if len(split.Options) != 0 {
  173. pkg.Options = split.Options
  174. }
  175. if split.Changelog != "" {
  176. pkg.Changelog = split.Changelog
  177. }
  178. if split.Install != "" {
  179. pkg.Install = split.Install
  180. }
  181. return pkg
  182. }