123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // Package srcinfo is a parser for srcinfo files. Typically generated by
- // makepkg, part of the pacman package manager.
- //
- // Split packages and architecture dependent fields are fully supported.
- //
- // This Package aimes to parse srcinfos but not interpret them in any way.
- // All values are fundamentally strings, other tools should be used for
- // things such as dependency parsing, validity checking etc.
- package srcinfo
- import (
- "fmt"
- )
- // ArchString describes string values that may be architecture dependent.
- // For Example depends_x86_64.
- // If Arch is an empty string then the field is not architecture dependent.
- type ArchString struct {
- Arch string // Architecture name
- Value string // Value
- }
- // Package describes the fields of a pkgbuild that may be overwritten by
- // in build_<pkgname> function.
- type Package struct {
- Pkgname string
- Pkgdesc string
- Arch []string
- URL string
- License []string
- Groups []string
- Depends []ArchString
- OptDepends []ArchString
- Provides []ArchString
- Conflicts []ArchString
- Replaces []ArchString
- Backup []string
- Options []string
- Install string
- Changelog string
- }
- // PackageBase describes the fields of a pkgbuild that may not be overwritten
- // in package_<pkgname> function.
- type PackageBase struct {
- Pkgbase string
- Pkgver string
- Pkgrel string
- Epoch string
- Source []ArchString
- ValidPGPKeys []string
- NoExtract []string
- MD5Sums []ArchString
- SHA1Sums []ArchString
- SHA224Sums []ArchString
- SHA256Sums []ArchString
- SHA384Sums []ArchString
- SHA512Sums []ArchString
- MakeDepends []ArchString
- CheckDepends []ArchString
- }
- // Srcinfo represents a full srcinfo. All global fields are defined here while
- // fields overwritten in the package_<pkgname> function are defined in the
- // Packages field.
- //
- // Note: The Packages field only contains the values that each package
- // overrides, global fields will be missing. A Package containing both global
- // and overwritten fields can be generated using the SplitPackage function.
- type Srcinfo struct {
- PackageBase // Fields that only apply to the package base
- Package // Fields that apply to the package globally
- Packages []Package // Fields for each package this package base contains
- }
- // EmptyOverride is used to signal when a value has been overridden with an
- // empty value. An empty ovrride is when a value is defined in the pkgbuild but
- // then overridden inside the package function to be empty.
- //
- // For example "pkgdesc=''" is an empty override on the pkgdesc which would
- // lead to the line "pkgdesc=" in the srcinfo.
- //
- // This value is used internally to store empty overrides, mainly to avoid
- // using string pointers. It is possible to check for empty overrides using
- // the Packages slice in Packagebase.
- //
- // During normal use with the SplitPackage function this value will be
- // converted back to an empty string, or removed entirely for slice values.
- // This means the this value can be completley ignored unless you are
- // explicitly looking for empty overrides.
- const EmptyOverride = "\x00"
- // Version formats a version string from the epoch, pkgver and pkgrel of the
- // srcinfo. In the format [epoch:]pkgver-pkgrel.
- func (si *Srcinfo) Version() string {
- if si.Epoch == "" {
- return si.Pkgver + "-" + si.Pkgrel
- }
- return si.Epoch + ":" + si.Pkgver + "-" + si.Pkgrel
- }
- // SplitPackages generates a splice of all packages that are part of this
- // srcinfo. This is equivalent to calling SplitPackage on every pkgname.
- func (si *Srcinfo) SplitPackages() []*Package {
- pkgs := make([]*Package, 0, len(si.Packages))
- for _, pkg := range si.Packages {
- pkgs = append(pkgs, mergeSplitPackage(&si.Package, &pkg))
- }
- return pkgs
- }
- // SplitPackage generates a Package that contains all fields that the specified
- // pkgname has. But will fall back on global fields if they are not defined in
- // the Package.
- //
- // Note slice values will be passed by reference, it is not recommended you
- // modify this struct after it is returned.
- func (si *Srcinfo) SplitPackage(pkgname string) (*Package, error) {
- for n := range si.Packages {
- if si.Packages[n].Pkgname == pkgname {
- return mergeSplitPackage(&si.Package, &si.Packages[n]), nil
- }
- }
- return nil, fmt.Errorf("Package \"%s\" is not part of the package base \"%s\"", pkgname, si.Pkgbase)
- }
- func mergeArchSlice(global, override []ArchString) []ArchString {
- overridden := make(map[string]struct{})
- merged := make([]ArchString, 0, len(override))
- for _, v := range override {
- overridden[v.Arch] = struct{}{}
- if v.Value == EmptyOverride {
- continue
- }
- merged = append(merged, v)
- }
- for _, v := range global {
- if _, ok := overridden[v.Arch]; !ok {
- merged = append(merged, v)
- }
- }
- return merged
- }
- func mergeSplitPackage(base, split *Package) *Package {
- pkg := &Package{}
- *pkg = *base
- pkg.Pkgname = split.Pkgname
- if split.Pkgdesc != "" {
- pkg.Pkgdesc = split.Pkgdesc
- }
- if len(split.Arch) != 0 {
- pkg.Arch = split.Arch
- }
- if split.URL != "" {
- pkg.URL = split.URL
- }
- if len(split.License) != 0 {
- pkg.License = split.License
- }
- if len(split.Groups) != 0 {
- pkg.Groups = split.Groups
- }
- if len(split.Depends) != 0 {
- pkg.Depends = mergeArchSlice(pkg.Depends, split.Depends)
- }
- if len(split.OptDepends) != 0 {
- pkg.OptDepends = mergeArchSlice(pkg.OptDepends, split.OptDepends)
- }
- if len(split.Provides) != 0 {
- pkg.Provides = mergeArchSlice(pkg.Provides, split.Provides)
- }
- if len(split.Conflicts) != 0 {
- pkg.Conflicts = mergeArchSlice(pkg.Conflicts, split.Conflicts)
- }
- if len(split.Replaces) != 0 {
- pkg.Replaces = mergeArchSlice(pkg.Replaces, split.Replaces)
- }
- if len(split.Backup) != 0 {
- pkg.Backup = split.Backup
- }
- if len(split.Options) != 0 {
- pkg.Options = split.Options
- }
- if split.Changelog != "" {
- pkg.Changelog = split.Changelog
- }
- if split.Install != "" {
- pkg.Install = split.Install
- }
- return pkg
- }
|