pkgbuild.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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 Version // 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-%s", p.Epoch, p.Pkgver, p.Pkgrel)
  121. }
  122. return fmt.Sprintf("%s-%s", 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: 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. // ParseSRCINFOContent parses a .SRCINFO formatted byte slice.
  179. // This is a safe alternative to ParsePKGBUILD given that the .SRCINFO content
  180. // is available
  181. func ParseSRCINFOContent(content []byte) (*PKGBUILD, error) {
  182. return parsePKGBUILD(string(content))
  183. }
  184. // parse a PKGBUILD and check that the required fields has a non-empty value
  185. func parsePKGBUILD(input string) (*PKGBUILD, error) {
  186. pkgb, err := parse(input)
  187. if err != nil {
  188. return nil, err
  189. }
  190. if !validPkgver(string(pkgb.Pkgver)) {
  191. return nil, fmt.Errorf("invalid pkgver: %s", pkgb.Pkgver)
  192. }
  193. if len(pkgb.Arch) == 0 {
  194. return nil, fmt.Errorf("Arch missing")
  195. }
  196. if len(pkgb.Pkgnames) == 0 {
  197. return nil, fmt.Errorf("missing pkgname")
  198. }
  199. for _, name := range pkgb.Pkgnames {
  200. if !validPkgname(name) {
  201. return nil, fmt.Errorf("invalid pkgname: %s", name)
  202. }
  203. }
  204. return pkgb, nil
  205. }
  206. // parses a SRCINFO formatted PKGBUILD
  207. func parse(input string) (*PKGBUILD, error) {
  208. var pkgbuild *PKGBUILD
  209. var next item
  210. lexer := lex(input)
  211. Loop:
  212. for {
  213. token := lexer.nextItem()
  214. switch token.typ {
  215. case itemPkgbase:
  216. next = lexer.nextItem()
  217. pkgbuild = &PKGBUILD{Epoch: 0, Pkgbase: next.val}
  218. case itemPkgname:
  219. next = lexer.nextItem()
  220. pkgbuild.Pkgnames = append(pkgbuild.Pkgnames, next.val)
  221. case itemPkgver:
  222. next = lexer.nextItem()
  223. version, err := parseVersion(next.val)
  224. if err != nil {
  225. return nil, err
  226. }
  227. pkgbuild.Pkgver = version
  228. case itemPkgrel:
  229. next = lexer.nextItem()
  230. rel, err := parseVersion(next.val)
  231. if err != nil {
  232. return nil, err
  233. }
  234. pkgbuild.Pkgrel = rel
  235. case itemPkgdir:
  236. next = lexer.nextItem()
  237. pkgbuild.Pkgdir = next.val
  238. case itemEpoch:
  239. next = lexer.nextItem()
  240. epoch, err := strconv.ParseInt(next.val, 10, 0)
  241. if err != nil {
  242. return nil, err
  243. }
  244. if epoch < 0 {
  245. return nil, fmt.Errorf("invalid epoch: %d", epoch)
  246. }
  247. pkgbuild.Epoch = int(epoch)
  248. case itemPkgdesc:
  249. next = lexer.nextItem()
  250. pkgbuild.Pkgdesc = next.val
  251. case itemArch:
  252. next = lexer.nextItem()
  253. if arch, ok := archs[next.val]; ok {
  254. pkgbuild.Arch = append(pkgbuild.Arch, arch)
  255. } else {
  256. return nil, fmt.Errorf("invalid Arch: %s", next.val)
  257. }
  258. case itemURL:
  259. next = lexer.nextItem()
  260. pkgbuild.URL = next.val
  261. case itemLicense:
  262. next = lexer.nextItem()
  263. pkgbuild.License = append(pkgbuild.License, next.val)
  264. case itemGroups:
  265. next = lexer.nextItem()
  266. pkgbuild.Groups = append(pkgbuild.Groups, next.val)
  267. case itemDepends:
  268. next = lexer.nextItem()
  269. deps, err := parseDependency(next.val, pkgbuild.Depends)
  270. if err != nil {
  271. return nil, err
  272. }
  273. pkgbuild.Depends = deps
  274. case itemOptdepends:
  275. next = lexer.nextItem()
  276. pkgbuild.Optdepends = append(pkgbuild.Optdepends, next.val)
  277. case itemMakedepends:
  278. next = lexer.nextItem()
  279. deps, err := parseDependency(next.val, pkgbuild.Makedepends)
  280. if err != nil {
  281. return nil, err
  282. }
  283. pkgbuild.Makedepends = deps
  284. case itemCheckdepends:
  285. next = lexer.nextItem()
  286. deps, err := parseDependency(next.val, pkgbuild.Checkdepends)
  287. if err != nil {
  288. return nil, err
  289. }
  290. pkgbuild.Checkdepends = deps
  291. case itemProvides:
  292. next = lexer.nextItem()
  293. pkgbuild.Provides = append(pkgbuild.Provides, next.val)
  294. case itemConflicts:
  295. next = lexer.nextItem()
  296. pkgbuild.Conflicts = append(pkgbuild.Conflicts, next.val)
  297. case itemReplaces:
  298. next = lexer.nextItem()
  299. pkgbuild.Replaces = append(pkgbuild.Replaces, next.val)
  300. case itemBackup:
  301. next = lexer.nextItem()
  302. pkgbuild.Backup = append(pkgbuild.Backup, next.val)
  303. case itemOptions:
  304. next = lexer.nextItem()
  305. pkgbuild.Options = append(pkgbuild.Options, next.val)
  306. case itemInstall:
  307. next = lexer.nextItem()
  308. pkgbuild.Install = next.val
  309. case itemChangelog:
  310. next = lexer.nextItem()
  311. pkgbuild.Changelog = next.val
  312. case itemSource:
  313. next = lexer.nextItem()
  314. pkgbuild.Source = append(pkgbuild.Source, next.val)
  315. case itemNoextract:
  316. next = lexer.nextItem()
  317. pkgbuild.Noextract = append(pkgbuild.Noextract, next.val)
  318. case itemMd5sums:
  319. next = lexer.nextItem()
  320. pkgbuild.Md5sums = append(pkgbuild.Md5sums, next.val)
  321. case itemSha1sums:
  322. next = lexer.nextItem()
  323. pkgbuild.Sha1sums = append(pkgbuild.Sha1sums, next.val)
  324. case itemSha224sums:
  325. next = lexer.nextItem()
  326. pkgbuild.Sha224sums = append(pkgbuild.Sha224sums, next.val)
  327. case itemSha256sums:
  328. next = lexer.nextItem()
  329. pkgbuild.Sha256sums = append(pkgbuild.Sha256sums, next.val)
  330. case itemSha384sums:
  331. next = lexer.nextItem()
  332. pkgbuild.Sha384sums = append(pkgbuild.Sha384sums, next.val)
  333. case itemSha512sums:
  334. next = lexer.nextItem()
  335. pkgbuild.Sha512sums = append(pkgbuild.Sha512sums, next.val)
  336. case itemValidpgpkeys:
  337. next = lexer.nextItem()
  338. pkgbuild.Validpgpkeys = append(pkgbuild.Validpgpkeys, next.val)
  339. case itemEndSplit:
  340. case itemError:
  341. return nil, fmt.Errorf(token.val)
  342. case itemEOF:
  343. break Loop
  344. default:
  345. return nil, fmt.Errorf(token.val)
  346. }
  347. }
  348. return pkgbuild, nil
  349. }
  350. // parse and validate a version string
  351. func parseVersion(s string) (Version, error) {
  352. if validPkgver(s) {
  353. return Version(s), nil
  354. }
  355. return "", fmt.Errorf("invalid version string: %s", s)
  356. }
  357. // check if name is a valid pkgname format
  358. func validPkgname(name string) bool {
  359. if len(name) < 1 {
  360. return false
  361. }
  362. if name[0] == '-' {
  363. return false
  364. }
  365. for _, r := range name {
  366. if !isValidPkgnameChar(uint8(r)) {
  367. return false
  368. }
  369. }
  370. return true
  371. }
  372. // check if version is a valid pkgver format
  373. func validPkgver(version string) bool {
  374. if len(version) < 1 {
  375. return false
  376. }
  377. if !isAlphaNumeric(version[0]) {
  378. return false
  379. }
  380. for _, r := range version[1:] {
  381. if !isValidPkgverChar(uint8(r)) {
  382. return false
  383. }
  384. }
  385. return true
  386. }
  387. // ParseDeps parses a string slice of dependencies into a slice of Dependency
  388. // objects.
  389. func ParseDeps(deps []string) ([]*Dependency, error) {
  390. var err error
  391. dependencies := make([]*Dependency, 0)
  392. for _, dep := range deps {
  393. dependencies, err = parseDependency(dep, dependencies)
  394. if err != nil {
  395. return nil, err
  396. }
  397. }
  398. return dependencies, nil
  399. }
  400. // parse dependency with possible version restriction
  401. func parseDependency(dep string, deps []*Dependency) ([]*Dependency, error) {
  402. var name string
  403. var dependency *Dependency
  404. if dep == "" {
  405. return deps, nil
  406. }
  407. if dep[0] == '-' {
  408. return nil, fmt.Errorf("invalid dependency name")
  409. }
  410. i := 0
  411. for _, c := range dep {
  412. if !isValidPkgnameChar(uint8(c)) {
  413. break
  414. }
  415. i++
  416. }
  417. // check if the dependency has been set before
  418. name = dep[0:i]
  419. for _, d := range deps {
  420. if d.Name == name {
  421. dependency = d
  422. }
  423. }
  424. if dependency == nil {
  425. dependency = &Dependency{
  426. Name: name,
  427. sgt: false,
  428. slt: false,
  429. }
  430. deps = append(deps, dependency)
  431. }
  432. if len(dep) == len(name) {
  433. return deps, nil
  434. }
  435. var eq bytes.Buffer
  436. for _, c := range dep[i:] {
  437. if c == '<' || c == '>' || c == '=' {
  438. i++
  439. eq.WriteRune(c)
  440. continue
  441. }
  442. break
  443. }
  444. version, err := NewCompleteVersion(dep[i:])
  445. if err != nil {
  446. return nil, err
  447. }
  448. switch eq.String() {
  449. case "==":
  450. dependency.MinVer = version
  451. dependency.MaxVer = version
  452. case "<=":
  453. dependency.MaxVer = version
  454. case ">=":
  455. dependency.MinVer = version
  456. case "<":
  457. dependency.MaxVer = version
  458. dependency.slt = true
  459. case ">":
  460. dependency.MinVer = version
  461. dependency.sgt = true
  462. }
  463. return deps, nil
  464. }
  465. // isLowerAlpha reports whether c is a lowercase alpha character
  466. func isLowerAlpha(c uint8) bool {
  467. return 'a' <= c && c <= 'z'
  468. }
  469. // check if c is a valid pkgname char
  470. func isValidPkgnameChar(c uint8) bool {
  471. return isLowerAlpha(c) || isDigit(c) || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
  472. }
  473. // check if c is a valid pkgver char
  474. func isValidPkgverChar(c uint8) bool {
  475. return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.' || c == '~'
  476. }