yay/vendor/github.com/Morganamilo/go-srcinfo/srcinfo.go
Anna d6b862357d Replace gopkgbuild with go-srcinfo (#528)
* Prefer vercmp over gopkgbuild

* Replace gopkgbuild with go-srcinfo
2018-07-16 15:28:18 +01:00

216 lines
5.9 KiB
Go

// 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
}