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.
 

180 lines
3.5 KiB

package aur
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
archlinux "maze.io/archlinux.v0"
)
// Defaults
const (
DefaultURL = "https://aur.archlinux.org"
DefaultRPC = DefaultURL + "/rpc/"
DefaultVersion = 5
)
// Defaults
var (
DefaultHTTPClient = http.DefaultClient
)
// Client can query the AURJSON RPC interface
type Client struct {
RPC string
Version int
}
// New client with defaults
func New() *Client {
return &Client{
RPC: DefaultRPC,
Version: DefaultVersion,
}
}
func (c *Client) get(typ string, query url.Values) (*Response, error) {
query.Set("v", strconv.Itoa(c.Version))
query.Set("type", typ)
req, err := http.NewRequest("GET", c.RPC+"?"+query.Encode(), nil)
if err != nil {
return nil, err
}
res, err := DefaultHTTPClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var (
response = new(Response)
dec = json.NewDecoder(res.Body)
)
if err = dec.Decode(response); err != nil {
return nil, err
}
if response.Type == "error" {
return nil, response
}
return response, nil
}
// Info retrieves information about a single package
func (c *Client) Info(name string) (*Info, error) {
query := make(url.Values)
query.Add("arg[]", name)
i, err := c.infos(query)
if err != nil {
return nil, err
}
return i[0], nil
}
// Infos retrieves information about multiple packages
func (c *Client) Infos(names ...string) ([]*Info, error) {
if len(names) == 0 {
return nil, nil
}
query := make(url.Values)
for _, name := range names {
query.Add("arg[]", name)
}
return c.infos(query)
}
func (c *Client) infos(query url.Values) ([]*Info, error) {
r, err := c.get("info", query)
if err != nil {
return nil, err
}
if r.Type != "multiinfo" {
return nil, fmt.Errorf("aurjson: expected multiinfo response, got %q", r.Type)
}
var results []*Info
if err = json.Unmarshal(r.Results, &results); err != nil {
return nil, err
}
fixup(results)
return results, nil
}
// Search for a package or maintainer
func (c *Client) Search(keywords string, field Field) ([]*Info, error) {
query := make(url.Values)
query.Set("by", string(field))
query.Set("arg", keywords)
r, err := c.get("search", query)
if err != nil {
return nil, err
}
if r.Type != "search" {
return nil, fmt.Errorf("aurjson: expected search response, got %q", r.Type)
}
var results []*Info
if err = json.Unmarshal(r.Results, &results); err != nil {
return nil, err
}
fixup(results)
return results, nil
}
// Field is a searchable field
type Field string
// Field types
const (
Name Field = "name"
NameOrDescription Field = "name-desc"
Maintainer Field = "maintainer"
)
// Info about a package
type Info struct {
archlinux.Package
ID int64
PackageBaseID int64
NumVotes int
Popularity float64
Maintainer string
FirstSubmitted time.Time
LastModified time.Time
URLPath string
Keywords []string
}
func (i *Info) UnmarshalJSON(data []byte) error {
type Alias Info
aux := &struct {
FirstSubmitted int64
LastModified int64
*Alias
}{
Alias: (*Alias)(i),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
i.FirstSubmitted = time.Unix(aux.FirstSubmitted, 0)
i.LastModified = time.Unix(aux.LastModified, 0)
return nil
}
// fixup release information
func fixup(results []*Info) {
// Rectify releases
for _, r := range results {
if i := strings.IndexByte(r.Version, '-'); i != -1 {
r.Version, r.Release = r.Version[:i], r.Version[i+1:]
}
}
}