mirror of
https://github.com/Jguer/yay
synced 2024-10-05 23:59:13 +00:00
Replace gopkgbuild with go-srcinfo (#528)
* Prefer vercmp over gopkgbuild * Replace gopkgbuild with go-srcinfo
This commit is contained in:
parent
b1fb1b9656
commit
d6b862357d
14
Gopkg.lock
generated
14
Gopkg.lock
generated
|
@ -1,6 +1,12 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/Morganamilo/go-srcinfo"
|
||||
packages = ["."]
|
||||
revision = "368edc79b2c53cd9c065818fd4e65843ef3e9e11"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jguer/go-alpm"
|
||||
|
@ -13,15 +19,9 @@
|
|||
packages = ["."]
|
||||
revision = "837b260b8e90895c45737e2e72313fe5bce6f2c4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mikkeloscar/gopkgbuild"
|
||||
packages = ["."]
|
||||
revision = "2bb4f1f1db67f81fe50f9c1c4ad9db4f20fd6b22"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "456465ee334310996a51a2282bf4cfe9f6269db508479c962474d61a4ce0a08c"
|
||||
inputs-digest = "2a7c6ddb680b62cd3f3cf47a0dfdad617e4a42e29204c75ecf5be3271feda5e1"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -13,4 +13,4 @@
|
|||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mikkeloscar/gopkgbuild"
|
||||
name = "github.com/Morganamilo/go-srcinfo"
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"sync"
|
||||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
// gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
func (dp *depPool) checkInnerConflict(name string, conflict string, conflicts mapStringSet) {
|
||||
|
|
26
install.go
26
install.go
|
@ -8,9 +8,9 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
gosrc "github.com/Morganamilo/go-srcinfo"
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
// Install handles package installs
|
||||
|
@ -25,7 +25,7 @@ func install(parser *arguments) error {
|
|||
warnings := &aurWarnings{}
|
||||
|
||||
removeMake := false
|
||||
srcinfosStale := make(map[string]*gopkg.PKGBUILD)
|
||||
srcinfosStale := make(map[string]*gosrc.Srcinfo)
|
||||
|
||||
//remotenames: names of all non repo packages on the system
|
||||
_, _, localNames, remoteNames, err := filterPackages()
|
||||
|
@ -407,7 +407,7 @@ func install(parser *arguments) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getIncompatible(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) (stringSet, error) {
|
||||
func getIncompatible(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo, bases map[string][]*rpc.Pkg) (stringSet, error) {
|
||||
incompatible := make(stringSet)
|
||||
alpmArch, err := alpmHandle.Arch()
|
||||
if err != nil {
|
||||
|
@ -711,14 +711,14 @@ func editPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseSRCINFOFiles(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error {
|
||||
func parseSRCINFOFiles(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo, bases map[string][]*rpc.Pkg) error {
|
||||
for k, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
|
||||
str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
|
||||
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
|
||||
|
||||
pkgbuild, err := gopkg.ParseSRCINFO(filepath.Join(dir, ".SRCINFO"))
|
||||
pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", pkg.Name, err)
|
||||
}
|
||||
|
@ -729,14 +729,14 @@ func parseSRCINFOFiles(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bas
|
|||
return nil
|
||||
}
|
||||
|
||||
func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) {
|
||||
func tryParsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo, bases map[string][]*rpc.Pkg) {
|
||||
for k, pkg := range pkgs {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
|
||||
str := bold(cyan("::") + " Parsing SRCINFO (%d/%d): %s\n")
|
||||
fmt.Printf(str, k+1, len(pkgs), cyan(formatPkgbase(pkg, bases)))
|
||||
|
||||
pkgbuild, err := gopkg.ParseSRCINFO(filepath.Join(dir, ".SRCINFO"))
|
||||
pkgbuild, err := gosrc.ParseFile(filepath.Join(dir, ".SRCINFO"))
|
||||
if err != nil {
|
||||
fmt.Printf("cannot parse %s skipping: %s\n", pkg.Name, err)
|
||||
continue
|
||||
|
@ -752,15 +752,11 @@ func pkgBuildsToSkip(pkgs []*rpc.Pkg, targets stringSet) stringSet {
|
|||
for _, pkg := range pkgs {
|
||||
if config.ReDownload == "no" || (config.ReDownload == "yes" && !targets.get(pkg.Name)) {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase, ".SRCINFO")
|
||||
pkgbuild, err := gopkg.ParseSRCINFO(dir)
|
||||
pkgbuild, err := gosrc.ParseFile(dir)
|
||||
|
||||
if err == nil {
|
||||
versionRPC, errR := gopkg.NewCompleteVersion(pkg.Version)
|
||||
versionPKG, errP := gopkg.NewCompleteVersion(pkgbuild.Version())
|
||||
if errP == nil && errR == nil {
|
||||
if !versionRPC.Newer(versionPKG) {
|
||||
toSkip.set(pkg.PackageBase)
|
||||
}
|
||||
if alpm.VerCmp(pkgbuild.Version(), pkg.Version) > 0 {
|
||||
toSkip.set(pkg.PackageBase)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -833,7 +829,7 @@ func downloadPkgBuildsSources(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, inco
|
|||
return
|
||||
}
|
||||
|
||||
func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gopkg.PKGBUILD, parser *arguments, incompatible stringSet, conflicts mapStringSet) error {
|
||||
func buildInstallPkgBuilds(dp *depPool, do *depOrder, srcinfos map[string]*gosrc.Srcinfo, parser *arguments, incompatible stringSet, conflicts mapStringSet) error {
|
||||
for _, pkg := range do.Aur {
|
||||
dir := filepath.Join(config.BuildDir, pkg.PackageBase)
|
||||
built := true
|
||||
|
|
6
keys.go
6
keys.go
|
@ -7,8 +7,8 @@ import (
|
|||
"os/exec"
|
||||
"strings"
|
||||
|
||||
gosrc "github.com/Morganamilo/go-srcinfo"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
// pgpKeySet maps a PGP key with a list of PKGBUILDs that require it.
|
||||
|
@ -41,7 +41,7 @@ func (set pgpKeySet) get(key string) bool {
|
|||
|
||||
// checkPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
|
||||
// asks the user whether yay should try to import them.
|
||||
func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD) error {
|
||||
func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, srcinfos map[string]*gosrc.Srcinfo) error {
|
||||
// Let's check the keys individually, and then we can offer to import
|
||||
// the problematic ones.
|
||||
problematic := make(pgpKeySet)
|
||||
|
@ -51,7 +51,7 @@ func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, srcinfos map[str
|
|||
for _, pkg := range pkgs {
|
||||
srcinfo := srcinfos[pkg.PackageBase]
|
||||
|
||||
for _, key := range srcinfo.Validpgpkeys {
|
||||
for _, key := range srcinfo.ValidPGPKeys {
|
||||
// If key already marked as problematic, indicate the current
|
||||
// PKGBUILD requires it.
|
||||
if problematic.get(key) {
|
||||
|
|
26
keys_test.go
26
keys_test.go
|
@ -11,8 +11,8 @@ import (
|
|||
"regexp"
|
||||
"testing"
|
||||
|
||||
gosrc "github.com/Morganamilo/go-srcinfo"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -124,6 +124,14 @@ func TestImportKeys(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func makeSrcinfo(pkgbase string, pgpkeys ...string) *gosrc.Srcinfo {
|
||||
srcinfo := gosrc.Srcinfo{}
|
||||
srcinfo.Pkgbase = pkgbase
|
||||
srcinfo.ValidPGPKeys = pgpkeys
|
||||
|
||||
return &srcinfo
|
||||
}
|
||||
|
||||
func TestCheckPgpKeys(t *testing.T) {
|
||||
keyringDir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
|
||||
if err != nil {
|
||||
|
@ -139,7 +147,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
|
||||
casetests := []struct {
|
||||
pkgs []*rpc.Pkg
|
||||
srcinfos map[string]*gopkg.PKGBUILD
|
||||
srcinfos map[string]*gosrc.Srcinfo
|
||||
bases map[string][]*rpc.Pkg
|
||||
wantError bool
|
||||
}{
|
||||
|
@ -147,7 +155,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
// 487EACC08557AD082088DABA1EB2638FF56C0C53: Dave Reisner.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("cower")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"cower": {Pkgbase: "cower", Validpgpkeys: []string{"487EACC08557AD082088DABA1EB2638FF56C0C53"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"cower": makeSrcinfo("cower", "487EACC08557AD082088DABA1EB2638FF56C0C53")},
|
||||
bases: map[string][]*rpc.Pkg{"cower": {newPkg("cower")}},
|
||||
wantError: false,
|
||||
},
|
||||
|
@ -156,7 +164,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
// B6C8F98282B944E3B0D5C2530FC3042E345AD05D: Hans Wennborg.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("libc++")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"libc++": {Pkgbase: "libc++", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"libc++": makeSrcinfo("libc++", "11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D")},
|
||||
bases: map[string][]*rpc.Pkg{"libc++": {newPkg("libc++")}},
|
||||
wantError: false,
|
||||
},
|
||||
|
@ -164,7 +172,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
// ABAF11C65A2970B130ABE3C479BE3E4300411886: Linus Torvalds.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("dummy-1"), newPkg("dummy-2")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"dummy-1": {Pkgbase: "dummy-1", Validpgpkeys: []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}}, "dummy-2": {Pkgbase: "dummy-2", Validpgpkeys: []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"dummy-1": makeSrcinfo("dummy-1", "ABAF11C65A2970B130ABE3C479BE3E4300411886"), "dummy-2": makeSrcinfo("dummy-2", "ABAF11C65A2970B130ABE3C479BE3E4300411886")},
|
||||
bases: map[string][]*rpc.Pkg{"dummy-1": {newPkg("dummy-1")}, "dummy-2": {newPkg("dummy-2")}},
|
||||
wantError: false,
|
||||
},
|
||||
|
@ -174,21 +182,21 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
// C52048C0C0748FEE227D47A2702353E0F7E48EDB: Thomas Dickey.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("dummy-3")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"dummy-3": {Pkgbase: "dummy-3", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"dummy-3": makeSrcinfo("dummy-3", "11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB")},
|
||||
bases: map[string][]*rpc.Pkg{"dummy-3": {newPkg("dummy-3")}},
|
||||
wantError: false,
|
||||
},
|
||||
// Two dummy packages with existing keys.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("dummy-4"), newPkg("dummy-5")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"dummy-4": {Pkgbase: "dummy-4", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294"}}, "dummy-5": {Pkgbase: "dummy-5", Validpgpkeys: []string{"C52048C0C0748FEE227D47A2702353E0F7E48EDB"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"dummy-4": makeSrcinfo("dummy-4", "11E521D646982372EB577A1F8F0871F202119294"), "dummy-5": makeSrcinfo("dummy-5", "C52048C0C0748FEE227D47A2702353E0F7E48EDB")},
|
||||
bases: map[string][]*rpc.Pkg{"dummy-4": {newPkg("dummy-4")}, "dummy-5": {newPkg("dummy-5")}},
|
||||
wantError: false,
|
||||
},
|
||||
// Dummy package with invalid key, should fail.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("dummy-7")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"dummy-7": {Pkgbase: "dummy-7", Validpgpkeys: []string{"THIS-SHOULD-FAIL"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"dummy-7": makeSrcinfo("dummy-7", "THIS-SHOULD-FAIL")},
|
||||
bases: map[string][]*rpc.Pkg{"dummy-7": {newPkg("dummy-7")}},
|
||||
wantError: true,
|
||||
},
|
||||
|
@ -196,7 +204,7 @@ func TestCheckPgpKeys(t *testing.T) {
|
|||
// A314827C4E4250A204CE6E13284FC34C8E4B1A25: Thomas Bächler.
|
||||
{
|
||||
pkgs: []*rpc.Pkg{newPkg("dummy-8")},
|
||||
srcinfos: map[string]*gopkg.PKGBUILD{"dummy-8": {Pkgbase: "dummy-8", Validpgpkeys: []string{"A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL"}}},
|
||||
srcinfos: map[string]*gosrc.Srcinfo{"dummy-8": makeSrcinfo("dummy-8", "A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL")},
|
||||
bases: map[string][]*rpc.Pkg{"dummy-8": {newPkg("dummy-8")}},
|
||||
wantError: true,
|
||||
},
|
||||
|
|
88
upgrade.go
88
upgrade.go
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
alpm "github.com/jguer/go-alpm"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
pkgb "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
// upgrade type describes a system upgrade.
|
||||
|
@ -63,64 +62,49 @@ func (u upSlice) Less(i, j int) bool {
|
|||
|
||||
}
|
||||
|
||||
func getVersionDiff(oldVersion, newversion string) (left, right string) {
|
||||
old, errOld := pkgb.NewCompleteVersion(oldVersion)
|
||||
new, errNew := pkgb.NewCompleteVersion(newversion)
|
||||
|
||||
if errOld != nil {
|
||||
left = red("Invalid Version")
|
||||
}
|
||||
if errNew != nil {
|
||||
right = red("Invalid Version")
|
||||
func getVersionDiff(oldVersion, newVersion string) (left, right string) {
|
||||
if oldVersion == newVersion {
|
||||
return oldVersion, newVersion
|
||||
}
|
||||
|
||||
if errOld == nil && errNew == nil {
|
||||
oldVersion := old.String()
|
||||
newVersion := new.String()
|
||||
diffPosition := 0
|
||||
|
||||
if oldVersion == newVersion {
|
||||
return oldVersion, newVersion
|
||||
}
|
||||
|
||||
diffPosition := 0
|
||||
|
||||
checkWords := func(str string, index int, words ...string) bool {
|
||||
for _, word := range words {
|
||||
wordLength := len(word)
|
||||
nextIndex := index + 1
|
||||
if (index < len(str)-wordLength) &&
|
||||
(str[nextIndex:(nextIndex+wordLength)] == word) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for index, char := range oldVersion {
|
||||
charIsSpecial := !(unicode.IsLetter(char) || unicode.IsNumber(char))
|
||||
|
||||
if (index >= len(newVersion)) || (char != rune(newVersion[index])) {
|
||||
if charIsSpecial {
|
||||
diffPosition = index
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if charIsSpecial ||
|
||||
(((index == len(oldVersion)-1) || (index == len(newVersion)-1)) &&
|
||||
((len(oldVersion) != len(newVersion)) ||
|
||||
(oldVersion[index] == newVersion[index]))) ||
|
||||
checkWords(oldVersion, index, "rc", "pre", "alpha", "beta") {
|
||||
diffPosition = index + 1
|
||||
checkWords := func(str string, index int, words ...string) bool {
|
||||
for _, word := range words {
|
||||
wordLength := len(word)
|
||||
nextIndex := index + 1
|
||||
if (index < len(str)-wordLength) &&
|
||||
(str[nextIndex:(nextIndex+wordLength)] == word) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
samePart := oldVersion[0:diffPosition]
|
||||
|
||||
left = samePart + red(oldVersion[diffPosition:])
|
||||
right = samePart + green(newVersion[diffPosition:])
|
||||
return false
|
||||
}
|
||||
|
||||
for index, char := range oldVersion {
|
||||
charIsSpecial := !(unicode.IsLetter(char) || unicode.IsNumber(char))
|
||||
|
||||
if (index >= len(newVersion)) || (char != rune(newVersion[index])) {
|
||||
if charIsSpecial {
|
||||
diffPosition = index
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if charIsSpecial ||
|
||||
(((index == len(oldVersion)-1) || (index == len(newVersion)-1)) &&
|
||||
((len(oldVersion) != len(newVersion)) ||
|
||||
(oldVersion[index] == newVersion[index]))) ||
|
||||
checkWords(oldVersion, index, "rc", "pre", "alpha", "beta") {
|
||||
diffPosition = index + 1
|
||||
}
|
||||
}
|
||||
|
||||
samePart := oldVersion[0:diffPosition]
|
||||
|
||||
left = samePart + red(oldVersion[diffPosition:])
|
||||
right = samePart + green(newVersion[diffPosition:])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
8
vcs.go
8
vcs.go
|
@ -9,8 +9,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
gosrc "github.com/Morganamilo/go-srcinfo"
|
||||
rpc "github.com/mikkeloscar/aur"
|
||||
gopkg "github.com/mikkeloscar/gopkgbuild"
|
||||
)
|
||||
|
||||
// Info contains the last commit sha of a repo
|
||||
|
@ -25,7 +25,7 @@ type shaInfo struct {
|
|||
// createDevelDB forces yay to create a DB of the existing development packages
|
||||
func createDevelDB() error {
|
||||
infoMap := make(map[string]*rpc.Pkg)
|
||||
srcinfosStale := make(map[string]*gopkg.PKGBUILD)
|
||||
srcinfosStale := make(map[string]*gosrc.Srcinfo)
|
||||
|
||||
_, _, _, remoteNames, err := filterPackages()
|
||||
if err != nil {
|
||||
|
@ -103,7 +103,7 @@ func parseSource(source string) (url string, branch string, protocols []string)
|
|||
return
|
||||
}
|
||||
|
||||
func updateVCSData(pkgName string, sources []string) {
|
||||
func updateVCSData(pkgName string, sources []gosrc.ArchString) {
|
||||
if savedInfo == nil {
|
||||
savedInfo = make(vcsInfo)
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func updateVCSData(pkgName string, sources []string) {
|
|||
info := make(shaInfos)
|
||||
|
||||
for _, source := range sources {
|
||||
url, branch, protocols := parseSource(source)
|
||||
url, branch, protocols := parseSource(source.Value)
|
||||
if url == "" || branch == "" {
|
||||
continue
|
||||
}
|
||||
|
|
38
vendor/github.com/Morganamilo/go-srcinfo/line_error.go
generated
vendored
Normal file
38
vendor/github.com/Morganamilo/go-srcinfo/line_error.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package srcinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// LineError is an error type that stores the line number at which an error
|
||||
// occurred as well the full Line that cased the error and an error string.
|
||||
type LineError struct {
|
||||
LineNumber int // The line number at which the error occurred
|
||||
Line string // The line that caused the error
|
||||
ErrorStr string // An error string
|
||||
}
|
||||
|
||||
// Error Returns an error string in the format:
|
||||
// "Line <LineNumber>: <ErrorStr>: <Line>".
|
||||
func (le LineError) Error() string {
|
||||
return fmt.Sprintf("Line %d: %s: %s", le.LineNumber, le.ErrorStr, le.Line)
|
||||
}
|
||||
|
||||
// Error Returns a new LineError
|
||||
func Error(LineNumber int, Line string, ErrorStr string) *LineError {
|
||||
return &LineError{
|
||||
LineNumber,
|
||||
Line,
|
||||
ErrorStr,
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf Returns a new LineError using the same formatting rules as
|
||||
// fmt.Printf.
|
||||
func Errorf(LineNumber int, Line string, ErrorStr string, args ...interface{}) *LineError {
|
||||
return &LineError{
|
||||
LineNumber,
|
||||
Line,
|
||||
fmt.Sprintf(ErrorStr, args...),
|
||||
}
|
||||
}
|
310
vendor/github.com/Morganamilo/go-srcinfo/parser.go
generated
vendored
Normal file
310
vendor/github.com/Morganamilo/go-srcinfo/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
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)
|
||||
}
|
155
vendor/github.com/Morganamilo/go-srcinfo/printsrcinfo.go
generated
vendored
Normal file
155
vendor/github.com/Morganamilo/go-srcinfo/printsrcinfo.go
generated
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
package srcinfo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
func appendHeader(buffer *bytes.Buffer, key string, value string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
|
||||
buffer.WriteString(key + " = " + value + "\n")
|
||||
}
|
||||
|
||||
func appendValue(buffer *bytes.Buffer, key string, value string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if value == EmptyOverride {
|
||||
value = ""
|
||||
}
|
||||
|
||||
buffer.WriteString("\t" + key + " = " + value + "\n")
|
||||
}
|
||||
|
||||
func appendMultiValue(buffer *bytes.Buffer, key string, values []string) {
|
||||
for _, value := range values {
|
||||
if value == EmptyOverride {
|
||||
value = ""
|
||||
}
|
||||
|
||||
buffer.WriteString("\t" + key + " = " + value + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
func appendMultiArchValue(buffer *bytes.Buffer, key string, values []ArchString) {
|
||||
for _, value := range values {
|
||||
if value.Value == EmptyOverride {
|
||||
value.Value = ""
|
||||
}
|
||||
|
||||
if value.Arch == "" {
|
||||
buffer.WriteString("\t" + key + " = " + value.Value + "\n")
|
||||
} else {
|
||||
buffer.WriteString("\t" + key + "_" + value.Arch + " = " + value.Value + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//String generates a string that should be similar to the srcinfo data used to
|
||||
//create this Srcinfo struct. Fields will be printed in order and with the same
|
||||
//whitespcae rules that `makepkg --printsrcinfo` uses.
|
||||
//
|
||||
// The order of each global field is as follows:
|
||||
// pkgdesc
|
||||
// pkgver
|
||||
// pkgrel
|
||||
// epoch
|
||||
// url
|
||||
// install
|
||||
// changelog
|
||||
// arch
|
||||
// groups
|
||||
// license
|
||||
// checkdepends
|
||||
// makedepends
|
||||
// depends
|
||||
// optdepends
|
||||
// provides
|
||||
// conflicts
|
||||
// replaces
|
||||
// noextract
|
||||
// options
|
||||
// backup
|
||||
// source
|
||||
// validpgpkeys
|
||||
// md5suns
|
||||
// sha1sums
|
||||
// sha224sums
|
||||
// sha256sums
|
||||
// sha384sums
|
||||
// sha512sums
|
||||
//
|
||||
// The order of each overwritten field is as follows:
|
||||
// pkgdesc
|
||||
// url
|
||||
// install
|
||||
// changelog
|
||||
// arch
|
||||
// groups
|
||||
// license
|
||||
// checkdepends
|
||||
// depends
|
||||
// optdepends
|
||||
// provides
|
||||
// conflicts
|
||||
// replaces
|
||||
// options
|
||||
// backup
|
||||
func (si *Srcinfo) String() string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
appendHeader(&buffer, "pkgbase", si.Pkgbase)
|
||||
|
||||
appendValue(&buffer, "pkgdesc", si.Pkgdesc)
|
||||
appendValue(&buffer, "pkgver", si.Pkgver)
|
||||
appendValue(&buffer, "pkgrel", si.Pkgrel)
|
||||
appendValue(&buffer, "epoch", si.Epoch)
|
||||
appendValue(&buffer, "url", si.URL)
|
||||
appendValue(&buffer, "install", si.Install)
|
||||
appendValue(&buffer, "changelog", si.Changelog)
|
||||
appendMultiValue(&buffer, "arch", si.Arch)
|
||||
appendMultiValue(&buffer, "groups", si.Groups)
|
||||
appendMultiValue(&buffer, "license", si.License)
|
||||
appendMultiArchValue(&buffer, "checkdepends", si.CheckDepends)
|
||||
appendMultiArchValue(&buffer, "makedepends", si.MakeDepends)
|
||||
appendMultiArchValue(&buffer, "depends", si.Depends)
|
||||
appendMultiArchValue(&buffer, "optdepends", si.OptDepends)
|
||||
appendMultiArchValue(&buffer, "provides", si.Provides)
|
||||
appendMultiArchValue(&buffer, "conflicts", si.Conflicts)
|
||||
appendMultiArchValue(&buffer, "replaces", si.Replaces)
|
||||
appendMultiValue(&buffer, "noextract", si.NoExtract)
|
||||
appendMultiValue(&buffer, "options", si.Options)
|
||||
appendMultiValue(&buffer, "backup", si.Backup)
|
||||
appendMultiValue(&buffer, "validpgpkeys", si.ValidPGPKeys)
|
||||
appendMultiArchValue(&buffer, "source", si.Source)
|
||||
appendMultiArchValue(&buffer, "md5sums", si.MD5Sums)
|
||||
appendMultiArchValue(&buffer, "sha1sums", si.SHA1Sums)
|
||||
appendMultiArchValue(&buffer, "sha224sums", si.SHA224Sums)
|
||||
appendMultiArchValue(&buffer, "sha256sums", si.SHA256Sums)
|
||||
appendMultiArchValue(&buffer, "sha384sums", si.SHA384Sums)
|
||||
appendMultiArchValue(&buffer, "sha512sums", si.SHA512Sums)
|
||||
|
||||
for n, pkg := range si.Packages {
|
||||
appendHeader(&buffer, "\npkgname", si.Packages[n].Pkgname)
|
||||
|
||||
appendValue(&buffer, "pkgdesc", pkg.Pkgdesc)
|
||||
appendValue(&buffer, "url", pkg.URL)
|
||||
appendValue(&buffer, "install", pkg.Install)
|
||||
appendValue(&buffer, "changelog", pkg.Changelog)
|
||||
appendMultiValue(&buffer, "arch", pkg.Arch)
|
||||
appendMultiValue(&buffer, "groups", pkg.Groups)
|
||||
appendMultiValue(&buffer, "license", pkg.License)
|
||||
appendMultiArchValue(&buffer, "depends", pkg.Depends)
|
||||
appendMultiArchValue(&buffer, "optdepends", pkg.OptDepends)
|
||||
appendMultiArchValue(&buffer, "provides", pkg.Provides)
|
||||
appendMultiArchValue(&buffer, "conflicts", pkg.Conflicts)
|
||||
appendMultiArchValue(&buffer, "replaces", pkg.Replaces)
|
||||
appendMultiValue(&buffer, "options", pkg.Options)
|
||||
appendMultiValue(&buffer, "backup", pkg.Backup)
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
215
vendor/github.com/Morganamilo/go-srcinfo/srcinfo.go
generated
vendored
Normal file
215
vendor/github.com/Morganamilo/go-srcinfo/srcinfo.go
generated
vendored
Normal file
|
@ -0,0 +1,215 @@
|
|||
// 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
|
||||
}
|
283
vendor/github.com/mikkeloscar/gopkgbuild/lex.go
generated
vendored
283
vendor/github.com/mikkeloscar/gopkgbuild/lex.go
generated
vendored
|
@ -1,283 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// based on the lexer from: src/pkg/text/template/parse/lex.go (golang source)
|
||||
|
||||
package pkgbuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// pos is a position in input being scanned
|
||||
type pos int
|
||||
|
||||
type item struct {
|
||||
typ itemType
|
||||
pos pos
|
||||
val string
|
||||
}
|
||||
|
||||
func (i item) String() string {
|
||||
switch {
|
||||
case i.typ == itemEOF:
|
||||
return "EOF"
|
||||
case i.typ == itemError:
|
||||
return i.val
|
||||
case len(i.val) > 10:
|
||||
return fmt.Sprintf("%.10q...", i.val)
|
||||
}
|
||||
return fmt.Sprintf("%q", i.val)
|
||||
}
|
||||
|
||||
type itemType int
|
||||
|
||||
const (
|
||||
itemError itemType = iota
|
||||
itemEOF
|
||||
itemVariable
|
||||
itemValue
|
||||
itemEndSplit
|
||||
// PKGBUILD variables
|
||||
itemPkgname // pkgname variable
|
||||
itemPkgver // pkgver variable
|
||||
itemPkgrel // pkgrel variable
|
||||
itemPkgdir // pkgdir variable
|
||||
itemEpoch // epoch variable
|
||||
itemPkgbase // pkgbase variable
|
||||
itemPkgdesc // pkgdesc variable
|
||||
itemArch // arch variable
|
||||
itemURL // url variable
|
||||
itemLicense // license variable
|
||||
itemGroups // groups variable
|
||||
itemDepends // depends variable
|
||||
itemOptdepends // optdepends variable
|
||||
itemMakedepends // makedepends variable
|
||||
itemCheckdepends // checkdepends variable
|
||||
itemProvides // provides variable
|
||||
itemConflicts // conflicts variable
|
||||
itemReplaces // replaces variable
|
||||
itemBackup // backup variable
|
||||
itemOptions // options variable
|
||||
itemInstall // install variable
|
||||
itemChangelog // changelog variable
|
||||
itemSource // source variable
|
||||
itemNoextract // noextract variable
|
||||
itemMd5sums // md5sums variable
|
||||
itemSha1sums // sha1sums variable
|
||||
itemSha224sums // sha224sums variable
|
||||
itemSha256sums // sha256sums variable
|
||||
itemSha384sums // sha384sums variable
|
||||
itemSha512sums // sha512sums variable
|
||||
itemValidpgpkeys // validpgpkeys variable
|
||||
)
|
||||
|
||||
// PKGBUILD variables
|
||||
var variables = map[string]itemType{
|
||||
"pkgname": itemPkgname,
|
||||
"pkgver": itemPkgver,
|
||||
"pkgrel": itemPkgrel,
|
||||
"pkgdir": itemPkgdir,
|
||||
"epoch": itemEpoch,
|
||||
"pkgbase": itemPkgbase,
|
||||
"pkgdesc": itemPkgdesc,
|
||||
"arch": itemArch,
|
||||
"url": itemURL,
|
||||
"license": itemLicense,
|
||||
"groups": itemGroups,
|
||||
"depends": itemDepends,
|
||||
"optdepends": itemOptdepends,
|
||||
"makedepends": itemMakedepends,
|
||||
"checkdepends": itemCheckdepends,
|
||||
"provides": itemProvides,
|
||||
"conflicts": itemConflicts,
|
||||
"replaces": itemReplaces,
|
||||
"backup": itemBackup,
|
||||
"options": itemOptions,
|
||||
"install": itemInstall,
|
||||
"changelog": itemChangelog,
|
||||
"source": itemSource,
|
||||
"noextract": itemNoextract,
|
||||
"md5sums": itemMd5sums,
|
||||
"sha1sums": itemSha1sums,
|
||||
"sha224sums": itemSha224sums,
|
||||
"sha256sums": itemSha256sums,
|
||||
"sha384sums": itemSha384sums,
|
||||
"sha512sums": itemSha512sums,
|
||||
"validpgpkeys": itemValidpgpkeys,
|
||||
}
|
||||
|
||||
const eof = -1
|
||||
|
||||
// stateFn represents the state of the scanner as a function that returns the next state
|
||||
type stateFn func(*lexer) stateFn
|
||||
|
||||
// lexer holds the state of the scanner
|
||||
type lexer struct {
|
||||
input string
|
||||
state stateFn
|
||||
pos pos
|
||||
start pos
|
||||
width pos
|
||||
lastPos pos
|
||||
items chan item // channel of scanned items
|
||||
}
|
||||
|
||||
// next returns the next rune in the input
|
||||
func (l *lexer) next() rune {
|
||||
if int(l.pos) >= len(l.input) {
|
||||
l.width = 0
|
||||
return eof
|
||||
}
|
||||
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
|
||||
l.width = pos(w)
|
||||
l.pos += l.width
|
||||
return r
|
||||
}
|
||||
|
||||
// peek returns but does not consume the next rune in the input
|
||||
func (l *lexer) peek() rune {
|
||||
r := l.next()
|
||||
l.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
// backup steps back one rune. Can only be called once per call of next
|
||||
func (l *lexer) backup() {
|
||||
l.pos -= l.width
|
||||
}
|
||||
|
||||
// emit passes an item back to the client
|
||||
func (l *lexer) emit(t itemType) {
|
||||
l.items <- item{t, l.start, l.input[l.start:l.pos]}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
// ignore skips over the pending input before this point
|
||||
func (l *lexer) ignore() {
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
// errorf returns an error token and terminates the scan by passing
|
||||
// back a nil pointer that will be the next state, terminating l.nextItem.
|
||||
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
|
||||
l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
|
||||
return nil
|
||||
}
|
||||
|
||||
// nextItem returns the next item from the input.
|
||||
func (l *lexer) nextItem() item {
|
||||
item := <-l.items
|
||||
l.lastPos = item.pos
|
||||
return item
|
||||
}
|
||||
|
||||
func lex(input string) *lexer {
|
||||
l := &lexer{
|
||||
input: input,
|
||||
items: make(chan item),
|
||||
}
|
||||
go l.run()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *lexer) run() {
|
||||
for l.state = lexEnv; l.state != nil; {
|
||||
l.state = l.state(l)
|
||||
}
|
||||
}
|
||||
|
||||
func lexEnv(l *lexer) stateFn {
|
||||
var r rune
|
||||
for {
|
||||
switch r = l.next(); {
|
||||
case r == eof:
|
||||
l.emit(itemEOF)
|
||||
return nil
|
||||
case isAlphaNumericUnderscore(r):
|
||||
return lexVariable
|
||||
case r == '\n':
|
||||
buffer := l.input[l.start:l.pos]
|
||||
if buffer == "\n" {
|
||||
if l.peek() == '\n' {
|
||||
l.next()
|
||||
l.emit(itemEndSplit)
|
||||
}
|
||||
l.ignore()
|
||||
}
|
||||
case r == '\t':
|
||||
l.ignore()
|
||||
case r == ' ':
|
||||
l.ignore()
|
||||
case r == '#':
|
||||
return lexComment
|
||||
default:
|
||||
l.errorf("unable to parse character: %c", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lexComment(l *lexer) stateFn {
|
||||
for {
|
||||
switch l.next() {
|
||||
case '\n':
|
||||
l.ignore()
|
||||
return lexEnv
|
||||
case eof:
|
||||
l.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lexVariable(l *lexer) stateFn {
|
||||
for {
|
||||
switch r := l.next(); {
|
||||
case isAlphaNumericUnderscore(r):
|
||||
// absorb
|
||||
case r == ' ' && l.peek() == '=':
|
||||
l.backup()
|
||||
variable := l.input[l.start:l.pos]
|
||||
|
||||
// strip arch from source_arch like constructs
|
||||
witharch := strings.SplitN(variable, "_", 2)
|
||||
if len(witharch) == 2 {
|
||||
variable = witharch[0]
|
||||
}
|
||||
|
||||
if _, ok := variables[variable]; ok {
|
||||
l.emit(variables[variable])
|
||||
// TODO to cut off ' = '
|
||||
l.next()
|
||||
l.next()
|
||||
l.next()
|
||||
l.ignore()
|
||||
return lexValue
|
||||
}
|
||||
return l.errorf("invalid variable: %s", variable)
|
||||
default:
|
||||
pattern := l.input[l.start:l.pos]
|
||||
return l.errorf("invalid pattern: %s", pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lexValue(l *lexer) stateFn {
|
||||
for {
|
||||
switch l.next() {
|
||||
case '\n':
|
||||
l.backup()
|
||||
l.emit(itemValue)
|
||||
return lexEnv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isAlphaNumericUnderscore reports whether r is an alphabetic, digit, or underscore.
|
||||
func isAlphaNumericUnderscore(r rune) bool {
|
||||
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
|
||||
}
|
625
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go
generated
vendored
625
vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go
generated
vendored
|
@ -1,625 +0,0 @@
|
|||
package pkgbuild
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Dependency describes a dependency with min and max version, if any.
|
||||
type Dependency struct {
|
||||
Name string // dependency name
|
||||
MinVer *CompleteVersion // min version
|
||||
sgt bool // defines if min version is strictly greater than
|
||||
MaxVer *CompleteVersion // max version
|
||||
slt bool // defines if max version is strictly less than
|
||||
}
|
||||
|
||||
// Restrict merges two dependencies together into a new dependency where the
|
||||
// conditions of both a and b are met
|
||||
func (a *Dependency) Restrict(b *Dependency) *Dependency {
|
||||
newDep := &Dependency{
|
||||
Name: a.Name,
|
||||
}
|
||||
|
||||
if a.MaxVer != nil || b.MaxVer != nil {
|
||||
newDep.MaxVer = &CompleteVersion{}
|
||||
|
||||
if a.MaxVer == nil {
|
||||
*newDep.MaxVer = *b.MaxVer
|
||||
newDep.slt = b.slt
|
||||
} else if b.MaxVer == nil {
|
||||
*newDep.MaxVer = *a.MaxVer
|
||||
newDep.slt = a.slt
|
||||
} else {
|
||||
cmpMax := a.MaxVer.cmp(b.MaxVer)
|
||||
if cmpMax >= 1 {
|
||||
*newDep.MaxVer = *b.MaxVer
|
||||
newDep.slt = b.slt
|
||||
} else if cmpMax <= -1 {
|
||||
*newDep.MaxVer = *a.MaxVer
|
||||
newDep.slt = a.slt
|
||||
} else if cmpMax == 0 {
|
||||
if len(a.MaxVer.Pkgrel) > len(b.MaxVer.Pkgrel) {
|
||||
*newDep.MaxVer = *a.MaxVer
|
||||
} else {
|
||||
*newDep.MaxVer = *b.MaxVer
|
||||
}
|
||||
if a.slt != b.slt {
|
||||
newDep.slt = true
|
||||
} else {
|
||||
newDep.slt = a.slt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if a.MinVer != nil || b.MinVer != nil {
|
||||
newDep.MinVer = &CompleteVersion{}
|
||||
|
||||
if a.MinVer == nil {
|
||||
*newDep.MinVer = *b.MinVer
|
||||
newDep.sgt = b.slt
|
||||
} else if b.MinVer == nil {
|
||||
*newDep.MinVer = *a.MinVer
|
||||
newDep.sgt = a.sgt
|
||||
} else {
|
||||
cmpMin := a.MinVer.cmp(b.MinVer)
|
||||
if cmpMin >= 1 {
|
||||
*newDep.MinVer = *a.MinVer
|
||||
newDep.sgt = a.sgt
|
||||
} else if cmpMin <= -1 {
|
||||
*newDep.MinVer = *b.MinVer
|
||||
newDep.sgt = b.sgt
|
||||
} else if cmpMin == 0 {
|
||||
if len(a.MinVer.Pkgrel) > len(b.MinVer.Pkgrel) {
|
||||
*newDep.MinVer = *a.MinVer
|
||||
} else {
|
||||
*newDep.MinVer = *b.MinVer
|
||||
}
|
||||
if a.sgt != b.sgt {
|
||||
newDep.sgt = true
|
||||
} else {
|
||||
newDep.sgt = a.sgt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newDep
|
||||
}
|
||||
|
||||
func (dep *Dependency) String() string {
|
||||
str := ""
|
||||
greaterThan := ">"
|
||||
lessThan := "<"
|
||||
|
||||
if !dep.sgt {
|
||||
greaterThan = ">="
|
||||
}
|
||||
|
||||
if !dep.slt {
|
||||
lessThan = "<="
|
||||
}
|
||||
|
||||
if dep.MinVer != nil {
|
||||
str += dep.Name + greaterThan + dep.MinVer.String()
|
||||
|
||||
if dep.MaxVer != nil {
|
||||
str += " "
|
||||
}
|
||||
}
|
||||
|
||||
if dep.MaxVer != nil {
|
||||
str += dep.Name + lessThan + dep.MaxVer.String()
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// PKGBUILD is a struct describing a parsed PKGBUILD file.
|
||||
// Required fields are:
|
||||
// pkgname
|
||||
// pkgver
|
||||
// pkgrel
|
||||
// arch
|
||||
// (license) - not required but recommended
|
||||
//
|
||||
// parsing a PKGBUILD file without these fields will fail
|
||||
type PKGBUILD struct {
|
||||
Pkgnames []string
|
||||
Pkgver Version // required
|
||||
Pkgrel Version // required
|
||||
Pkgdir string
|
||||
Epoch int
|
||||
Pkgbase string
|
||||
Pkgdesc string
|
||||
Arch []string // required
|
||||
URL string
|
||||
License []string // recommended
|
||||
Groups []string
|
||||
Depends []*Dependency
|
||||
Optdepends []string
|
||||
Makedepends []*Dependency
|
||||
Checkdepends []*Dependency
|
||||
Provides []string
|
||||
Conflicts []string
|
||||
Replaces []string
|
||||
Backup []string
|
||||
Options []string
|
||||
Install string
|
||||
Changelog string
|
||||
Source []string
|
||||
Noextract []string
|
||||
Md5sums []string
|
||||
Sha1sums []string
|
||||
Sha224sums []string
|
||||
Sha256sums []string
|
||||
Sha384sums []string
|
||||
Sha512sums []string
|
||||
Validpgpkeys []string
|
||||
}
|
||||
|
||||
// Newer is true if p has a higher version number than p2
|
||||
func (p *PKGBUILD) Newer(p2 *PKGBUILD) bool {
|
||||
if p.Epoch < p2.Epoch {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Pkgver.bigger(p2.Pkgver) {
|
||||
return true
|
||||
}
|
||||
|
||||
if p2.Pkgver.bigger(p.Pkgver) {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.Pkgrel > p2.Pkgrel
|
||||
}
|
||||
|
||||
// Older is true if p has a smaller version number than p2
|
||||
func (p *PKGBUILD) Older(p2 *PKGBUILD) bool {
|
||||
if p.Epoch < p2.Epoch {
|
||||
return true
|
||||
}
|
||||
|
||||
if p2.Pkgver.bigger(p.Pkgver) {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.Pkgver.bigger(p2.Pkgver) {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.Pkgrel < p2.Pkgrel
|
||||
}
|
||||
|
||||
// Version returns the full version of the PKGBUILD (including epoch and rel)
|
||||
func (p *PKGBUILD) Version() string {
|
||||
if p.Epoch > 0 {
|
||||
return fmt.Sprintf("%d:%s-%s", p.Epoch, p.Pkgver, p.Pkgrel)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%s", p.Pkgver, p.Pkgrel)
|
||||
}
|
||||
|
||||
// CompleteVersion returns a Complete version struct including version, rel and
|
||||
// epoch.
|
||||
func (p *PKGBUILD) CompleteVersion() CompleteVersion {
|
||||
return CompleteVersion{
|
||||
Version: p.Pkgver,
|
||||
Epoch: uint8(p.Epoch),
|
||||
Pkgrel: p.Pkgrel,
|
||||
}
|
||||
}
|
||||
|
||||
// BuildDepends is Depends, MakeDepends and CheckDepends combined.
|
||||
func (p *PKGBUILD) BuildDepends() []*Dependency {
|
||||
// TODO real merge
|
||||
deps := make([]*Dependency, len(p.Depends)+len(p.Makedepends)+len(p.Checkdepends))
|
||||
|
||||
deps = append(p.Depends, p.Makedepends...)
|
||||
deps = append(deps, p.Checkdepends...)
|
||||
|
||||
return deps
|
||||
}
|
||||
|
||||
// IsDevel returns true if package contains devel packages (-{bzr,git,svn,hg})
|
||||
// TODO: more robust check.
|
||||
func (p *PKGBUILD) IsDevel() bool {
|
||||
for _, name := range p.Pkgnames {
|
||||
if strings.HasSuffix(name, "-git") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.HasSuffix(name, "-svn") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.HasSuffix(name, "-hg") {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.HasSuffix(name, "-bzr") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MustParseSRCINFO must parse the .SRCINFO given by path or it will panic
|
||||
func MustParseSRCINFO(path string) *PKGBUILD {
|
||||
pkgbuild, err := ParseSRCINFO(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pkgbuild
|
||||
}
|
||||
|
||||
// ParseSRCINFO parses .SRCINFO file given by path.
|
||||
// This is a safe alternative to ParsePKGBUILD given that a .SRCINFO file is
|
||||
// available
|
||||
func ParseSRCINFO(path string) (*PKGBUILD, error) {
|
||||
f, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read file: %s, %s", path, err.Error())
|
||||
}
|
||||
|
||||
return parsePKGBUILD(string(f))
|
||||
}
|
||||
|
||||
// ParseSRCINFOContent parses a .SRCINFO formatted byte slice.
|
||||
// This is a safe alternative to ParsePKGBUILD given that the .SRCINFO content
|
||||
// is available
|
||||
func ParseSRCINFOContent(content []byte) (*PKGBUILD, error) {
|
||||
return parsePKGBUILD(string(content))
|
||||
}
|
||||
|
||||
// parse a PKGBUILD and check that the required fields has a non-empty value
|
||||
func parsePKGBUILD(input string) (*PKGBUILD, error) {
|
||||
pkgb, err := parse(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !validPkgver(string(pkgb.Pkgver)) {
|
||||
return nil, fmt.Errorf("invalid pkgver: %s", pkgb.Pkgver)
|
||||
}
|
||||
|
||||
if len(pkgb.Arch) == 0 {
|
||||
return nil, fmt.Errorf("Arch missing")
|
||||
}
|
||||
|
||||
if len(pkgb.Pkgnames) == 0 {
|
||||
return nil, fmt.Errorf("missing pkgname")
|
||||
}
|
||||
|
||||
for _, name := range pkgb.Pkgnames {
|
||||
if !validPkgname(name) {
|
||||
return nil, fmt.Errorf("invalid pkgname: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgb, nil
|
||||
}
|
||||
|
||||
// parses a SRCINFO formatted PKGBUILD
|
||||
func parse(input string) (*PKGBUILD, error) {
|
||||
var pkgbuild *PKGBUILD
|
||||
var next item
|
||||
|
||||
lexer := lex(input)
|
||||
Loop:
|
||||
for {
|
||||
token := lexer.nextItem()
|
||||
|
||||
// strip arch from source_arch like constructs
|
||||
witharch := strings.SplitN(token.val, "_", 2)
|
||||
if len(witharch) == 2 {
|
||||
found := false
|
||||
for _, arch := range pkgbuild.Arch {
|
||||
if arch == witharch[1] {
|
||||
token.val = witharch[0]
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unsupported arch for variable: %s", token.val)
|
||||
}
|
||||
}
|
||||
|
||||
switch token.typ {
|
||||
case itemPkgbase:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild = &PKGBUILD{Epoch: 0, Pkgbase: next.val}
|
||||
case itemPkgname:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Pkgnames = append(pkgbuild.Pkgnames, next.val)
|
||||
case itemPkgver:
|
||||
next = lexer.nextItem()
|
||||
version, err := parseVersion(next.val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgbuild.Pkgver = version
|
||||
case itemPkgrel:
|
||||
next = lexer.nextItem()
|
||||
rel, err := parseVersion(next.val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgbuild.Pkgrel = rel
|
||||
case itemPkgdir:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Pkgdir = next.val
|
||||
case itemEpoch:
|
||||
next = lexer.nextItem()
|
||||
epoch, err := strconv.ParseInt(next.val, 10, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if epoch < 0 {
|
||||
return nil, fmt.Errorf("invalid epoch: %d", epoch)
|
||||
}
|
||||
pkgbuild.Epoch = int(epoch)
|
||||
case itemPkgdesc:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Pkgdesc = next.val
|
||||
case itemArch:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Arch = append(pkgbuild.Arch, next.val)
|
||||
case itemURL:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.URL = next.val
|
||||
case itemLicense:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.License = append(pkgbuild.License, next.val)
|
||||
case itemGroups:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Groups = append(pkgbuild.Groups, next.val)
|
||||
case itemDepends:
|
||||
next = lexer.nextItem()
|
||||
deps, err := parseDependency(next.val, pkgbuild.Depends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgbuild.Depends = deps
|
||||
case itemOptdepends:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Optdepends = append(pkgbuild.Optdepends, next.val)
|
||||
case itemMakedepends:
|
||||
next = lexer.nextItem()
|
||||
deps, err := parseDependency(next.val, pkgbuild.Makedepends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgbuild.Makedepends = deps
|
||||
case itemCheckdepends:
|
||||
next = lexer.nextItem()
|
||||
deps, err := parseDependency(next.val, pkgbuild.Checkdepends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgbuild.Checkdepends = deps
|
||||
case itemProvides:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Provides = append(pkgbuild.Provides, next.val)
|
||||
case itemConflicts:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Conflicts = append(pkgbuild.Conflicts, next.val)
|
||||
case itemReplaces:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Replaces = append(pkgbuild.Replaces, next.val)
|
||||
case itemBackup:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Backup = append(pkgbuild.Backup, next.val)
|
||||
case itemOptions:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Options = append(pkgbuild.Options, next.val)
|
||||
case itemInstall:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Install = next.val
|
||||
case itemChangelog:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Changelog = next.val
|
||||
case itemSource:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Source = append(pkgbuild.Source, next.val)
|
||||
case itemNoextract:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Noextract = append(pkgbuild.Noextract, next.val)
|
||||
case itemMd5sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Md5sums = append(pkgbuild.Md5sums, next.val)
|
||||
case itemSha1sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Sha1sums = append(pkgbuild.Sha1sums, next.val)
|
||||
case itemSha224sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Sha224sums = append(pkgbuild.Sha224sums, next.val)
|
||||
case itemSha256sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Sha256sums = append(pkgbuild.Sha256sums, next.val)
|
||||
case itemSha384sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Sha384sums = append(pkgbuild.Sha384sums, next.val)
|
||||
case itemSha512sums:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Sha512sums = append(pkgbuild.Sha512sums, next.val)
|
||||
case itemValidpgpkeys:
|
||||
next = lexer.nextItem()
|
||||
pkgbuild.Validpgpkeys = append(pkgbuild.Validpgpkeys, next.val)
|
||||
case itemEndSplit:
|
||||
case itemError:
|
||||
return nil, fmt.Errorf(token.val)
|
||||
case itemEOF:
|
||||
break Loop
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid variable: %s", token.val)
|
||||
}
|
||||
}
|
||||
return pkgbuild, nil
|
||||
}
|
||||
|
||||
// parse and validate a version string
|
||||
func parseVersion(s string) (Version, error) {
|
||||
if validPkgver(s) {
|
||||
return Version(s), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("invalid version string: %s", s)
|
||||
}
|
||||
|
||||
// check if name is a valid pkgname format
|
||||
func validPkgname(name string) bool {
|
||||
if len(name) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if name[0] == '-' {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, r := range name {
|
||||
if !isValidPkgnameChar(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// check if version is a valid pkgver format
|
||||
func validPkgver(version string) bool {
|
||||
if len(version) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if !isAlphaNumeric(rune(version[0])) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, r := range version[1:] {
|
||||
if !isValidPkgverChar(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseDeps parses a string slice of dependencies into a slice of Dependency
|
||||
// objects.
|
||||
func ParseDeps(deps []string) ([]*Dependency, error) {
|
||||
var err error
|
||||
dependencies := make([]*Dependency, 0)
|
||||
|
||||
for _, dep := range deps {
|
||||
dependencies, err = parseDependency(dep, dependencies)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies, nil
|
||||
}
|
||||
|
||||
// parse dependency with possible version restriction
|
||||
func parseDependency(dep string, deps []*Dependency) ([]*Dependency, error) {
|
||||
var name string
|
||||
var dependency *Dependency
|
||||
index := -1
|
||||
|
||||
if dep == "" {
|
||||
return deps, nil
|
||||
}
|
||||
|
||||
if dep[0] == '-' {
|
||||
return nil, fmt.Errorf("invalid dependency name")
|
||||
}
|
||||
|
||||
i := 0
|
||||
for _, c := range dep {
|
||||
if !isValidPkgnameChar(c) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// check if the dependency has been set before
|
||||
name = dep[0:i]
|
||||
for n, d := range deps {
|
||||
if d.Name == name {
|
||||
index = n
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
dependency = &Dependency{
|
||||
Name: name,
|
||||
sgt: false,
|
||||
slt: false,
|
||||
}
|
||||
|
||||
if len(dep) != len(name) {
|
||||
var eq bytes.Buffer
|
||||
for _, c := range dep[i:] {
|
||||
if c == '<' || c == '>' || c == '=' {
|
||||
i++
|
||||
eq.WriteRune(c)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
version, err := NewCompleteVersion(dep[i:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch eq.String() {
|
||||
case "=":
|
||||
dependency.MinVer = version
|
||||
dependency.MaxVer = version
|
||||
case "<=":
|
||||
dependency.MaxVer = version
|
||||
case ">=":
|
||||
dependency.MinVer = version
|
||||
case "<":
|
||||
dependency.MaxVer = version
|
||||
dependency.slt = true
|
||||
case ">":
|
||||
dependency.MinVer = version
|
||||
dependency.sgt = true
|
||||
}
|
||||
}
|
||||
|
||||
if index == -1 {
|
||||
deps = append(deps, dependency)
|
||||
} else {
|
||||
deps[index] = deps[index].Restrict(dependency)
|
||||
}
|
||||
|
||||
return deps, nil
|
||||
}
|
||||
|
||||
// isLowerAlpha reports whether c is a lowercase alpha character
|
||||
func isLowerAlpha(c rune) bool {
|
||||
return 'a' <= c && c <= 'z'
|
||||
}
|
||||
|
||||
// check if c is a valid pkgname char
|
||||
func isValidPkgnameChar(c rune) bool {
|
||||
return isAlphaNumeric(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
|
||||
}
|
||||
|
||||
// check if c is a valid pkgver char
|
||||
func isValidPkgverChar(c rune) bool {
|
||||
return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.' || c == '~'
|
||||
}
|
324
vendor/github.com/mikkeloscar/gopkgbuild/version.go
generated
vendored
324
vendor/github.com/mikkeloscar/gopkgbuild/version.go
generated
vendored
|
@ -1,324 +0,0 @@
|
|||
package pkgbuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Version string
|
||||
type Version string
|
||||
|
||||
type CompleteVersion struct {
|
||||
Version Version
|
||||
Epoch uint8
|
||||
Pkgrel Version
|
||||
}
|
||||
|
||||
func (c *CompleteVersion) String() string {
|
||||
str := ""
|
||||
|
||||
if c.Epoch > 0 {
|
||||
str = fmt.Sprintf("%d:", c.Epoch)
|
||||
}
|
||||
|
||||
str = fmt.Sprintf("%s%s", str, c.Version)
|
||||
|
||||
if c.Pkgrel != "" {
|
||||
str = fmt.Sprintf("%s-%s", str, c.Pkgrel)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// NewCompleteVersion creates a CompleteVersion including basic version, epoch
|
||||
// and rel from string
|
||||
func NewCompleteVersion(s string) (*CompleteVersion, error) {
|
||||
var err error
|
||||
epoch := 0
|
||||
rel := Version("")
|
||||
|
||||
// handle possible epoch
|
||||
versions := strings.Split(s, ":")
|
||||
if len(versions) > 2 {
|
||||
return nil, fmt.Errorf("invalid version format: %s", s)
|
||||
}
|
||||
|
||||
if len(versions) > 1 {
|
||||
epoch, err = strconv.Atoi(versions[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// handle possible rel
|
||||
versions = strings.Split(versions[len(versions)-1], "-")
|
||||
if len(versions) > 2 {
|
||||
return nil, fmt.Errorf("invalid version format: %s", s)
|
||||
}
|
||||
|
||||
if len(versions) > 1 {
|
||||
rel = Version(versions[1])
|
||||
}
|
||||
|
||||
// finally check that the actual version is valid
|
||||
if validPkgver(versions[0]) {
|
||||
return &CompleteVersion{
|
||||
Version: Version(versions[0]),
|
||||
Epoch: uint8(epoch),
|
||||
Pkgrel: rel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid version format: %s", s)
|
||||
}
|
||||
|
||||
// Older returns true if a is older than the argument version
|
||||
func (a *CompleteVersion) Older(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == -1
|
||||
}
|
||||
|
||||
// Newer returns true if a is newer than the argument version
|
||||
func (a *CompleteVersion) Newer(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == 1
|
||||
}
|
||||
|
||||
// Equal returns true if a is equal to the argument version
|
||||
func (a *CompleteVersion) Equal(b *CompleteVersion) bool {
|
||||
return a.cmp(b) == 0
|
||||
}
|
||||
|
||||
// Satisfies tests whether or not version fits inside the bounds specified by
|
||||
// dep
|
||||
func (version *CompleteVersion) Satisfies(dep *Dependency) bool {
|
||||
var cmpMax int8
|
||||
var cmpMin int8
|
||||
|
||||
if dep.MaxVer != nil {
|
||||
cmpMax = version.cmp(dep.MaxVer)
|
||||
if cmpMax == 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if cmpMax == 0 && dep.slt {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if dep.MinVer != nil {
|
||||
if dep.MaxVer == dep.MinVer {
|
||||
cmpMin = cmpMax
|
||||
} else {
|
||||
cmpMin = version.cmp(dep.MinVer)
|
||||
}
|
||||
if cmpMin == -1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if cmpMin == 0 && dep.sgt {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Compare a to b:
|
||||
// return 1: a is newer than b
|
||||
// 0: a and b are the same version
|
||||
// -1: b is newer than a
|
||||
func (a *CompleteVersion) cmp(b *CompleteVersion) int8 {
|
||||
if a.Epoch > b.Epoch {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Epoch < b.Epoch {
|
||||
return -1
|
||||
}
|
||||
|
||||
if a.Version.bigger(b.Version) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if b.Version.bigger(a.Version) {
|
||||
return -1
|
||||
}
|
||||
|
||||
if a.Pkgrel == "" || b.Pkgrel == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
if a.Pkgrel.bigger(b.Pkgrel) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if b.Pkgrel.bigger(a.Pkgrel) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Compare alpha and numeric segments of two versions.
|
||||
// return 1: a is newer than b
|
||||
// 0: a and b are the same version
|
||||
// -1: b is newer than a
|
||||
//
|
||||
// This is based on the rpmvercmp function used in libalpm
|
||||
// https://projects.archlinux.org/pacman.git/tree/lib/libalpm/version.c
|
||||
func rpmvercmp(av, bv Version) int {
|
||||
if av == bv {
|
||||
return 0
|
||||
}
|
||||
a, b := []rune(string(av)), []rune(string(bv))
|
||||
|
||||
var one, two, ptr1, ptr2 int
|
||||
var isNum bool
|
||||
one, two, ptr1, ptr2 = 0, 0, 0, 0
|
||||
|
||||
// loop through each version segment of a and b and compare them
|
||||
for len(a) > one && len(b) > two {
|
||||
for len(a) > one && !isAlphaNumeric(a[one]) {
|
||||
one++
|
||||
}
|
||||
for len(b) > two && !isAlphaNumeric(b[two]) {
|
||||
two++
|
||||
}
|
||||
|
||||
// if we ran to the end of either, we are finished with the loop
|
||||
if !(len(a) > one && len(b) > two) {
|
||||
break
|
||||
}
|
||||
|
||||
// if the seperator lengths were different, we are also finished
|
||||
if one-ptr1 != two-ptr2 {
|
||||
if one-ptr1 < two-ptr2 {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
ptr1 = one
|
||||
ptr2 = two
|
||||
|
||||
// grab first completely alpha or completely numeric segment
|
||||
// leave one and two pointing to the start of the alpha or numeric
|
||||
// segment and walk ptr1 and ptr2 to end of segment
|
||||
if isDigit(a[ptr1]) {
|
||||
for len(a) > ptr1 && isDigit(a[ptr1]) {
|
||||
ptr1++
|
||||
}
|
||||
for len(b) > ptr2 && isDigit(b[ptr2]) {
|
||||
ptr2++
|
||||
}
|
||||
isNum = true
|
||||
} else {
|
||||
for len(a) > ptr1 && isAlpha(a[ptr1]) {
|
||||
ptr1++
|
||||
}
|
||||
for len(b) > ptr2 && isAlpha(b[ptr2]) {
|
||||
ptr2++
|
||||
}
|
||||
isNum = false
|
||||
}
|
||||
|
||||
// take care of the case where the two version segments are
|
||||
// different types: one numeric, the other alpha (i.e. empty)
|
||||
// numeric segments are always newer than alpha segments
|
||||
if two == ptr2 {
|
||||
if isNum {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
if isNum {
|
||||
// we know this part of the strings only contains digits
|
||||
// so we can ignore the error value since it should
|
||||
// always be nil
|
||||
as, _ := strconv.ParseInt(string(a[one:ptr1]), 10, 0)
|
||||
bs, _ := strconv.ParseInt(string(b[two:ptr2]), 10, 0)
|
||||
|
||||
// whichever number has more digits wins
|
||||
if as > bs {
|
||||
return 1
|
||||
}
|
||||
if as < bs {
|
||||
return -1
|
||||
}
|
||||
} else {
|
||||
cmp := alphaCompare(a[one:ptr1], b[two:ptr2])
|
||||
if cmp < 0 {
|
||||
return -1
|
||||
}
|
||||
if cmp > 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// advance one and two to next segment
|
||||
one = ptr1
|
||||
two = ptr2
|
||||
}
|
||||
|
||||
// this catches the case where all numeric and alpha segments have
|
||||
// compared identically but the segment separating characters were
|
||||
// different
|
||||
if len(a) <= one && len(b) <= two {
|
||||
return 0
|
||||
}
|
||||
|
||||
// the final showdown. we never want a remaining alpha string to
|
||||
// beat an empty string. the logic is a bit weird, but:
|
||||
// - if one is empty and two is not an alpha, two is newer.
|
||||
// - if one is an alpha, two is newer.
|
||||
// - otherwise one is newer.
|
||||
if (len(a) <= one && !isAlpha(b[two])) || len(a) > one && isAlpha(a[one]) {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// alphaCompare compares two alpha version segments and will return a positive
|
||||
// value if a is bigger than b and a negative if b is bigger than a else 0
|
||||
func alphaCompare(a, b []rune) int8 {
|
||||
if string(a) == string(b) {
|
||||
return 0
|
||||
}
|
||||
|
||||
i := 0
|
||||
for len(a) > i && len(b) > i && a[i] == b[i] {
|
||||
i++
|
||||
}
|
||||
|
||||
if len(a) == i && len(b) > i {
|
||||
return -1
|
||||
}
|
||||
|
||||
if len(b) == i {
|
||||
return 1
|
||||
}
|
||||
|
||||
return int8(a[i]) - int8(b[i])
|
||||
}
|
||||
|
||||
// check if version number v is bigger than v2
|
||||
func (v Version) bigger(v2 Version) bool {
|
||||
return rpmvercmp(v, v2) == 1
|
||||
}
|
||||
|
||||
// isAlphaNumeric reports whether c is an alpha character or digit
|
||||
func isAlphaNumeric(c rune) bool {
|
||||
return isDigit(c) || isAlpha(c)
|
||||
}
|
||||
|
||||
// isAlpha reports whether c is an alpha character
|
||||
func isAlpha(c rune) bool {
|
||||
return unicode.IsLetter(c)
|
||||
}
|
||||
|
||||
// isDigit reports whether d is an ASCII digit
|
||||
func isDigit(d rune) bool {
|
||||
return unicode.IsDigit(d)
|
||||
}
|
Loading…
Reference in a new issue