123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- package srcinfo
- import (
- "fmt"
- "io/ioutil"
- "strings"
- )
- // parser is used to track our current state as we parse the srcinfo.
- type parser struct {
- // srcinfo is a Pointer to the Srcinfo we are currently building.
- srcinfo *Srcinfo
- // seenPkgnames is a set of pkgnames we have seen
- seenPkgnames map[string]struct{}
- }
- func (psr *parser) currentPackage() (*Package, error) {
- if psr.srcinfo.Pkgbase == "" {
- return nil, fmt.Errorf("Not in pkgbase or pkgname")
- } else if len(psr.srcinfo.Packages) == 0 {
- return &psr.srcinfo.Package, nil
- } else {
- return &psr.srcinfo.Packages[len(psr.srcinfo.Packages) - 1], nil
- }
- }
- func (psr *parser) setHeaderOrField(key, value string) error {
- pkgbase := &psr.srcinfo.PackageBase
- switch key {
- case "pkgbase":
- if psr.srcinfo.Pkgbase != "" {
- return fmt.Errorf("key \"%s\" can not occur after pkgbase or pkgname", key)
- }
- pkgbase.Pkgbase = value
- return nil
- case "pkgname":
- if psr.srcinfo.Pkgbase == "" {
- return fmt.Errorf("key \"%s\" can not occur before pkgbase", key)
- }
- if _, ok := psr.seenPkgnames[value]; ok {
- return fmt.Errorf("pkgname \"%s\" can not occur more than once", value)
- }
- psr.seenPkgnames[value] = struct{}{}
- psr.srcinfo.Packages = append(psr.srcinfo.Packages, Package{Pkgname: value})
- return nil
- }
- if psr.srcinfo.Pkgbase == "" {
- return fmt.Errorf("key \"%s\" can not occur before pkgbase or pkgname", key)
- }
- return psr.setField(key, value)
- }
- func (psr *parser) setField(archKey, value string) error {
- pkg, err := psr.currentPackage()
- if err != nil {
- return err
- }
- pkgbase := &psr.srcinfo.PackageBase
- key, arch := splitArchFromKey(archKey)
- err = checkArch(psr.srcinfo.Arch, archKey, arch)
- if err != nil {
- return err
- }
- if value == "" {
- value = EmptyOverride
- }
- // pkgbase only + not arch dependent
- found := true
- switch archKey {
- case "pkgver":
- pkgbase.Pkgver = value
- case "pkgrel":
- pkgbase.Pkgrel = value
- case "epoch":
- pkgbase.Epoch = value
- case "validpgpkeys":
- pkgbase.ValidPGPKeys = append(pkgbase.ValidPGPKeys, value)
- case "noextract":
- pkgbase.NoExtract = append(pkgbase.NoExtract, value)
- default:
- found = false
- }
- if found {
- if len(psr.srcinfo.Packages) > 0 {
- return fmt.Errorf("key \"%s\" can not occur after pkgname", archKey)
- }
- return nil
- }
- // pkgbase only + arch dependent
- found = true
- switch key {
- case "source":
- pkgbase.Source = append(pkgbase.Source, ArchString{arch, value})
- case "md5sums":
- pkgbase.MD5Sums = append(pkgbase.MD5Sums, ArchString{arch, value})
- case "sha1sums":
- pkgbase.SHA1Sums = append(pkgbase.SHA1Sums, ArchString{arch, value})
- case "sha224sums":
- pkgbase.SHA224Sums = append(pkgbase.SHA224Sums, ArchString{arch, value})
- case "sha256sums":
- pkgbase.SHA256Sums = append(pkgbase.SHA256Sums, ArchString{arch, value})
- case "sha384sums":
- pkgbase.SHA384Sums = append(pkgbase.SHA384Sums, ArchString{arch, value})
- case "sha512sums":
- pkgbase.SHA512Sums = append(pkgbase.SHA512Sums, ArchString{arch, value})
- case "makedepends":
- pkgbase.MakeDepends = append(pkgbase.MakeDepends, ArchString{arch, value})
- case "checkdepends":
- pkgbase.CheckDepends = append(pkgbase.CheckDepends, ArchString{arch, value})
- default:
- found = false
- }
- if found {
- if len(psr.srcinfo.Packages) > 0 {
- return fmt.Errorf("key \"%s\" can not occur after pkgname", archKey)
- }
- return nil
- }
- // pkgbase or pkgname + not arch dependent
- found = true
- switch archKey {
- case "pkgdesc":
- pkg.Pkgdesc = value
- case "url":
- pkg.URL = value
- case "license":
- pkg.License = append(pkg.License, value)
- case "install":
- pkg.Install = value
- case "changelog":
- pkg.Changelog = value
- case "groups":
- pkg.Groups = append(pkg.Groups, value)
- case "arch":
- pkg.Arch = append(pkg.Arch, value)
- case "backup":
- pkg.Backup = append(pkg.Backup, value)
- case "options":
- pkg.Options = append(pkg.Options, value)
- default:
- found = false
- }
- if found {
- return nil
- }
- // pkgbase or pkgname + arch dependent
- switch key {
- case "depends":
- pkg.Depends = append(pkg.Depends, ArchString{arch, value})
- case "optdepends":
- pkg.OptDepends = append(pkg.OptDepends, ArchString{arch, value})
- case "conflicts":
- pkg.Conflicts = append(pkg.Conflicts, ArchString{arch, value})
- case "provides":
- pkg.Provides = append(pkg.Provides, ArchString{arch, value})
- case "replaces":
- pkg.Replaces = append(pkg.Replaces, ArchString{arch, value})
- default:
- return fmt.Errorf("Unknown key: \"%s\"", archKey)
- }
- return nil
- }
- func parse(data string) (*Srcinfo, error) {
- psr := &parser{
- &Srcinfo{},
- make(map[string]struct{}),
- }
- lines := strings.Split(data, "\n")
- for n, line := range lines {
- line = strings.TrimSpace(line)
- if line == "" || strings.HasPrefix(line, "#") {
- continue
- }
- key, value, err := splitPair(line)
- if err != nil {
- return nil, Error(n+1, line, err.Error())
- }
- err = psr.setHeaderOrField(key, value)
- if err != nil {
- return nil, Error(n+1, line, err.Error())
- }
- }
- if psr.srcinfo.Pkgbase == "" {
- return nil, fmt.Errorf("No pkgbase field")
- }
- if len(psr.srcinfo.Packages) == 0 {
- return nil, fmt.Errorf("No pkgname field")
- }
- if psr.srcinfo.Pkgver == "" {
- return nil, fmt.Errorf("No pkgver field")
- }
- if psr.srcinfo.Pkgrel == "" {
- return nil, fmt.Errorf("No pkgrel field")
- }
- if len(psr.srcinfo.Arch) == 0 {
- return nil, fmt.Errorf("No arch field")
- }
- return psr.srcinfo, nil
- }
- // splitPair splits a key value string in the form of "key = value",
- // whitespace being ignored. The key and the value is returned.
- func splitPair(line string) (string, string, error) {
- split := strings.SplitN(line, "=", 2)
- if len(split) != 2 {
- return "", "", fmt.Errorf("Line does not contain =")
- }
- key := strings.TrimSpace(split[0])
- value := strings.TrimSpace(split[1])
- if key == "" {
- return "", "", fmt.Errorf("Key is empty")
- }
- return key, value, nil
- }
- // splitArchFromKey splits up architecture dependent field names, separating
- // the field name from the architecture they depend on.
- func splitArchFromKey(key string) (string, string) {
- split := strings.SplitN(key, "_", 2)
- if len(split) == 2 {
- return split[0], split[1]
- }
- return split[0], ""
- }
- // checkArg checks that the arch from an arch dependent string is actually
- // defined inside of the srcinfo and speicifly disallows the arch "any" as it
- // is not a real arch
- func checkArch(arches []string, key string, arch string) error {
- if arch == "" {
- return nil
- }
- if arch == "any" {
- return fmt.Errorf("Invalid key \"%s\" arch \"%s\" is not allowed", key, arch)
- }
- for _, a := range arches {
- if a == arch {
- return nil
- }
- }
- return fmt.Errorf("Invalid key \"%s\" unsupported arch \"%s\"", key, arch)
- }
- // ParseFile parses a srcinfo file as specified by path.
- func ParseFile(path string) (*Srcinfo, error) {
- file, err := ioutil.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("Unable to read file: %s: %s", path, err.Error())
- }
- return Parse(string(file))
- }
- // Parse parses a srcinfo in string form. Parsing will fail if:
- // A srcinfo does not contain all required fields
- // The same pkgname is specified more then once
- // arch is missing
- // pkgver is mising
- // pkgrel is missing
- // An architecture specific field is defined for an architecture that does not exist
- // An unknown key is specified
- // An empty value is specified
- //
- // Required fields are:
- // pkgbase
- // pkname
- // arch
- // pkgrel
- // pkgver
- func Parse(data string) (*Srcinfo, error) {
- return parse(data)
- }
|