srcinfo.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. MakeDepends []ArchString
  56. CheckDepends []ArchString
  57. }
  58. // Srcinfo represents a full srcinfo. All global fields are defined here while
  59. // fields overwritten in the package_<pkgname> function are defined in the
  60. // Packages field.
  61. //
  62. // Note: The Packages field only contains the values that each package
  63. // overrides, global fields will be missing. A Package containing both global
  64. // and overwritten fields can be generated using the SplitPackage function.
  65. type Srcinfo struct {
  66. PackageBase // Fields that only apply to the package base
  67. Package // Fields that apply to the package globally
  68. Packages []Package // Fields for each package this package base contains
  69. }
  70. // EmptyOverride is used to signal when a value has been overridden with an
  71. // empty value. An empty ovrride is when a value is defined in the pkgbuild but
  72. // then overridden inside the package function to be empty.
  73. //
  74. // For example "pkgdesc=''" is an empty override on the pkgdesc which would
  75. // lead to the line "pkgdesc=" in the srcinfo.
  76. //
  77. // This value is used internally to store empty overrides, mainly to avoid
  78. // using string pointers. It is possible to check for empty overrides using
  79. // the Packages slice in Packagebase.
  80. //
  81. // During normal use with the SplitPackage function this value will be
  82. // converted back to an empty string, or removed entirely for slice values.
  83. // This means the this value can be completley ignored unless you are
  84. // explicitly looking for empty overrides.
  85. const EmptyOverride = "\x00"
  86. // Version formats a version string from the epoch, pkgver and pkgrel of the
  87. // srcinfo. In the format [epoch:]pkgver-pkgrel.
  88. func (si *Srcinfo) Version() string {
  89. if si.Epoch == "" {
  90. return si.Pkgver + "-" + si.Pkgrel
  91. }
  92. return si.Epoch + ":" + si.Pkgver + "-" + si.Pkgrel
  93. }
  94. // SplitPackages generates a splice of all packages that are part of this
  95. // srcinfo. This is equivalent to calling SplitPackage on every pkgname.
  96. func (si *Srcinfo) SplitPackages() []*Package {
  97. pkgs := make([]*Package, 0, len(si.Packages))
  98. for _, pkg := range si.Packages {
  99. pkgs = append(pkgs, mergeSplitPackage(&si.Package, &pkg))
  100. }
  101. return pkgs
  102. }
  103. // SplitPackage generates a Package that contains all fields that the specified
  104. // pkgname has. But will fall back on global fields if they are not defined in
  105. // the Package.
  106. //
  107. // Note slice values will be passed by reference, it is not recommended you
  108. // modify this struct after it is returned.
  109. func (si *Srcinfo) SplitPackage(pkgname string) (*Package, error) {
  110. for n := range si.Packages {
  111. if si.Packages[n].Pkgname == pkgname {
  112. return mergeSplitPackage(&si.Package, &si.Packages[n]), nil
  113. }
  114. }
  115. return nil, fmt.Errorf("Package \"%s\" is not part of the package base \"%s\"", pkgname, si.Pkgbase)
  116. }
  117. func mergeArchSlice(global, override []ArchString) []ArchString {
  118. overridden := make(map[string]struct{})
  119. merged := make([]ArchString, 0, len(override))
  120. for _, v := range override {
  121. overridden[v.Arch] = struct{}{}
  122. if v.Value == EmptyOverride {
  123. continue
  124. }
  125. merged = append(merged, v)
  126. }
  127. for _, v := range global {
  128. if _, ok := overridden[v.Arch]; !ok {
  129. merged = append(merged, v)
  130. }
  131. }
  132. return merged
  133. }
  134. func mergeSplitPackage(base, split *Package) *Package {
  135. pkg := &Package{}
  136. *pkg = *base
  137. pkg.Pkgname = split.Pkgname
  138. if split.Pkgdesc != "" {
  139. pkg.Pkgdesc = split.Pkgdesc
  140. }
  141. if len(split.Arch) != 0 {
  142. pkg.Arch = split.Arch
  143. }
  144. if split.URL != "" {
  145. pkg.URL = split.URL
  146. }
  147. if len(split.License) != 0 {
  148. pkg.License = split.License
  149. }
  150. if len(split.Groups) != 0 {
  151. pkg.Groups = split.Groups
  152. }
  153. if len(split.Depends) != 0 {
  154. pkg.Depends = mergeArchSlice(pkg.Depends, split.Depends)
  155. }
  156. if len(split.OptDepends) != 0 {
  157. pkg.OptDepends = mergeArchSlice(pkg.OptDepends, split.OptDepends)
  158. }
  159. if len(split.Provides) != 0 {
  160. pkg.Provides = mergeArchSlice(pkg.Provides, split.Provides)
  161. }
  162. if len(split.Conflicts) != 0 {
  163. pkg.Conflicts = mergeArchSlice(pkg.Conflicts, split.Conflicts)
  164. }
  165. if len(split.Replaces) != 0 {
  166. pkg.Replaces = mergeArchSlice(pkg.Replaces, split.Replaces)
  167. }
  168. if len(split.Backup) != 0 {
  169. pkg.Backup = split.Backup
  170. }
  171. if len(split.Options) != 0 {
  172. pkg.Options = split.Options
  173. }
  174. if split.Changelog != "" {
  175. pkg.Changelog = split.Changelog
  176. }
  177. if split.Install != "" {
  178. pkg.Install = split.Install
  179. }
  180. return pkg
  181. }