genesis-index/release.go

263 lines
5.0 KiB
Go

package main
import (
"fmt"
"github.com/jhunt/go-db"
"github.com/starkandwayne/goutils/log"
)
type Release struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
SHA1 string `json:"sha1,omitempty"`
URL string `json:"url,omitempty"`
Disabled bool `json:"disabled"`
}
func CreateRelease(d *db.DB, name, url string) error {
return d.Exec(`INSERT INTO releases (name, url) VALUES ($1, $2)`, name, url)
}
func FindAllReleases(d *db.DB) ([]string, error) {
l := make([]string, 0)
r, err := d.Query(`SELECT name FROM releases`)
if err != nil {
return l, err
}
for r.Next() {
var o string
if err = r.Scan(&o); err != nil {
return l, err
}
l = append(l, o)
}
return l, nil
}
func FindRelease(d *db.DB, name string) (Release, error) {
var o Release
r, err := d.Query(`SELECT name, url, disabled FROM releases WHERE name = $1`, name)
if err != nil {
return o, err
}
if !r.Next() {
return o, fmt.Errorf("release '%s' not found", name)
}
if err = r.Scan(&o.Name, &o.URL, &o.Disabled); err != nil {
return o, err
}
if r.Next() {
return o, fmt.Errorf("duplicate releases found for '%s'", name)
}
return o, nil
}
func FindAllReleaseVersions(d *db.DB, name string) ([]Release, error) {
l := make([]Release, 0)
r, err := d.Query(`
SELECT
name,
version,
sha1,
url
FROM release_versions
WHERE name = $1
AND valid = 1
ORDER BY
vnum DESC`, name)
if err != nil {
return l, err
}
for r.Next() {
var o Release
if err = r.Scan(&o.Name, &o.Version, &o.SHA1, &o.URL); err != nil {
return l, err
}
l = append(l, o)
}
if len(l) == 0 {
n, err := d.Count("SELECT * FROM releases WHERE name = $1", name)
if err == nil && n != 0 {
return l, nil
}
return l, fmt.Errorf("release '%s' not found", name)
}
return l, nil
}
func FindLatestReleaseVersions(d *db.DB) ([]Release, error) {
l := make([]Release, 0)
r, err := d.Query(`
SELECT
v.name,
v.version,
v.sha1,
v.url
FROM
release_versions v
INNER JOIN (
SELECT
name,
MAX(vnum) AS latest
FROM release_versions
WHERE valid = 1
GROUP BY name
) q
ON
q.name = v.name
AND q.latest = v.vnum
`)
if err != nil {
return l, err
}
for r.Next() {
var o Release
if err = r.Scan(&o.Name, &o.Version, &o.SHA1, &o.URL); err != nil {
return l, err
}
l = append(l, o)
}
return l, nil
}
func FindReleaseVersion(d *db.DB, name, version string) (Release, error) {
var o Release
where := ""
args := make([]interface{}, 1)
args[0] = name
if version != "" {
where = "AND version = $2"
args = append(args, version)
}
r, err := d.Query(fmt.Sprintf(`
SELECT
name,
version,
sha1,
url
FROM
release_versions
WHERE name = $1
AND valid = 1
%s
ORDER BY
vnum DESC
LIMIT 1
`, where), args...)
if err != nil {
return o, err
}
if !r.Next() {
if version != "" {
return o, fmt.Errorf("version '%s' of release '%s' not found", version, name)
}
n, err := d.Count("SELECT * FROM releases WHERE name = $1", name)
if err == nil && n != 0 {
return o, fmt.Errorf("no known versions for release '%s'", name)
}
return o, fmt.Errorf("release '%s' not found", name)
}
if err = r.Scan(&o.Name, &o.Version, &o.SHA1, &o.URL); err != nil {
return o, err
}
if r.Next() {
return o, fmt.Errorf("duplicate releases found for '%s'", name)
}
return o, nil
}
func DeleteRelease(d *db.DB, name string) error {
err := d.Exec(`DELETE FROM release_versions WHERE name = $1`, name)
if err != nil {
return err
}
return d.Exec(`DELETE FROM releases WHERE name = $1`, name)
}
func DeleteReleaseVersion(d *db.DB, name, version string) error {
return d.Exec(`DELETE FROM release_versions WHERE name = $1 AND version = $2`, name, version)
}
func CheckReleaseVersion(d *db.DB, name, version string) error {
release, err := FindRelease(d, name)
if err != nil {
log.Debugf("unable to find release '%s': %s", name, err)
return err
}
/* generate the URL from the template */
url := urlify(release.URL, version)
log.Debugf("checking version '%s' of '%s' at '%s'", version, name, url)
recheck := true
n, _ := d.Count(`SELECT * FROM release_versions WHERE name = $1 AND version = $2`, name, version)
if n == 0 {
recheck = false
num, err := vnum(version)
if err != nil {
return err
}
d.Exec(`INSERT INTO release_versions (name, version, vnum, valid) VALUES ($1, $2, $3, 0)`,
name, version, num)
}
/* do the async part in its own goroutine */
go func() {
/* download and SHA1 the file */
sha1, err := sha1sum(url)
if err != nil {
log.Debugf("download/sha1sum failed: %s...", err)
if !recheck {
d.Exec(`DELETE FROM release_versions WHERE name = $1 AND version = $2`,
name, version)
}
return
}
err = d.Exec(`
UPDATE release_versions
SET valid = 1,
url = $3,
sha1 = $4
WHERE name = $1
AND version = $2`, name, version, url, sha1)
if err != nil {
log.Debugf("unable to check version '%s' of '%s': %s", version, name, err)
return
}
}()
return nil
}