parent
a9d92b3074
commit
11f2017bff
|
@ -60,7 +60,8 @@ func unpack(src, name string) error {
|
|||
}
|
||||
uaIface, err := archiver.ByExtension(src)
|
||||
if err != nil {
|
||||
if filepath.Ext(src) == binExt {
|
||||
ext := filepath.Ext(src)
|
||||
if ext == binExt || len(ext) > 3 {
|
||||
dest = filepath.Join(dest, name+binExt)
|
||||
if err := os.Rename(src, dest); err != nil {
|
||||
return err
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
amd64Re = regexp.MustCompile(`amd64|x86_64|64-bit|[^m]64`)
|
||||
amd64Re = regexp.MustCompile(`amd64|x86_64|64-bit|[^mhv]64`)
|
||||
linuxRe = regexp.MustCompile(`linux`)
|
||||
windowsRe = regexp.MustCompile(`windows|\Awin`)
|
||||
)
|
||||
|
@ -23,11 +23,13 @@ type Release struct {
|
|||
type Asset struct {
|
||||
Name string
|
||||
DownloadURL string
|
||||
Version string // Release.Name
|
||||
}
|
||||
|
||||
type Forger interface {
|
||||
Name() string
|
||||
Latest() (Release, error)
|
||||
latestRelease() (Release, error)
|
||||
tagRelease(tag string) (Release, error)
|
||||
}
|
||||
|
||||
func splitURI(uri string) (string, []string, error) {
|
||||
|
@ -44,7 +46,7 @@ func splitURI(uri string) (string, []string, error) {
|
|||
return u.String(), paths, nil
|
||||
}
|
||||
|
||||
func Latest(f Forger) (Asset, error) {
|
||||
func TagRelease(f Forger, tag string) (Asset, error) {
|
||||
var asset Asset
|
||||
|
||||
var re *regexp.Regexp
|
||||
|
@ -57,7 +59,41 @@ func Latest(f Forger) (Asset, error) {
|
|||
return asset, fmt.Errorf("%q is not a supported OS", runtime.GOOS)
|
||||
}
|
||||
|
||||
release, err := f.Latest()
|
||||
release, err := f.tagRelease(tag)
|
||||
if err != nil {
|
||||
return asset, fmt.Errorf("could not get %q release: %w", tag, err)
|
||||
}
|
||||
|
||||
for _, a := range release.Assets {
|
||||
if amd64Re.MatchString(a.Name) && re.MatchString(a.Name) {
|
||||
fmt.Printf("found %q\n", a.Name)
|
||||
asset = a
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if asset.Name == "" {
|
||||
return asset, errors.New("no release found for this OS")
|
||||
}
|
||||
|
||||
asset.Version = release.Name
|
||||
return asset, nil
|
||||
}
|
||||
|
||||
func LatestRelease(f Forger) (Asset, error) {
|
||||
var asset Asset
|
||||
|
||||
var re *regexp.Regexp
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
re = linuxRe
|
||||
case "windows":
|
||||
re = windowsRe
|
||||
default:
|
||||
return asset, fmt.Errorf("%q is not a supported OS", runtime.GOOS)
|
||||
}
|
||||
|
||||
release, err := f.latestRelease()
|
||||
if err != nil {
|
||||
return asset, fmt.Errorf("could not get latest release: %w", err)
|
||||
}
|
||||
|
@ -74,5 +110,6 @@ func Latest(f Forger) (Asset, error) {
|
|||
return asset, errors.New("no release found for this OS")
|
||||
}
|
||||
|
||||
asset.Version = release.Name
|
||||
return asset, nil
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
var _ Forger = (*Gitea)(nil)
|
||||
|
||||
type Gitea struct {
|
||||
BaseURL string
|
||||
Owner string
|
||||
|
@ -40,7 +38,7 @@ func (g Gitea) Name() string {
|
|||
return g.Repo
|
||||
}
|
||||
|
||||
func (g Gitea) Latest() (Release, error) {
|
||||
func (g Gitea) latestRelease() (Release, error) {
|
||||
var release Release
|
||||
|
||||
var releases []GiteaRelease
|
||||
|
@ -70,3 +68,29 @@ func (g Gitea) Latest() (Release, error) {
|
|||
|
||||
return release, nil
|
||||
}
|
||||
|
||||
func (g Gitea) tagRelease(tag string) (Release, error) {
|
||||
var release Release
|
||||
|
||||
u := fmt.Sprintf("%s/api/v1/repos/%s/%s/releases/tags/%s", g.BaseURL, g.Owner, g.Repo, tag)
|
||||
res, err := http.Get(u)
|
||||
if err != nil {
|
||||
return release, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var r GiteaRelease
|
||||
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
|
||||
return release, err
|
||||
}
|
||||
|
||||
release.Name = r.TagName
|
||||
for _, a := range r.Assets {
|
||||
release.Assets = append(release.Assets, Asset{
|
||||
Name: a.Name,
|
||||
DownloadURL: a.BrowserDownloadURL,
|
||||
})
|
||||
}
|
||||
|
||||
return release, nil
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
var _ Forger = (*GitHub)(nil)
|
||||
|
||||
type GitHub struct {
|
||||
Owner string
|
||||
Repo string
|
||||
|
@ -36,7 +34,7 @@ func (g GitHub) Name() string {
|
|||
return g.Repo
|
||||
}
|
||||
|
||||
func (g GitHub) Latest() (Release, error) {
|
||||
func (g GitHub) latestRelease() (Release, error) {
|
||||
var release Release
|
||||
|
||||
var r GitHubRelease
|
||||
|
@ -61,3 +59,29 @@ func (g GitHub) Latest() (Release, error) {
|
|||
|
||||
return release, nil
|
||||
}
|
||||
|
||||
func (g GitHub) tagRelease(tag string) (Release, error) {
|
||||
var release Release
|
||||
|
||||
var r GitHubRelease
|
||||
u := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, tag)
|
||||
res, err := http.Get(u)
|
||||
if err != nil {
|
||||
return release, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
|
||||
return release, err
|
||||
}
|
||||
|
||||
release.Name = r.TagName
|
||||
for _, a := range r.Assets {
|
||||
release.Assets = append(release.Assets, Asset{
|
||||
Name: a.Name,
|
||||
DownloadURL: a.BrowserDownloadURL,
|
||||
})
|
||||
}
|
||||
|
||||
return release, nil
|
||||
}
|
||||
|
|
48
main.go
48
main.go
|
@ -9,7 +9,6 @@ import (
|
|||
"go.jolheiser.com/eget/disk"
|
||||
"go.jolheiser.com/eget/forge"
|
||||
"go.jolheiser.com/eget/meta"
|
||||
"go.jolheiser.com/eget/shell"
|
||||
)
|
||||
|
||||
var Version = "develop"
|
||||
|
@ -24,18 +23,16 @@ func main() {
|
|||
fs.BoolVar(updateFlag, "u", *updateFlag, "--update")
|
||||
deleteFlag := flag.Bool("delete", false, "Delete package")
|
||||
fs.BoolVar(deleteFlag, "d", *deleteFlag, "--delete")
|
||||
nuFlag := fs.Bool("nu", false, "Write out Nu environment")
|
||||
syncFlag := fs.Bool("sync", false, "Sync packages")
|
||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||
fs.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
if *nuFlag {
|
||||
nu, err := shell.Nu()
|
||||
if err != nil {
|
||||
if *syncFlag {
|
||||
if err := sync(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(nu)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -68,7 +65,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
asset, err := forge.Latest(f)
|
||||
asset, err := forge.LatestRelease(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -78,7 +75,7 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if strings.EqualFold(asset.Name, m.Packages[name]) {
|
||||
if strings.EqualFold(asset.Version, m.Packages[name].Version) {
|
||||
fmt.Printf("%q is up-to-date\n", name)
|
||||
return
|
||||
}
|
||||
|
@ -91,7 +88,7 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
if err := meta.Upsert(name, asset.Name); err != nil {
|
||||
if err := meta.Upsert(name, uri, asset.Version); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
@ -106,3 +103,36 @@ func uriName(uri string) string {
|
|||
parts := strings.FieldsFunc(uri, func(r rune) bool { return r == '/' })
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
func sync() error {
|
||||
m, err := meta.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var f forge.Forger
|
||||
for name, pkg := range m.Packages {
|
||||
fmt.Printf("syncing %q\n", name)
|
||||
if err := os.RemoveAll(disk.Path(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err = forge.NewGitea(pkg.Repo)
|
||||
if strings.HasPrefix(pkg.Repo, "github") {
|
||||
f, err = forge.NewGitHub(pkg.Repo)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asset, err := forge.TagRelease(f, pkg.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := disk.Install(name, asset); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
64
meta/meta.go
64
meta/meta.go
|
@ -8,31 +8,44 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"go.jolheiser.com/eget/disk"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
type Meta struct {
|
||||
Packages map[string]string `json:"packages"`
|
||||
Packages map[string]Package `json:"packages"`
|
||||
}
|
||||
|
||||
func Upsert(name, version string) error {
|
||||
type Package struct {
|
||||
Repo string `json:"repo"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func Upsert(name, repo, version string) error {
|
||||
m, err := Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for n := range m.Packages {
|
||||
if strings.EqualFold(n, name) {
|
||||
m.Packages[n] = version
|
||||
m.Packages[n] = Package{
|
||||
Repo: repo,
|
||||
Version: version,
|
||||
}
|
||||
return save(m)
|
||||
}
|
||||
}
|
||||
m.Packages[name] = version
|
||||
m.Packages[name] = Package{
|
||||
Repo: repo,
|
||||
Version: version,
|
||||
}
|
||||
return save(m)
|
||||
}
|
||||
|
||||
func Read() (Meta, error) {
|
||||
m := Meta{
|
||||
Packages: make(map[string]string),
|
||||
Packages: make(map[string]Package),
|
||||
}
|
||||
fp, err := metaPath()
|
||||
if err != nil {
|
||||
|
@ -68,7 +81,11 @@ func Remove(name string) error {
|
|||
}
|
||||
|
||||
func metaPath() (string, error) {
|
||||
return xdg.DataFile("eget/meta.json")
|
||||
return xdg.ConfigFile("eget/packages.json")
|
||||
}
|
||||
|
||||
func nushellPath() (string, error) {
|
||||
return xdg.DataFile("eget/eget.nu")
|
||||
}
|
||||
|
||||
func save(m Meta) error {
|
||||
|
@ -80,6 +97,39 @@ func save(m Meta) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("could not create meta file: %w", err)
|
||||
}
|
||||
if err := json.NewEncoder(fi).Encode(m); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fi.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fp, err = nushellPath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get nushell path: %w", err)
|
||||
}
|
||||
fi, err = os.Create(fp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create nushell file: %w", err)
|
||||
}
|
||||
defer fi.Close()
|
||||
return json.NewEncoder(fi).Encode(m)
|
||||
out, err := m.nushell()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not generate nushell environment: %w", err)
|
||||
}
|
||||
fi.WriteString(out)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Meta) nushell() (string, error) {
|
||||
tmpl := "let-env PATH = ($env.PATH | append '%s')\n"
|
||||
|
||||
var out strings.Builder
|
||||
out.WriteString("# managed by eget; DO NOT EDIT\n\n")
|
||||
for name := range m.Packages {
|
||||
out.WriteString(fmt.Sprintf(tmpl, disk.Path(name)))
|
||||
}
|
||||
|
||||
return out.String(), nil
|
||||
}
|
||||
|
|
25
shell/nu.go
25
shell/nu.go
|
@ -1,25 +0,0 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.jolheiser.com/eget/disk"
|
||||
"go.jolheiser.com/eget/meta"
|
||||
)
|
||||
|
||||
func Nu() (string, error) {
|
||||
tmpl := "let-env PATH = ($env.PATH | append '%s')\n"
|
||||
m, err := meta.Read()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var out strings.Builder
|
||||
out.WriteString("# managed by eget; DO NOT EDIT\n\n")
|
||||
for name := range m.Packages {
|
||||
out.WriteString(fmt.Sprintf(tmpl, disk.Path(name)))
|
||||
}
|
||||
|
||||
return out.String(), nil
|
||||
}
|
Reference in New Issue