parent
a9d92b3074
commit
11f2017bff
|
@ -60,7 +60,8 @@ func unpack(src, name string) error {
|
||||||
}
|
}
|
||||||
uaIface, err := archiver.ByExtension(src)
|
uaIface, err := archiver.ByExtension(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if filepath.Ext(src) == binExt {
|
ext := filepath.Ext(src)
|
||||||
|
if ext == binExt || len(ext) > 3 {
|
||||||
dest = filepath.Join(dest, name+binExt)
|
dest = filepath.Join(dest, name+binExt)
|
||||||
if err := os.Rename(src, dest); err != nil {
|
if err := os.Rename(src, dest); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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`)
|
linuxRe = regexp.MustCompile(`linux`)
|
||||||
windowsRe = regexp.MustCompile(`windows|\Awin`)
|
windowsRe = regexp.MustCompile(`windows|\Awin`)
|
||||||
)
|
)
|
||||||
|
@ -23,11 +23,13 @@ type Release struct {
|
||||||
type Asset struct {
|
type Asset struct {
|
||||||
Name string
|
Name string
|
||||||
DownloadURL string
|
DownloadURL string
|
||||||
|
Version string // Release.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
type Forger interface {
|
type Forger interface {
|
||||||
Name() string
|
Name() string
|
||||||
Latest() (Release, error)
|
latestRelease() (Release, error)
|
||||||
|
tagRelease(tag string) (Release, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitURI(uri string) (string, []string, error) {
|
func splitURI(uri string) (string, []string, error) {
|
||||||
|
@ -44,7 +46,7 @@ func splitURI(uri string) (string, []string, error) {
|
||||||
return u.String(), paths, nil
|
return u.String(), paths, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Latest(f Forger) (Asset, error) {
|
func TagRelease(f Forger, tag string) (Asset, error) {
|
||||||
var asset Asset
|
var asset Asset
|
||||||
|
|
||||||
var re *regexp.Regexp
|
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)
|
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 {
|
if err != nil {
|
||||||
return asset, fmt.Errorf("could not get latest release: %w", err)
|
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")
|
return asset, errors.New("no release found for this OS")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asset.Version = release.Name
|
||||||
return asset, nil
|
return asset, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Forger = (*Gitea)(nil)
|
|
||||||
|
|
||||||
type Gitea struct {
|
type Gitea struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
Owner string
|
Owner string
|
||||||
|
@ -40,7 +38,7 @@ func (g Gitea) Name() string {
|
||||||
return g.Repo
|
return g.Repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Gitea) Latest() (Release, error) {
|
func (g Gitea) latestRelease() (Release, error) {
|
||||||
var release Release
|
var release Release
|
||||||
|
|
||||||
var releases []GiteaRelease
|
var releases []GiteaRelease
|
||||||
|
@ -70,3 +68,29 @@ func (g Gitea) Latest() (Release, error) {
|
||||||
|
|
||||||
return release, nil
|
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"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Forger = (*GitHub)(nil)
|
|
||||||
|
|
||||||
type GitHub struct {
|
type GitHub struct {
|
||||||
Owner string
|
Owner string
|
||||||
Repo string
|
Repo string
|
||||||
|
@ -36,7 +34,7 @@ func (g GitHub) Name() string {
|
||||||
return g.Repo
|
return g.Repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GitHub) Latest() (Release, error) {
|
func (g GitHub) latestRelease() (Release, error) {
|
||||||
var release Release
|
var release Release
|
||||||
|
|
||||||
var r GitHubRelease
|
var r GitHubRelease
|
||||||
|
@ -61,3 +59,29 @@ func (g GitHub) Latest() (Release, error) {
|
||||||
|
|
||||||
return release, nil
|
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/disk"
|
||||||
"go.jolheiser.com/eget/forge"
|
"go.jolheiser.com/eget/forge"
|
||||||
"go.jolheiser.com/eget/meta"
|
"go.jolheiser.com/eget/meta"
|
||||||
"go.jolheiser.com/eget/shell"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = "develop"
|
var Version = "develop"
|
||||||
|
@ -24,18 +23,16 @@ func main() {
|
||||||
fs.BoolVar(updateFlag, "u", *updateFlag, "--update")
|
fs.BoolVar(updateFlag, "u", *updateFlag, "--update")
|
||||||
deleteFlag := flag.Bool("delete", false, "Delete package")
|
deleteFlag := flag.Bool("delete", false, "Delete package")
|
||||||
fs.BoolVar(deleteFlag, "d", *deleteFlag, "--delete")
|
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 {
|
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||||
fs.Usage()
|
fs.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if *nuFlag {
|
if *syncFlag {
|
||||||
nu, err := shell.Nu()
|
if err := sync(); err != nil {
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
fmt.Println(nu)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +65,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
asset, err := forge.Latest(f)
|
asset, err := forge.LatestRelease(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +75,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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)
|
fmt.Printf("%q is up-to-date\n", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -91,7 +88,7 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := meta.Upsert(name, asset.Name); err != nil {
|
if err := meta.Upsert(name, uri, asset.Version); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,3 +103,36 @@ func uriName(uri string) string {
|
||||||
parts := strings.FieldsFunc(uri, func(r rune) bool { return r == '/' })
|
parts := strings.FieldsFunc(uri, func(r rune) bool { return r == '/' })
|
||||||
return parts[len(parts)-1]
|
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
|
||||||
|
}
|
||||||
|
|
66
meta/meta.go
66
meta/meta.go
|
@ -8,31 +8,44 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.jolheiser.com/eget/disk"
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Meta struct {
|
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()
|
m, err := Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for n := range m.Packages {
|
for n := range m.Packages {
|
||||||
if strings.EqualFold(n, name) {
|
if strings.EqualFold(n, name) {
|
||||||
m.Packages[n] = version
|
m.Packages[n] = Package{
|
||||||
|
Repo: repo,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
return save(m)
|
return save(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.Packages[name] = version
|
m.Packages[name] = Package{
|
||||||
|
Repo: repo,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
return save(m)
|
return save(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Read() (Meta, error) {
|
func Read() (Meta, error) {
|
||||||
m := Meta{
|
m := Meta{
|
||||||
Packages: make(map[string]string),
|
Packages: make(map[string]Package),
|
||||||
}
|
}
|
||||||
fp, err := metaPath()
|
fp, err := metaPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -68,7 +81,11 @@ func Remove(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func metaPath() (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 {
|
func save(m Meta) error {
|
||||||
|
@ -80,6 +97,39 @@ func save(m Meta) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create meta file: %w", err)
|
return fmt.Errorf("could not create meta file: %w", err)
|
||||||
}
|
}
|
||||||
defer fi.Close()
|
if err := json.NewEncoder(fi).Encode(m); err != nil {
|
||||||
return json.NewEncoder(fi).Encode(m)
|
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()
|
||||||
|
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