aur.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "os"
  10. "os/exec"
  11. "sort"
  12. "strings"
  13. )
  14. // AurInfo is the result of an info search
  15. type AurInfo struct {
  16. Version int `json:"version"`
  17. Type string `json:"type"`
  18. Resultcount int `json:"resultcount"`
  19. Results []struct {
  20. ID int `json:"ID"`
  21. Name string `json:"Name"`
  22. PackageBaseID int `json:"PackageBaseID"`
  23. PackageBase string `json:"PackageBase"`
  24. Version string `json:"Version"`
  25. Description string `json:"Description"`
  26. URL string `json:"URL"`
  27. NumVotes int `json:"NumVotes"`
  28. Popularity float64 `json:"Popularity"`
  29. OutOfDate interface{} `json:"OutOfDate"`
  30. Maintainer string `json:"Maintainer"`
  31. FirstSubmitted int `json:"FirstSubmitted"`
  32. LastModified int `json:"LastModified"`
  33. URLPath string `json:"URLPath"`
  34. Depends []string `json:"Depends"`
  35. MakeDepends []string `json:"MakeDepends"`
  36. OptDepends []string `json:"OptDepends"`
  37. Conflicts []string `json:"Conflicts"`
  38. License []string `json:"License"`
  39. Keywords []string `json:"Keywords"`
  40. } `json:"results"`
  41. }
  42. // AurResult describes an AUR package
  43. type AurResult struct {
  44. ID int `json:"ID"`
  45. Name string `json:"Name"`
  46. PackageBaseID int `json:"PackageBaseID"`
  47. PackageBase string `json:"PackageBase"`
  48. Version string `json:"Version"`
  49. Description string `json:"Description"`
  50. URL string `json:"URL"`
  51. NumVotes int `json:"NumVotes"`
  52. Popularity int `json:"Popularity"`
  53. OutOfDate interface{} `json:"OutOfDate"`
  54. Maintainer string `json:"Maintainer"`
  55. FirstSubmitted int `json:"FirstSubmitted"`
  56. LastModified int `json:"LastModified"`
  57. URLPath string `json:"URLPath"`
  58. }
  59. // AurSearch describes an AUR search
  60. type AurSearch struct {
  61. Resultcount int `json:"resultcount"`
  62. Results []AurResult `json:"results"`
  63. Type string `json:"type"`
  64. Version int `json:"version"`
  65. }
  66. // getJSON handles JSON retrieval and decoding to struct
  67. func getJSON(url string, target interface{}) error {
  68. r, err := http.Get(url)
  69. if err != nil {
  70. return err
  71. }
  72. defer r.Body.Close()
  73. return json.NewDecoder(r.Body).Decode(target)
  74. }
  75. func (r AurSearch) Len() int {
  76. return len(r.Results)
  77. }
  78. func (r AurSearch) Less(i, j int) bool {
  79. return r.Results[i].NumVotes > r.Results[j].NumVotes
  80. }
  81. func (r AurSearch) Swap(i, j int) {
  82. r.Results[i], r.Results[j] = r.Results[j], r.Results[i]
  83. }
  84. func searchAurPackages(pkg string) (search AurSearch, err error) {
  85. err = getJSON("https://aur.archlinux.org/rpc/?v=5&type=search&arg="+pkg, &search)
  86. sort.Sort(search)
  87. return
  88. }
  89. func infoAurPackage(pkg string) (info AurInfo, err error) {
  90. err = getJSON("https://aur.archlinux.org/rpc/?v=5&type=info&arg[]="+pkg, &info)
  91. return
  92. }
  93. func (r AurSearch) printSearch(index int) (err error) {
  94. for i, result := range r.Results {
  95. if index != SearchMode {
  96. fmt.Printf("%d \033[1maur/\x1B[33m%s \x1B[36m%s\033[0m (%d)\n %s\n",
  97. i+index, result.Name, result.Version, result.NumVotes, result.Description)
  98. } else {
  99. fmt.Printf("\033[1maur/\x1B[33m%s \x1B[36m%s\033[0m (%d)\n %s\n",
  100. result.Name, result.Version, result.NumVotes, result.Description)
  101. }
  102. }
  103. return
  104. }
  105. func downloadFile(filepath string, url string) (err error) {
  106. // Create the file
  107. out, err := os.Create(filepath)
  108. if err != nil {
  109. return err
  110. }
  111. defer out.Close()
  112. // Get the data
  113. resp, err := http.Get(url)
  114. if err != nil {
  115. return err
  116. }
  117. defer resp.Body.Close()
  118. // Writer the body to file
  119. _, err = io.Copy(out, resp.Body)
  120. if err != nil {
  121. return err
  122. }
  123. return nil
  124. }
  125. // To implement
  126. func (a AurResult) getDepsfromFile(pkgbuildLoc string) (err error) {
  127. var depend string
  128. file, err := os.Open(pkgbuildLoc)
  129. if err != nil {
  130. return err
  131. }
  132. defer file.Close()
  133. scanner := bufio.NewScanner(file)
  134. for scanner.Scan() {
  135. if strings.Contains(scanner.Text(), "optdepends=(") {
  136. continue
  137. }
  138. if strings.Contains(scanner.Text(), "depends=(") {
  139. depend = scanner.Text()
  140. fields := strings.Fields(depend)
  141. for _, i := range fields {
  142. fmt.Println(i)
  143. }
  144. break
  145. }
  146. }
  147. return nil
  148. }
  149. func (a AurResult) getDepsFromRPC() (final []string, err error) {
  150. f := func(c rune) bool {
  151. return c == '>' || c == '<' || c == '=' || c == ' '
  152. }
  153. info, err := infoAurPackage(a.Name)
  154. if len(info.Results) == 0 {
  155. return final, errors.New("Failed to get deps from RPC")
  156. }
  157. for _, deps := range info.Results[0].MakeDepends {
  158. fields := strings.FieldsFunc(deps, f)
  159. if !isInRepo(fields[0]) {
  160. final = append(final, fields[0])
  161. }
  162. }
  163. for _, deps := range info.Results[0].Depends {
  164. fields := strings.FieldsFunc(deps, f)
  165. if !isInRepo(fields[0]) {
  166. final = append(final, fields[0])
  167. }
  168. }
  169. return
  170. }
  171. func installAURPackage(pkgList string) (err error) {
  172. return err
  173. }
  174. func (a AurResult) getAURDependencies() (err error) {
  175. _, err = a.getDepsFromRPC()
  176. return nil
  177. }
  178. func (a AurResult) installResult() (err error) {
  179. // No need to use filepath.separators because it won't run on inferior platforms
  180. err = os.MkdirAll(BuildDir+"builds", 0755)
  181. if err != nil {
  182. fmt.Println(err)
  183. return
  184. }
  185. tarLocation := BuildDir + a.Name + ".tar.gz"
  186. err = downloadFile(tarLocation, BaseURL+a.URLPath)
  187. if err != nil {
  188. return
  189. }
  190. err = exec.Command(TarBin, "-xf", tarLocation, "-C", BuildDir).Run()
  191. if err != nil {
  192. return
  193. }
  194. a.getAURDependencies()
  195. os.Exit(0)
  196. fmt.Print("\033[1m\x1b[32m==> Edit PKGBUILD? (y/n)\033[0m")
  197. var response string
  198. fmt.Scanln(&response)
  199. if strings.ContainsAny(response, "y & Y") {
  200. editcmd := exec.Command(Editor, BuildDir+a.Name+"/"+"PKGBUILD")
  201. editcmd.Stdout = os.Stdout
  202. editcmd.Stderr = os.Stderr
  203. editcmd.Stdin = os.Stdin
  204. err = editcmd.Run()
  205. }
  206. err = os.Chdir(BuildDir + a.Name)
  207. if err != nil {
  208. return
  209. }
  210. makepkgcmd := exec.Command(MakepkgBin, "-sri")
  211. makepkgcmd.Stdout = os.Stdout
  212. makepkgcmd.Stderr = os.Stderr
  213. makepkgcmd.Stdin = os.Stdin
  214. err = makepkgcmd.Run()
  215. return
  216. }