mirror of
https://github.com/Jguer/yay.git
synced 2024-11-07 17:47:21 +01:00
216 lines
5.9 KiB
Go
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
|
||
|
}
|