feat: add sync

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main
jolheiser 2023-01-14 21:31:58 -06:00
parent a9d92b3074
commit 11f2017bff
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
7 changed files with 193 additions and 52 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}