Arch Linux helpers and parsers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

191 lines
4.2 KiB

package archlinux
import (
"bufio"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"strings"
)
const skip = "SKIP"
// PackageBuild describes a PKGBUILD file
type PackageBuild struct {
// Package is the base package
Package
// Packages are the packages contained in this build
Packages map[string]*Package
// Source files
Source []string
// SourceArch are arch specific sources
SourceArch map[string][]string
// MD5Sums are the checksums of the sources
MD5Sums [][]byte `srcinfo:"md5sums,hex,skip"`
SHA1Sums [][]byte `srcinfo:"sha1sums,hex,skip"`
SHA256Sums [][]byte `srcinfo:"sha256sums,hex,skip"`
SHA384Sums [][]byte `srcinfo:"sha384sums,hex,skip"`
SHA512Sums [][]byte `srcinfo:"sha512sums,hex,skip"`
}
// VerifySource verifies the checksums of source with index n
func (build *PackageBuild) VerifySource(dir string, n int) error {
if n < 0 || n >= len(build.Source) {
return errors.New("archlinux: index out of range")
}
mh := newMultiHash()
if n < len(build.MD5Sums) {
mh.Add("MD5", md5.New, build.MD5Sums[n])
}
if n < len(build.SHA1Sums) {
mh.Add("SHA-1", sha1.New, build.SHA1Sums[n])
}
if n < len(build.SHA256Sums) {
mh.Add("SHA-256", sha256.New, build.SHA256Sums[n])
}
if n < len(build.SHA384Sums) {
mh.Add("SHA-384", sha512.New384, build.SHA384Sums[n])
}
if n < len(build.SHA512Sums) {
mh.Add("SHA-512", sha512.New, build.SHA512Sums[n])
}
if len(mh) == 0 {
// Nothing to do...
return nil
}
source := build.Source[n]
if i := strings.Index(source, "::"); i != -1 {
source = source[:i]
}
f, err := os.Open(filepath.Join(dir, source))
if err != nil {
return err
}
defer f.Close()
var b [8192]byte
for {
n, err := f.Read(b[:])
if err != nil {
if err == io.EOF {
break
}
return err
}
if _, err = mh.Write(b[:n]); err != nil {
return err
}
}
return mh.Check()
}
// VerifySources verifies all package source files stored at the given dir
func (build *PackageBuild) VerifySources(dir string) error {
for n := range build.Source {
if err := build.VerifySource(dir, n); err != nil {
return err
}
}
return nil
}
// ReadPackageBuild reads a PKGBUILD file
func ReadPackageBuild(r io.Reader) (*PackageBuild, error) {
return nil, nil
}
func parseFieldSrcInfo(field reflect.StructField) (name, encoding string) {
tag := field.Tag.Get("srcinfo")
switch tag {
case "-":
// Ignored tag
case "":
// No desc tag, default to upper case field name
name = strings.ToLower(field.Name)
default:
if i := strings.IndexByte(tag, ','); i != -1 {
name, encoding = tag[:i], tag[i+1:]
} else {
name = tag
}
}
return
}
// ReadSrcInfo reads a .SRCINFO file
func ReadSrcInfo(r io.Reader) (*PackageBuild, error) {
var (
build = &PackageBuild{
Packages: make(map[string]*Package),
}
pkg = &build.Package
s = bufio.NewScanner(r)
)
values, encodings := parsePackageFields(parseFieldSrcInfo, build, &build.Package)
for s.Scan() {
if err := s.Err(); err != nil {
if err == io.EOF {
break
}
return nil, err
}
line := s.Text()
if line == "" {
continue
}
if line[0] == '#' {
continue
}
if line[0] == '\t' || line[0] == ' ' {
fields := strings.SplitN(strings.TrimSpace(line), " = ", 2)
if len(fields) != 2 {
continue
}
v, ok := values[fields[0]]
if !ok {
return nil, fmt.Errorf("archlinux: unknown .SRCINFO field %q", fields[0])
}
if err := setPackageValue(pkg, v, fields[1], encodings[fields[0]]); err != nil {
return nil, err
}
} else if strings.HasPrefix(line, "pkgbase = ") {
build.Base = line[len("pkgbase = "):]
build.Name = build.Base
pkg = &build.Package
} else if strings.HasPrefix(line, "pkgname = ") {
var (
ok bool
name = line[len("pkgname = "):]
)
if pkg, ok = build.Packages[name]; !ok {
pkg = &Package{
Name: name,
Base: build.Base,
Version: build.Version,
Release: build.Release,
Epoch: build.Epoch,
Arch: make([]string, len(build.Arch)),
License: make([]string, len(build.License)),
}
copy(pkg.Arch, build.Arch)
copy(pkg.License, build.License)
build.Packages[name] = pkg
}
values, encodings = parsePackageFields(parseFieldSrcInfo, pkg)
}
}
return build, nil
}