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.

package_info.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package archlinux
  2. import (
  3. "bufio"
  4. "encoding/base64"
  5. "encoding/hex"
  6. "fmt"
  7. "io"
  8. "net/url"
  9. "reflect"
  10. "strings"
  11. "time"
  12. )
  13. // ReadPackageInfo reads a package description from a .PKGINFO file
  14. func ReadPackageInfo(r io.Reader) (*Package, error) {
  15. pkg := new(Package)
  16. if n, ok := r.(namer); ok {
  17. pkg.Filename = n.Name()
  18. }
  19. if err := pkg.readPackageInfo(r); err != nil {
  20. return nil, err
  21. }
  22. if pkg.Name == "" {
  23. return nil, ErrNoPackageName
  24. }
  25. if pkg.Version == "" {
  26. return nil, ErrNoPackageVersion
  27. }
  28. if pkg.Release == "" {
  29. return nil, ErrNoPackageRelease
  30. }
  31. return pkg, nil
  32. }
  33. func (pkg *Package) readBuildInfo(r io.Reader) (err error) {
  34. s := bufio.NewScanner(r)
  35. for s.Scan() {
  36. if err = s.Err(); err != nil {
  37. if err == io.EOF {
  38. err = nil
  39. }
  40. break
  41. }
  42. fields := strings.SplitN(s.Text(), " = ", 2)
  43. if len(fields) != 2 {
  44. continue
  45. }
  46. switch fields[0] {
  47. case "buildenv":
  48. pkg.BuildEnv = append(pkg.BuildEnv, fields[1])
  49. case "options":
  50. pkg.Options = append(pkg.Options, fields[1])
  51. }
  52. }
  53. return
  54. }
  55. func (pkg *Package) readPackageInfo(r io.Reader) (err error) {
  56. values, encodings := parsePackageFields(parseFieldInfo, pkg)
  57. s := bufio.NewScanner(r)
  58. for s.Scan() {
  59. if err = s.Err(); err != nil {
  60. if err == io.EOF {
  61. err = nil
  62. }
  63. break
  64. }
  65. fields := strings.SplitN(s.Text(), " = ", 2)
  66. if len(fields) != 2 {
  67. continue
  68. }
  69. v, ok := values[fields[0]]
  70. if !ok {
  71. return fmt.Errorf("archlinux: unknown PKGINFO field %q", fields[0])
  72. }
  73. if err = setPackageValue(pkg, v, fields[1], encodings[fields[0]]); err != nil {
  74. return
  75. }
  76. }
  77. return
  78. }
  79. func parseFieldInfo(field reflect.StructField) (name, encoding string) {
  80. tag := field.Tag.Get("pkginfo")
  81. switch tag {
  82. case "-":
  83. // Ignored tag
  84. case "":
  85. // No desc tag, default to upper case field name
  86. name = strings.ToLower(field.Name)
  87. default:
  88. if i := strings.IndexByte(tag, ','); i != -1 {
  89. name, encoding = tag[:i], tag[i+1:]
  90. } else {
  91. name = tag
  92. }
  93. }
  94. return
  95. }
  96. // WritePackageInfo writes a PKGINFO to the supplied Writer
  97. func (pkg *Package) WritePackageInfo(w io.Writer) (int, error) {
  98. var (
  99. value = reflect.Indirect(reflect.ValueOf(pkg))
  100. typ = value.Type()
  101. total, n int
  102. err error
  103. )
  104. for i := 0; i < value.NumField(); i++ {
  105. fieldValue := value.Field(i)
  106. fieldType := typ.Field(i)
  107. name, encoding := parseFieldInfo(fieldType)
  108. if name == "" {
  109. // No name means ignored field
  110. continue
  111. }
  112. switch v := fieldValue.Interface().(type) {
  113. case string:
  114. if v == "" {
  115. continue
  116. }
  117. switch encoding {
  118. case "":
  119. // No additional encoding
  120. case evrEncoding:
  121. // Epoch:Version-Release
  122. if pkg.Epoch > 0 {
  123. v = fmt.Sprintf("%d:%s-%s", pkg.Epoch, pkg.Version, pkg.Release)
  124. } else {
  125. v = fmt.Sprintf("%s-%s", pkg.Version, pkg.Release)
  126. }
  127. }
  128. if n, err = fmt.Fprintf(w, "%s = %s\n", name, v); err != nil {
  129. return total + n, err
  130. }
  131. total += n
  132. case []string:
  133. if len(v) == 0 {
  134. continue
  135. }
  136. for _, s := range v {
  137. if n, err = fmt.Fprintf(w, "%s = %s\n", name, s); err != nil {
  138. return total + n, err
  139. }
  140. }
  141. total += n
  142. case []byte:
  143. if len(v) == 0 {
  144. continue
  145. }
  146. var o []byte
  147. switch encoding {
  148. case "":
  149. o = v
  150. case base64Encoding:
  151. o = make([]byte, base64.StdEncoding.EncodedLen(len(v)))
  152. base64.StdEncoding.Encode(o, v)
  153. case hexEncoding:
  154. o = make([]byte, hex.EncodedLen(len(v)))
  155. hex.Encode(o, v)
  156. }
  157. if n, err = fmt.Fprintf(w, "%s = %s\n", name, o); err != nil {
  158. return total + n, err
  159. }
  160. total += n
  161. case int64:
  162. if v == 0 {
  163. continue
  164. }
  165. if n, err = fmt.Fprintf(w, "%s = %d\n", name, v); err != nil {
  166. return total + n, err
  167. }
  168. total += n
  169. case time.Time:
  170. if v.Equal(timeZero) {
  171. continue
  172. }
  173. if n, err = fmt.Fprintf(w, "%s = %d\n", name, v.Unix()); err != nil {
  174. return total + n, err
  175. }
  176. total += n
  177. case *url.URL:
  178. if v == nil {
  179. continue
  180. }
  181. if n, err = fmt.Fprintf(w, "%s = %s\n", name, v); err != nil {
  182. return total + n, err
  183. }
  184. total += n
  185. default:
  186. return total, fmt.Errorf("archlinux: can't write %T to info", v)
  187. }
  188. }
  189. return total, nil
  190. /*
  191. var (
  192. fields = []struct {
  193. Key string
  194. Value interface{}
  195. }{
  196. {"pkgname", pkg.Name},
  197. {"pkgbase", pkg.Base},
  198. {"pkgver", pkg.Version + "-" + pkg.Release},
  199. {"pkgdesc", pkg.Description},
  200. {"url", pkg.URL},
  201. {"builddate", pkg.BuildDate},
  202. {"packager", pkg.Packager},
  203. {"size", pkg.Size},
  204. {"arch", pkg.Arch},
  205. {"license", pkg.License},
  206. {"provides", pkg.Provides},
  207. {"conflicts", pkg.Conflicts},
  208. {"replaces", pkg.Replaces},
  209. {"backup", pkg.Backup},
  210. {"depend", pkg.Depends},
  211. {"optdepend", pkg.OptionalDepends},
  212. {"makedepend", pkg.MakeDepends},
  213. {"checkdepend", pkg.CheckDepends},
  214. }
  215. err error
  216. )
  217. if _, err = fmt.Fprintln(w, "# Generated by maze.io/archlinux.v0\n#", time.Now().UTC().Format(time.UnixDate)); err != nil {
  218. return err
  219. }
  220. for _, f := range fields {
  221. switch value := f.Value.(type) {
  222. case string:
  223. if value == "" {
  224. continue
  225. }
  226. if _, err = fmt.Fprintln(w, f.Key, "=", value); err != nil {
  227. return err
  228. }
  229. case []string:
  230. if len(value) > 0 {
  231. for _, v := range value {
  232. if v == "" {
  233. continue
  234. }
  235. if _, err = fmt.Fprintln(w, f.Key, "=", v); err != nil {
  236. return err
  237. }
  238. }
  239. }
  240. case int64:
  241. if value > 0 {
  242. if _, err = fmt.Fprintln(w, f.Key, "=", value); err != nil {
  243. return err
  244. }
  245. }
  246. case *url.URL:
  247. if value == nil {
  248. continue
  249. }
  250. if _, err = fmt.Fprintln(w, f.Key, "=", value.String()); err != nil {
  251. return err
  252. }
  253. }
  254. }
  255. return nil
  256. */
  257. }