|
- package archlinux
-
- import (
- "bufio"
- "encoding/base64"
- "encoding/hex"
- "fmt"
- "io"
- "net/url"
- "reflect"
- "strings"
- "time"
- )
-
- // ReadPackageDesc reads a package description from a desc file
- func ReadPackageDesc(r io.Reader) (*Package, error) {
- pkg := new(Package)
- if n, ok := r.(namer); ok {
- pkg.Filename = n.Name()
- }
- if err := pkg.readPackageDesc(r); err != nil {
- return nil, err
- }
- if pkg.Name == "" {
- return nil, ErrNoPackageName
- }
- if pkg.Version == "" {
- return nil, ErrNoPackageVersion
- }
- if pkg.Release == "" {
- return nil, ErrNoPackageRelease
- }
- return pkg, nil
- }
-
- func (pkg *Package) readPackageDesc(r io.Reader) (err error) {
- var (
- s = bufio.NewScanner(r)
- line string
- lines []string
- section string
- )
- values, encodings := parsePackageFields(parseFieldDesc, pkg)
- for s.Scan() {
- if err = s.Err(); err != nil {
- if err == io.EOF {
- err = nil
- }
- break
- }
- line = s.Text()
-
- if len(line) == 0 {
- v, ok := values[section]
- if !ok {
- return fmt.Errorf("archlinux: unsupported section %q", section)
- }
- switch v.Interface().(type) {
- case []string:
- for _, line = range lines {
- if err = setPackageValue(pkg, v, line, encodings[section]); err != nil {
- return
- }
- }
- default:
- if err = setPackageValue(pkg, v, strings.Join(lines, "\n"), encodings[section]); err != nil {
- return
- }
- }
- /*
- switch v.Interface().(type) {
- case string:
- switch encodings[section] {
- case "":
- v.SetString(lines[0])
- case evrEncoding:
- p := version.Parse(lines[0])
- pkg.Version = p.Version
- pkg.Release = p.Release
- if p.Epoch != "" {
- if pkg.Epoch, err = strconv.Atoi(p.Epoch); err != nil {
- return fmt.Errorf("archlinux: invalid epoch %q: %v", p.Epoch, err)
- }
- }
- }
- case []string:
- c := make([]string, len(lines))
- copy(c, lines)
- v.Set(reflect.ValueOf(c))
- case []byte:
- switch encodings[section] {
- case "":
- v.SetBytes([]byte(strings.Join(lines, "\n")))
- case base64Encoding:
- var b []byte
- if b, err = base64.StdEncoding.DecodeString(lines[0]); err != nil {
- return fmt.Errorf("archlinux: error parsing section %q: %v", section, err)
- }
- v.SetBytes(b)
- case hexEncoding:
- var b []byte
- if b, err = hex.DecodeString(lines[0]); err != nil {
- return fmt.Errorf("archlinux: error parsing section %q: %v", section, err)
- }
- v.SetBytes(b)
- }
- case time.Time:
- var i int64
- if i, err = strconv.ParseInt(lines[0], 10, 64); err != nil {
- return fmt.Errorf("archlinux: error parsing section %q: %v", section, err)
- }
- v.Set(reflect.ValueOf(time.Unix(i, 0)))
- case *url.URL:
- var u *url.URL
- if u, err = url.Parse(lines[0]); err != nil {
- return fmt.Errorf("archlinux: error parsing section %q: %v", section, err)
- }
- v.Set(reflect.ValueOf(u))
- }
- */
- } else if line[0] == '%' && line[len(line)-1] == '%' {
- section = line[1 : len(line)-1]
- lines = lines[:0]
- } else {
- lines = append(lines, line)
- }
- }
- return
- }
-
- func parseFieldDesc(field reflect.StructField) (name, encoding string) {
- tag := field.Tag.Get("pkgdesc")
- switch tag {
- case "-":
- // Ignored tag
- case "":
- // No desc tag, default to upper case field name
- name = strings.ToUpper(field.Name)
- default:
- if i := strings.IndexByte(tag, ','); i != -1 {
- name, encoding = strings.ToUpper(tag[:i]), tag[i+1:]
- } else {
- name = strings.ToUpper(tag)
- }
- }
- return
- }
-
- var timeZero time.Time
-
- // WritePackageDesc writes a package desc file to the target Writer.
- func (pkg *Package) WritePackageDesc(w io.Writer) (int, error) {
- var (
- value = reflect.Indirect(reflect.ValueOf(pkg))
- typ = value.Type()
- total, n int
- err error
- )
- for i := 0; i < value.NumField(); i++ {
- fieldValue := value.Field(i)
- fieldType := typ.Field(i)
- name, encoding := parseFieldDesc(fieldType)
- if name == "" {
- // No name means ignored field
- continue
- }
- switch v := fieldValue.Interface().(type) {
- case string:
- if v == "" {
- continue
- }
- switch encoding {
- case "":
- // No additional encoding
- case evrEncoding:
- // Epoch:Version-Release
- if pkg.Epoch > 0 {
- v = fmt.Sprintf("%d:%s-%s", pkg.Epoch, pkg.Version, pkg.Release)
- } else {
- v = fmt.Sprintf("%s-%s", pkg.Version, pkg.Release)
- }
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%s\n\n", name, v); err != nil {
- return total + n, err
- }
- total += n
- case int64:
- if v == 0 {
- continue
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%d\n\n", name, v); err != nil {
- return total + n, err
- }
- total += n
- case []string:
- if len(v) == 0 {
- continue
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%s\n\n", name, strings.Join(v, "\n")); err != nil {
- return total + n, err
- }
- total += n
- case []byte:
- if len(v) == 0 {
- continue
- }
- var o []byte
- switch encoding {
- case "":
- o = v
- case base64Encoding:
- o = make([]byte, base64.StdEncoding.EncodedLen(len(v)))
- base64.StdEncoding.Encode(o, v)
- case hexEncoding:
- o = make([]byte, hex.EncodedLen(len(v)))
- hex.Encode(o, v)
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%s\n\n", name, o); err != nil {
- return total + n, err
- }
- total += n
- case time.Time:
- if v.Equal(timeZero) {
- continue
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%d\n\n", name, v.Unix()); err != nil {
- return total + n, err
- }
- total += n
- case *url.URL:
- if v == nil {
- continue
- }
- if n, err = fmt.Fprintf(w, "%%%s%%\n%s\n\n", name, v); err != nil {
- return total + n, err
- }
- total += n
- default:
- return total, fmt.Errorf("archlinux: can't write %T to desc", v)
- }
- }
- return total, nil
- }
|