pkgbuild.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. package pkgbuild
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "strconv"
  7. "strings"
  8. )
  9. // Arch is a system architecture
  10. type Arch uint8
  11. const (
  12. // Any architecture
  13. Any Arch = iota
  14. // I686 architecture
  15. I686
  16. // X8664 x86_64 (64bit) architecture
  17. X8664
  18. // ARMv5 architecture (archlinux-arm)
  19. ARMv5
  20. // ARMv6h architecture (archlinux-arm)
  21. ARMv6h
  22. // ARMv7h architecture (archlinux-arm)
  23. ARMv7h
  24. // ARMv8 architecture (64bit) (archlinux-arm)
  25. ARMv8
  26. // MIPS64 architecture
  27. MIPS64
  28. )
  29. var archs = map[string]Arch{
  30. "any": Any,
  31. "i686": I686,
  32. "x86": I686,
  33. "x86_64": X8664,
  34. "aarch64": ARMv8,
  35. "arm": ARMv5,
  36. "armv5": ARMv5,
  37. "armv6h": ARMv6h,
  38. "armv7h": ARMv7h,
  39. "mips64el": MIPS64,
  40. }
  41. // Dependency describes a dependency with min and max version, if any.
  42. type Dependency struct {
  43. Name string // dependency name
  44. MinVer *CompleteVersion // min version
  45. sgt bool // defines if min version is strictly greater than
  46. MaxVer *CompleteVersion // max version
  47. slt bool // defines if max version is strictly less than
  48. }
  49. // PKGBUILD is a struct describing a parsed PKGBUILD file.
  50. // Required fields are:
  51. // pkgname
  52. // pkgver
  53. // pkgrel
  54. // arch
  55. // (license) - not required but recommended
  56. //
  57. // parsing a PKGBUILD file without these fields will fail
  58. type PKGBUILD struct {
  59. Pkgnames []string
  60. Pkgver Version // required
  61. Pkgrel int // required
  62. Pkgdir string
  63. Epoch int
  64. Pkgbase string
  65. Pkgdesc string
  66. Arch []Arch // required
  67. URL string
  68. License []string // recommended
  69. Groups []string
  70. Depends []*Dependency
  71. Optdepends []string
  72. Makedepends []*Dependency
  73. Checkdepends []*Dependency
  74. Provides []string
  75. Conflicts []string
  76. Replaces []string
  77. Backup []string
  78. Options []string
  79. Install string
  80. Changelog string
  81. Source []string
  82. Noextract []string
  83. Md5sums []string
  84. Sha1sums []string
  85. Sha224sums []string
  86. Sha256sums []string
  87. Sha384sums []string
  88. Sha512sums []string
  89. Validpgpkeys []string
  90. }
  91. // Newer is true if p has a higher version number than p2
  92. func (p *PKGBUILD) Newer(p2 *PKGBUILD) bool {
  93. if p.Epoch < p2.Epoch {
  94. return false
  95. }
  96. if p.Pkgver.bigger(p2.Pkgver) {
  97. return true
  98. }
  99. if p2.Pkgver.bigger(p.Pkgver) {
  100. return false
  101. }
  102. return p.Pkgrel > p2.Pkgrel
  103. }
  104. // Older is true if p has a smaller version number than p2
  105. func (p *PKGBUILD) Older(p2 *PKGBUILD) bool {
  106. if p.Epoch < p2.Epoch {
  107. return true
  108. }
  109. if p2.Pkgver.bigger(p.Pkgver) {
  110. return true
  111. }
  112. if p.Pkgver.bigger(p2.Pkgver) {
  113. return false
  114. }
  115. return p.Pkgrel < p2.Pkgrel
  116. }
  117. // Version returns the full version of the PKGBUILD (including epoch and rel)
  118. func (p *PKGBUILD) Version() string {
  119. if p.Epoch > 0 {
  120. return fmt.Sprintf("%d:%s-%d", p.Epoch, p.Pkgver, p.Pkgrel)
  121. }
  122. return fmt.Sprintf("%s-%d", p.Pkgver, p.Pkgrel)
  123. }
  124. // CompleteVersion returns a Complete version struct including version, rel and
  125. // epoch.
  126. func (p *PKGBUILD) CompleteVersion() CompleteVersion {
  127. return CompleteVersion{
  128. Version: p.Pkgver,
  129. Epoch: uint8(p.Epoch),
  130. Pkgrel: uint8(p.Pkgrel),
  131. }
  132. }
  133. // BuildDepends is Depends, MakeDepends and CheckDepends combined.
  134. func (p *PKGBUILD) BuildDepends() []*Dependency {
  135. // TODO real merge
  136. deps := make([]*Dependency, len(p.Depends)+len(p.Makedepends)+len(p.Checkdepends))
  137. deps = append(p.Depends, p.Makedepends...)
  138. deps = append(deps, p.Checkdepends...)
  139. return deps
  140. }
  141. // IsDevel returns true if package contains devel packages (-{bzr,git,svn,hg})
  142. // TODO: more robust check.
  143. func (p *PKGBUILD) IsDevel() bool {
  144. for _, name := range p.Pkgnames {
  145. if strings.HasSuffix(name, "-git") {
  146. return true
  147. }
  148. if strings.HasSuffix(name, "-svn") {
  149. return true
  150. }
  151. if strings.HasSuffix(name, "-hg") {
  152. return true
  153. }
  154. if strings.HasSuffix(name, "-bzr") {
  155. return true
  156. }
  157. }
  158. return false
  159. }
  160. // MustParseSRCINFO must parse the .SRCINFO given by path or it will panic
  161. func MustParseSRCINFO(path string) *PKGBUILD {
  162. pkgbuild, err := ParseSRCINFO(path)
  163. if err != nil {
  164. panic(err)
  165. }
  166. return pkgbuild
  167. }
  168. // ParseSRCINFO parses .SRCINFO file given by path.
  169. // This is a safe alternative to ParsePKGBUILD given that a .SRCINFO file is
  170. // available
  171. func ParseSRCINFO(path string) (*PKGBUILD, error) {
  172. f, err := ioutil.ReadFile(path)
  173. if err != nil {
  174. return nil, fmt.Errorf("unable to read file: %s, %s", path, err.Error())
  175. }
  176. return parsePKGBUILD(string(f))
  177. }
  178. // parse a PKGBUILD and check that the required fields has a non-empty value
  179. func parsePKGBUILD(input string) (*PKGBUILD, error) {
  180. pkgb, err := parse(input)
  181. if err != nil {
  182. return nil, err
  183. }
  184. if !validPkgver(string(pkgb.Pkgver)) {
  185. return nil, fmt.Errorf("invalid pkgver: %s", pkgb.Pkgver)
  186. }
  187. if len(pkgb.Arch) == 0 {
  188. return nil, fmt.Errorf("Arch missing")
  189. }
  190. if len(pkgb.Pkgnames) == 0 {
  191. return nil, fmt.Errorf("missing pkgname")
  192. }
  193. for _, name := range pkgb.Pkgnames {
  194. if !validPkgname(name) {
  195. return nil, fmt.Errorf("invalid pkgname: %s", name)
  196. }
  197. }
  198. return pkgb, nil
  199. }
  200. // parses a SRCINFO formatted PKGBUILD
  201. func parse(input string) (*PKGBUILD, error) {
  202. var pkgbuild *PKGBUILD
  203. var next item
  204. lexer := lex(input)
  205. Loop:
  206. for {
  207. token := lexer.nextItem()
  208. switch token.typ {
  209. case itemPkgbase:
  210. next = lexer.nextItem()
  211. pkgbuild = &PKGBUILD{Epoch: 0, Pkgbase: next.val}
  212. case itemPkgname:
  213. next = lexer.nextItem()
  214. pkgbuild.Pkgnames = append(pkgbuild.Pkgnames, next.val)
  215. case itemPkgver:
  216. next = lexer.nextItem()
  217. version, err := parseVersion(next.val)
  218. if err != nil {
  219. return nil, err
  220. }
  221. pkgbuild.Pkgver = version
  222. case itemPkgrel:
  223. next = lexer.nextItem()
  224. rel, err := strconv.ParseInt(next.val, 10, 0)
  225. if err != nil {
  226. return nil, err
  227. }
  228. pkgbuild.Pkgrel = int(rel)
  229. case itemPkgdir:
  230. next = lexer.nextItem()
  231. pkgbuild.Pkgdir = next.val
  232. case itemEpoch:
  233. next = lexer.nextItem()
  234. epoch, err := strconv.ParseInt(next.val, 10, 0)
  235. if err != nil {
  236. return nil, err
  237. }
  238. if epoch < 0 {
  239. return nil, fmt.Errorf("invalid epoch: %d", epoch)
  240. }
  241. pkgbuild.Epoch = int(epoch)
  242. case itemPkgdesc:
  243. next = lexer.nextItem()
  244. pkgbuild.Pkgdesc = next.val
  245. case itemArch:
  246. next = lexer.nextItem()
  247. if arch, ok := archs[next.val]; ok {
  248. pkgbuild.Arch = append(pkgbuild.Arch, arch)
  249. } else {
  250. return nil, fmt.Errorf("invalid Arch: %s", next.val)
  251. }
  252. case itemURL:
  253. next = lexer.nextItem()
  254. pkgbuild.URL = next.val
  255. case itemLicense:
  256. next = lexer.nextItem()
  257. pkgbuild.License = append(pkgbuild.License, next.val)
  258. case itemGroups:
  259. next = lexer.nextItem()
  260. pkgbuild.Groups = append(pkgbuild.Groups, next.val)
  261. case itemDepends:
  262. next = lexer.nextItem()
  263. deps, err := parseDependency(next.val, pkgbuild.Depends)
  264. if err != nil {
  265. return nil, err
  266. }
  267. pkgbuild.Depends = deps
  268. case itemOptdepends:
  269. next = lexer.nextItem()
  270. pkgbuild.Optdepends = append(pkgbuild.Optdepends, next.val)
  271. case itemMakedepends:
  272. next = lexer.nextItem()
  273. deps, err := parseDependency(next.val, pkgbuild.Makedepends)
  274. if err != nil {
  275. return nil, err
  276. }
  277. pkgbuild.Makedepends = deps
  278. case itemCheckdepends:
  279. next = lexer.nextItem()
  280. deps, err := parseDependency(next.val, pkgbuild.Checkdepends)
  281. if err != nil {
  282. return nil, err
  283. }
  284. pkgbuild.Checkdepends = deps
  285. case itemProvides:
  286. next = lexer.nextItem()
  287. pkgbuild.Provides = append(pkgbuild.Provides, next.val)
  288. case itemConflicts:
  289. next = lexer.nextItem()
  290. pkgbuild.Conflicts = append(pkgbuild.Conflicts, next.val)
  291. case itemReplaces:
  292. next = lexer.nextItem()
  293. pkgbuild.Replaces = append(pkgbuild.Replaces, next.val)
  294. case itemBackup:
  295. next = lexer.nextItem()
  296. pkgbuild.Backup = append(pkgbuild.Backup, next.val)
  297. case itemOptions:
  298. next = lexer.nextItem()
  299. pkgbuild.Options = append(pkgbuild.Options, next.val)
  300. case itemInstall:
  301. next = lexer.nextItem()
  302. pkgbuild.Install = next.val
  303. case itemChangelog:
  304. next = lexer.nextItem()
  305. pkgbuild.Changelog = next.val
  306. case itemSource:
  307. next = lexer.nextItem()
  308. pkgbuild.Source = append(pkgbuild.Source, next.val)
  309. case itemNoextract:
  310. next = lexer.nextItem()
  311. pkgbuild.Noextract = append(pkgbuild.Noextract, next.val)
  312. case itemMd5sums:
  313. next = lexer.nextItem()
  314. pkgbuild.Md5sums = append(pkgbuild.Md5sums, next.val)
  315. case itemSha1sums:
  316. next = lexer.nextItem()
  317. pkgbuild.Sha1sums = append(pkgbuild.Sha1sums, next.val)
  318. case itemSha224sums:
  319. next = lexer.nextItem()
  320. pkgbuild.Sha224sums = append(pkgbuild.Sha224sums, next.val)
  321. case itemSha256sums:
  322. next = lexer.nextItem()
  323. pkgbuild.Sha256sums = append(pkgbuild.Sha256sums, next.val)
  324. case itemSha384sums:
  325. next = lexer.nextItem()
  326. pkgbuild.Sha384sums = append(pkgbuild.Sha384sums, next.val)
  327. case itemSha512sums:
  328. next = lexer.nextItem()
  329. pkgbuild.Sha512sums = append(pkgbuild.Sha512sums, next.val)
  330. case itemValidpgpkeys:
  331. next = lexer.nextItem()
  332. pkgbuild.Validpgpkeys = append(pkgbuild.Validpgpkeys, next.val)
  333. case itemEndSplit:
  334. case itemError:
  335. return nil, fmt.Errorf(token.val)
  336. case itemEOF:
  337. break Loop
  338. default:
  339. return nil, fmt.Errorf(token.val)
  340. }
  341. }
  342. return pkgbuild, nil
  343. }
  344. // parse and validate a version string
  345. func parseVersion(s string) (Version, error) {
  346. if validPkgver(s) {
  347. return Version(s), nil
  348. }
  349. return "", fmt.Errorf("invalid version string: %s", s)
  350. }
  351. // check if name is a valid pkgname format
  352. func validPkgname(name string) bool {
  353. if len(name) < 1 {
  354. return false
  355. }
  356. if name[0] == '-' {
  357. return false
  358. }
  359. for _, r := range name {
  360. if !isValidPkgnameChar(uint8(r)) {
  361. return false
  362. }
  363. }
  364. return true
  365. }
  366. // check if version is a valid pkgver format
  367. func validPkgver(version string) bool {
  368. if len(version) < 1 {
  369. return false
  370. }
  371. if !isAlphaNumeric(version[0]) {
  372. return false
  373. }
  374. for _, r := range version[1:] {
  375. if !isValidPkgverChar(uint8(r)) {
  376. return false
  377. }
  378. }
  379. return true
  380. }
  381. // ParseDeps parses a string slice of dependencies into a slice of Dependency
  382. // objects.
  383. func ParseDeps(deps []string) ([]*Dependency, error) {
  384. var err error
  385. dependencies := make([]*Dependency, 0)
  386. for _, dep := range deps {
  387. dependencies, err = parseDependency(dep, dependencies)
  388. if err != nil {
  389. return nil, err
  390. }
  391. }
  392. return dependencies, nil
  393. }
  394. // parse dependency with possible version restriction
  395. func parseDependency(dep string, deps []*Dependency) ([]*Dependency, error) {
  396. var name string
  397. var dependency *Dependency
  398. if dep[0] == '-' {
  399. return nil, fmt.Errorf("invalid dependency name")
  400. }
  401. i := 0
  402. for _, c := range dep {
  403. if !isValidPkgnameChar(uint8(c)) {
  404. break
  405. }
  406. i++
  407. }
  408. // check if the dependency has been set before
  409. name = dep[0:i]
  410. for _, d := range deps {
  411. if d.Name == name {
  412. dependency = d
  413. }
  414. }
  415. if dependency == nil {
  416. dependency = &Dependency{
  417. Name: name,
  418. sgt: false,
  419. slt: false,
  420. }
  421. deps = append(deps, dependency)
  422. }
  423. if len(dep) == len(name) {
  424. return deps, nil
  425. }
  426. var eq bytes.Buffer
  427. for _, c := range dep[i:] {
  428. if c == '<' || c == '>' || c == '=' {
  429. i++
  430. eq.WriteRune(c)
  431. continue
  432. }
  433. break
  434. }
  435. version, err := NewCompleteVersion(dep[i:])
  436. if err != nil {
  437. return nil, err
  438. }
  439. switch eq.String() {
  440. case "==":
  441. dependency.MinVer = version
  442. dependency.MaxVer = version
  443. case "<=":
  444. dependency.MaxVer = version
  445. case ">=":
  446. dependency.MinVer = version
  447. case "<":
  448. dependency.MaxVer = version
  449. dependency.slt = true
  450. case ">":
  451. dependency.MinVer = version
  452. dependency.sgt = true
  453. }
  454. return deps, nil
  455. }
  456. // isLowerAlpha reports whether c is a lowercase alpha character
  457. func isLowerAlpha(c uint8) bool {
  458. return 'a' <= c && c <= 'z'
  459. }
  460. // check if c is a valid pkgname char
  461. func isValidPkgnameChar(c uint8) bool {
  462. return isLowerAlpha(c) || isDigit(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
  463. }
  464. // check if c is a valid pkgver char
  465. func isValidPkgverChar(c uint8) bool {
  466. return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.'
  467. }