Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d78064179f | |||
| 2157d9ecce | |||
| b686f810fb | |||
| c856bf0686 | |||
| c650c1dae0 | |||
| b3b6612ef2 | |||
| baf4cca4fb | |||
| e604f61151 | |||
| 8e74e58cad | |||
| be48f26e75 | |||
| b6265f4b1d | |||
| c0e535c630 | |||
| 2b6815e287 | |||
| a42c9b27e7 | |||
| e2c8335381 | |||
| b56641c659 | |||
| 61ba975e21 | |||
| 75a60070ba | |||
| a02a009b63 | |||
| 74adb915fc | |||
| bdca0a5ffc | |||
| 674cfe6b0d | |||
| bb50b55ac5 | |||
| 29016fcdb7 | |||
| c09574e659 | |||
| 1f39f5edf1 | |||
| 8661721ccc | |||
| 93d5ad9a53 | |||
| 77c3ea7d56 | |||
| fa76d95c04 | |||
| 6012f0f505 | |||
| 35046566a1 | |||
| 46f79e4d26 | |||
| 7fa6dcf183 | |||
| a5c2ac60d9 | |||
| 7d6d22cf69 | |||
| 28809828c2 | |||
| 3194648096 | |||
|
|
86706e88ad | ||
| 3ac715d447 | |||
| 3cf1e7f513 | |||
| c18d1440c3 | |||
| 87c2a8bf0d | |||
| ef1ea04760 | |||
| 6c9f841f11 | |||
| bfb4431763 | |||
| b5bc721840 | |||
| 337e25c34f | |||
| 6238542507 | |||
|
|
98ffff404a | ||
| dbe4cf98fa | |||
| 38edfe9283 | |||
| 332e36fb3d | |||
|
|
c3aba08681 | ||
|
|
57a75aa54e | ||
|
|
438eef3213 |
@@ -21,6 +21,7 @@ archives:
|
|||||||
arm64: aarch64
|
arm64: aarch64
|
||||||
nfpms:
|
nfpms:
|
||||||
- id: lure
|
- id: lure
|
||||||
|
package_name: linux-user-repository
|
||||||
file_name_template: '{{.PackageName}}-{{.Version}}-{{.Os}}-{{.Arch}}'
|
file_name_template: '{{.PackageName}}-{{.Version}}-{{.Os}}-{{.Arch}}'
|
||||||
description: "Linux User REpository"
|
description: "Linux User REpository"
|
||||||
replacements:
|
replacements:
|
||||||
@@ -33,7 +34,7 @@ nfpms:
|
|||||||
formats:
|
formats:
|
||||||
- apk
|
- apk
|
||||||
- deb
|
- deb
|
||||||
- rpm
|
- rpm
|
||||||
aurs:
|
aurs:
|
||||||
- name: lure-bin
|
- name: lure-bin
|
||||||
homepage: 'https://gitea.arsenm.dev/Arsen6331/lure'
|
homepage: 'https://gitea.arsenm.dev/Arsen6331/lure'
|
||||||
|
|||||||
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
lure:
|
||||||
|
go build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f lure
|
||||||
|
|
||||||
|
install: lure
|
||||||
|
sudo install -Dm755 lure /usr/local/bin/lure
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f /usr/local/bin/lure
|
||||||
|
|
||||||
|
.PHONY: install clean uninstall
|
||||||
37
README.md
37
README.md
@@ -1,6 +1,8 @@
|
|||||||
# LURE (Linux User REpository)
|
# LURE (Linux User REpository)
|
||||||
|
|
||||||
[](https://goreportcard.com/report/go.arsenm.dev/lure)
|
[](https://goreportcard.com/report/go.arsenm.dev/lure)
|
||||||
|
[](https://ci.appveyor.com/project/moussaelianarsen/lure)
|
||||||
|
[](https://aur.archlinux.org/packages/lure-bin/)
|
||||||
|
|
||||||
LURE is intended to bring the AUR to all distros. It is currently in an ***alpha*** state and may not be stable. It can download a repository, build packages in it using a bash script similar to [PKGBUILD](https://wiki.archlinux.org/title/PKGBUILD), and then install them using your system package manager.
|
LURE is intended to bring the AUR to all distros. It is currently in an ***alpha*** state and may not be stable. It can download a repository, build packages in it using a bash script similar to [PKGBUILD](https://wiki.archlinux.org/title/PKGBUILD), and then install them using your system package manager.
|
||||||
|
|
||||||
@@ -10,9 +12,17 @@ LURE is written in pure Go and has zero dependencies after it's built. The only
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Binary releases are not provided currently. They will be provided once I have time to set up a CI pipeline.
|
Distro packages and binary archives are provided at the latest Gitea release: https://gitea.arsenm.dev/Arsen6331/lure/releases/latest
|
||||||
|
|
||||||
To install LURE, you'll need Go 1.18 or newer. Once installed, clone this repo and run `go build` inside, and then run `sudo install -Dm755 lure /usr/local/bin`.
|
LURE is also available on the AUR as [lure-bin](https://aur.archlinux.org/packages/lure-bin)
|
||||||
|
|
||||||
|
### Building from source
|
||||||
|
|
||||||
|
To build LURE from source, you'll need Go 1.18 or newer. Once Go is installed, clone this repo and run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,26 +36,9 @@ This means it's really easy to deploy LURE on any distro that it has support for
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Distro Overrides
|
## Documentation
|
||||||
|
|
||||||
Allowing LURE to run on different distros provides some challenges. For example, some distros use different names for their packages. This is solved using distro overrides. Any variable or function used in a LURE build script may be overridden based on distro and CPU architecture. The way you do this is by appending the distro and/or architecture to the end of the name. For example, [ITD](https://gitea.arsenm.dev/Arsen6331/itd) depends on the `pactl` command as well as DBus and BlueZ. These are named somewhat differently on different distros. For ITD, I use the following for the dependencies:
|
The documentation for LURE is in the [docs](docs) directory in this repo.
|
||||||
|
|
||||||
```bash
|
|
||||||
deps=('dbus' 'bluez' 'pulseaudio-utils')
|
|
||||||
deps_arch=('dbus' 'bluez' 'libpulse')
|
|
||||||
deps_opensuse=('dbus-1' 'bluez' 'pulseaudio-utils')
|
|
||||||
```
|
|
||||||
|
|
||||||
Appending `arch` and `opensuse` to the end causes LURE to use the appropriate array based on the distro. If on Arch Linux, it will use `deps_arch`. If on OpenSUSE, it will use `deps_opensuse`, and if on anything else, it will use `deps`.
|
|
||||||
|
|
||||||
Names are checked in the following order:
|
|
||||||
|
|
||||||
- $name_$architecture_$distro
|
|
||||||
- $name_$distro
|
|
||||||
- $name_$architecture
|
|
||||||
- $name
|
|
||||||
|
|
||||||
Distro detection is performed by reading the `/usr/lib/os-release` and `/etc/os-release` files.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -68,8 +61,6 @@ As mentioned before, LURE has zero dependencies after it's built. All functional
|
|||||||
|
|
||||||
## Planned Features
|
## Planned Features
|
||||||
|
|
||||||
- Source patching via .patch files
|
|
||||||
- Binary releases using goreleaser + CI
|
|
||||||
- Automated install script
|
- Automated install script
|
||||||
- Automated docker-based testing tool
|
- Automated docker-based testing tool
|
||||||
- Web interface for repos
|
- Web interface for repos
|
||||||
194
build.go
194
build.go
@@ -19,6 +19,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io"
|
"io"
|
||||||
@@ -28,18 +29,20 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AlecAivazis/survey/v2"
|
||||||
_ "github.com/goreleaser/nfpm/v2/apk"
|
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||||
_ "github.com/goreleaser/nfpm/v2/rpm"
|
_ "github.com/goreleaser/nfpm/v2/rpm"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/sys/cpu"
|
|
||||||
|
|
||||||
"github.com/goreleaser/nfpm/v2"
|
"github.com/goreleaser/nfpm/v2"
|
||||||
"github.com/goreleaser/nfpm/v2/files"
|
"github.com/goreleaser/nfpm/v2/files"
|
||||||
"go.arsenm.dev/lure/distro"
|
"go.arsenm.dev/lure/distro"
|
||||||
"go.arsenm.dev/lure/download"
|
"go.arsenm.dev/lure/download"
|
||||||
|
"go.arsenm.dev/lure/internal/cpu"
|
||||||
|
"go.arsenm.dev/lure/internal/shutils"
|
||||||
"go.arsenm.dev/lure/internal/shutils/decoder"
|
"go.arsenm.dev/lure/internal/shutils/decoder"
|
||||||
"go.arsenm.dev/lure/manager"
|
"go.arsenm.dev/lure/manager"
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
@@ -56,6 +59,7 @@ type BuildVars struct {
|
|||||||
Epoch uint `sh:"epoch"`
|
Epoch uint `sh:"epoch"`
|
||||||
Description string `sh:"desc"`
|
Description string `sh:"desc"`
|
||||||
Homepage string `sh:"homepage"`
|
Homepage string `sh:"homepage"`
|
||||||
|
Maintainer string `sh:"maintainer"`
|
||||||
Architectures []string `sh:"architectures"`
|
Architectures []string `sh:"architectures"`
|
||||||
Licenses []string `sh:"license"`
|
Licenses []string `sh:"license"`
|
||||||
Provides []string `sh:"provides"`
|
Provides []string `sh:"provides"`
|
||||||
@@ -73,7 +77,7 @@ type Scripts struct {
|
|||||||
PreInstall string `sh:"preinstall"`
|
PreInstall string `sh:"preinstall"`
|
||||||
PostInstall string `sh:"postinstall"`
|
PostInstall string `sh:"postinstall"`
|
||||||
PreRemove string `sh:"preremove"`
|
PreRemove string `sh:"preremove"`
|
||||||
PostRemove string `sh:"postinstall"`
|
PostRemove string `sh:"postremove"`
|
||||||
PreUpgrade string `sh:"preupgrade"`
|
PreUpgrade string `sh:"preupgrade"`
|
||||||
PostUpgrade string `sh:"postupgrade"`
|
PostUpgrade string `sh:"postupgrade"`
|
||||||
PreTrans string `sh:"pretrans"`
|
PreTrans string `sh:"pretrans"`
|
||||||
@@ -88,12 +92,23 @@ func buildCmd(c *cli.Context) error {
|
|||||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, pkgNames, err := buildPackage(c.Context, script, mgr)
|
pkgPaths, _, err := buildPackage(c.Context, script, mgr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error building package").Err(err).Send()
|
log.Fatal("Error building package").Err(err).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Package(s) built successfully").Any("names", pkgNames).Send()
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error getting working directory").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkgPath := range pkgPaths {
|
||||||
|
name := filepath.Base(pkgPath)
|
||||||
|
err = os.Rename(pkgPath, filepath.Join(wd, name))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error moving the package").Err(err).Send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -104,8 +119,10 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var distroChanged bool
|
||||||
if distID, ok := os.LookupEnv("LURE_DISTRO"); ok {
|
if distID, ok := os.LookupEnv("LURE_DISTRO"); ok {
|
||||||
info.ID = distID
|
info.ID = distID
|
||||||
|
distroChanged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fl, err := os.Open(script)
|
fl, err := os.Open(script)
|
||||||
@@ -137,12 +154,32 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
|
|
||||||
dec := decoder.New(info, runner)
|
dec := decoder.New(info, runner)
|
||||||
|
|
||||||
|
// If distro was changed, the list of like distros
|
||||||
|
// no longer applies, so disable its use
|
||||||
|
if distroChanged {
|
||||||
|
dec.LikeDistros = false
|
||||||
|
}
|
||||||
|
|
||||||
var vars BuildVars
|
var vars BuildVars
|
||||||
err = dec.DecodeVars(&vars)
|
err = dec.DecodeVars(&vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !archMatches(vars.Architectures) {
|
||||||
|
var buildAnyway bool
|
||||||
|
survey.AskOne(
|
||||||
|
&survey.Confirm{
|
||||||
|
Message: "Your system's CPU architecture doesn't match this package. Do you want to build anyway?",
|
||||||
|
Default: true,
|
||||||
|
},
|
||||||
|
&buildAnyway,
|
||||||
|
)
|
||||||
|
if !buildAnyway {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
||||||
|
|
||||||
baseDir := filepath.Join(cacheDir, "pkgs", vars.Name)
|
baseDir := filepath.Join(cacheDir, "pkgs", vars.Name)
|
||||||
@@ -166,7 +203,7 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
|
|
||||||
if len(vars.BuildDepends) > 0 {
|
if len(vars.BuildDepends) > 0 {
|
||||||
log.Info("Installing build dependencies").Send()
|
log.Info("Installing build dependencies").Send()
|
||||||
installPkgs(ctx, vars.BuildDepends, mgr)
|
installPkgs(ctx, vars.BuildDepends, mgr, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtDeps, builtNames, repoDeps []string
|
var builtDeps, builtNames, repoDeps []string
|
||||||
@@ -198,11 +235,41 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn, ok := dec.GetFunc("build")
|
fn, ok := dec.GetFunc("prepare")
|
||||||
|
if ok {
|
||||||
|
log.Info("Executing prepare()").Send()
|
||||||
|
|
||||||
|
err = fn(ctx, interp.Dir(srcdir))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn, ok = dec.GetFunc("version")
|
||||||
|
if ok {
|
||||||
|
log.Info("Executing version()").Send()
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
err = fn(
|
||||||
|
ctx,
|
||||||
|
interp.Dir(srcdir),
|
||||||
|
interp.StdIO(os.Stdin, buf, os.Stderr),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.Version = strings.TrimSpace(buf.String())
|
||||||
|
|
||||||
|
log.Info("Updating version").Str("new", vars.Version).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn, ok = dec.GetFunc("build")
|
||||||
if ok {
|
if ok {
|
||||||
log.Info("Executing build()").Send()
|
log.Info("Executing build()").Send()
|
||||||
|
|
||||||
err = fn(ctx, srcdir)
|
err = fn(ctx, interp.Dir(srcdir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -212,10 +279,12 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
if ok {
|
if ok {
|
||||||
log.Info("Executing package()").Send()
|
log.Info("Executing package()").Send()
|
||||||
|
|
||||||
err = fn(ctx, srcdir)
|
err = fn(ctx, interp.Dir(srcdir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.Fatal("The package() function is required").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
uniq(
|
uniq(
|
||||||
@@ -230,14 +299,21 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Version: vars.Version,
|
Version: vars.Version,
|
||||||
Release: strconv.Itoa(vars.Release),
|
Release: strconv.Itoa(vars.Release),
|
||||||
Epoch: strconv.FormatUint(uint64(vars.Epoch), 10),
|
|
||||||
Homepage: vars.Homepage,
|
Homepage: vars.Homepage,
|
||||||
License: strings.Join(vars.Licenses, ", "),
|
License: strings.Join(vars.Licenses, ", "),
|
||||||
|
Maintainer: vars.Maintainer,
|
||||||
Overridables: nfpm.Overridables{
|
Overridables: nfpm.Overridables{
|
||||||
Depends: append(repoDeps, builtNames...),
|
Conflicts: vars.Conflicts,
|
||||||
|
Replaces: vars.Replaces,
|
||||||
|
Provides: vars.Provides,
|
||||||
|
Depends: append(repoDeps, builtNames...),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if vars.Epoch != 0 {
|
||||||
|
pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10)
|
||||||
|
}
|
||||||
|
|
||||||
setScripts(&vars, pkgInfo, filepath.Dir(script))
|
setScripts(&vars, pkgInfo, filepath.Dir(script))
|
||||||
|
|
||||||
if slices.Contains(vars.Architectures, "all") {
|
if slices.Contains(vars.Architectures, "all") {
|
||||||
@@ -245,7 +321,7 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pkgInfo.Arch == "arm" {
|
if pkgInfo.Arch == "arm" {
|
||||||
pkgInfo.Arch = checkARMVariant()
|
pkgInfo.Arch = cpu.ARMVariant()
|
||||||
}
|
}
|
||||||
|
|
||||||
contents := []*files.Content{}
|
contents := []*files.Content{}
|
||||||
@@ -342,6 +418,29 @@ func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]st
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(vars.BuildDepends) > 0 {
|
||||||
|
var removeBuildDeps bool
|
||||||
|
err = survey.AskOne(&survey.Confirm{
|
||||||
|
Message: "Would you like to remove build dependencies?",
|
||||||
|
}, &removeBuildDeps)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if removeBuildDeps {
|
||||||
|
err = mgr.Remove(
|
||||||
|
&manager.Opts{
|
||||||
|
AsRoot: true,
|
||||||
|
NoConfirm: true,
|
||||||
|
},
|
||||||
|
vars.BuildDepends...,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uniq(&pkgPaths, &pkgNames)
|
uniq(&pkgPaths, &pkgNames)
|
||||||
|
|
||||||
return pkgPaths, pkgNames, nil
|
return pkgPaths, pkgNames, nil
|
||||||
@@ -403,24 +502,6 @@ func setDirVars(ctx context.Context, runner *interp.Runner, srcdir, pkgdir strin
|
|||||||
return runner.Run(ctx, fl)
|
return runner.Run(ctx, fl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkARMVariant checks which variant of ARM lure is running
|
|
||||||
// on, by using the same detection method as Go itself
|
|
||||||
func checkARMVariant() string {
|
|
||||||
armEnv := os.Getenv("LURE_ARM_VARIANT")
|
|
||||||
// ensure value has "arm" prefix, such as arm5 or arm6
|
|
||||||
if strings.HasPrefix(armEnv, "arm") {
|
|
||||||
return armEnv
|
|
||||||
}
|
|
||||||
|
|
||||||
if cpu.ARM.HasVFPv3 {
|
|
||||||
return "arm7"
|
|
||||||
} else if cpu.ARM.HasVFP {
|
|
||||||
return "arm6"
|
|
||||||
} else {
|
|
||||||
return "arm5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setScripts(vars *BuildVars, info *nfpm.Info, scriptDir string) {
|
func setScripts(vars *BuildVars, info *nfpm.Info, scriptDir string) {
|
||||||
if vars.Scripts.PreInstall != "" {
|
if vars.Scripts.PreInstall != "" {
|
||||||
info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
|
info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
|
||||||
@@ -457,6 +538,61 @@ func setScripts(vars *BuildVars, info *nfpm.Info, scriptDir string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBuildVars only gets the build variables, while disabling exec, stat, open, and readdir
|
||||||
|
func getBuildVars(ctx context.Context, script string, info *distro.OSRelease) (*BuildVars, error) {
|
||||||
|
fl, err := os.Open(script)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fl.Close()
|
||||||
|
|
||||||
|
runner, err := interp.New(
|
||||||
|
interp.Env(expand.ListEnviron()),
|
||||||
|
interp.ExecHandler(shutils.NopExec),
|
||||||
|
interp.StatHandler(shutils.NopStat),
|
||||||
|
interp.OpenHandler(shutils.NopOpen),
|
||||||
|
interp.ReadDirHandler(shutils.NopReadDir),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = runner.Run(ctx, file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dec := decoder.New(info, runner)
|
||||||
|
|
||||||
|
var vars BuildVars
|
||||||
|
err = dec.DecodeVars(&vars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &vars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func archMatches(architectures []string) bool {
|
||||||
|
arch := runtime.GOARCH
|
||||||
|
|
||||||
|
if arch == "arm" {
|
||||||
|
arch = cpu.ARMVariant()
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(architectures, "arm") {
|
||||||
|
architectures = append(architectures, cpu.ARMVariant())
|
||||||
|
}
|
||||||
|
|
||||||
|
return slices.Contains(architectures, arch)
|
||||||
|
}
|
||||||
|
|
||||||
func uniq(ss ...*[]string) {
|
func uniq(ss ...*[]string) {
|
||||||
for _, s := range ss {
|
for _, s := range ss {
|
||||||
slices.Sort(*s)
|
slices.Sort(*s)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"go.arsenm.dev/lure/internal/shutils"
|
"go.arsenm.dev/lure/internal/shutils"
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
@@ -35,6 +36,7 @@ type OSRelease struct {
|
|||||||
Name string
|
Name string
|
||||||
PrettyName string
|
PrettyName string
|
||||||
ID string
|
ID string
|
||||||
|
Like []string
|
||||||
BuildID string
|
BuildID string
|
||||||
ANSIColor string
|
ANSIColor string
|
||||||
HomeURL string
|
HomeURL string
|
||||||
@@ -80,7 +82,7 @@ func ParseOSRelease(ctx context.Context) (*OSRelease, error) {
|
|||||||
return nil, ErrParse
|
return nil, ErrParse
|
||||||
}
|
}
|
||||||
|
|
||||||
return &OSRelease{
|
out := &OSRelease{
|
||||||
Name: runner.Vars["NAME"].Str,
|
Name: runner.Vars["NAME"].Str,
|
||||||
PrettyName: runner.Vars["PRETTY_NAME"].Str,
|
PrettyName: runner.Vars["PRETTY_NAME"].Str,
|
||||||
ID: runner.Vars["ID"].Str,
|
ID: runner.Vars["ID"].Str,
|
||||||
@@ -91,5 +93,11 @@ func ParseOSRelease(ctx context.Context) (*OSRelease, error) {
|
|||||||
SupportURL: runner.Vars["SUPPORT_URL"].Str,
|
SupportURL: runner.Vars["SUPPORT_URL"].Str,
|
||||||
BugReportURL: runner.Vars["BUG_REPORT_URL"].Str,
|
BugReportURL: runner.Vars["BUG_REPORT_URL"].Str,
|
||||||
Logo: runner.Vars["LOGO"].Str,
|
Logo: runner.Vars["LOGO"].Str,
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
if runner.Vars["ID_LIKE"].IsSet() {
|
||||||
|
out.Like = strings.Split(runner.Vars["ID_LIKE"].Str, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|||||||
6
docs/README.md
Normal file
6
docs/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# LURE Docs
|
||||||
|
|
||||||
|
- [Build Scripts](build-scripts.md)
|
||||||
|
- [Usage](usage.md)
|
||||||
|
- [Configuration](configuration.md)
|
||||||
|
- [Adding Packages to LURE's repo](adding-packages.md)
|
||||||
23
docs/adding-packages.md
Normal file
23
docs/adding-packages.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Adding Packages to LURE's repo
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- `go` (1.18+)
|
||||||
|
- `git`
|
||||||
|
- `lure-analyzer`
|
||||||
|
- `go install go.arsenm.dev/lure-repo-bot/cmd/lure-analyzer@latest`
|
||||||
|
- `shfmt`
|
||||||
|
- May be available in distro repos
|
||||||
|
- `go install mvdan.cc/sh/v3/cmd/shfmt@latest`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to submit a package
|
||||||
|
|
||||||
|
LURE's repo is hosted on Github at https://github.com/Arsen6331/lure-repo. In it, there are multiple directories each containing a `lure.sh` file. In order to add a package to LURE's repo, simply create a PR with a [build script](./build-scripts.md) and place it in a directory with the same name as the package.
|
||||||
|
|
||||||
|
Upon submitting the PR, [lure-repo-bot](https://github.com/Arsen6331/lure-repo-bot) will pull your PR and analyze it, providing suggestions for fixes as review comments. If there are no problems, the bot will approve your changes. If there are issues, re-request review from the bot after you've finished applying the fixes and it will automatically review the PR again.
|
||||||
|
|
||||||
|
All scripts submitted to the LURE repo should be formatted with `shfmt`. If they are not properly formatted, Github Actions will add suggestions in the "Files Changed" tab of the PR.
|
||||||
|
|
||||||
|
Once your PR is merged, LURE will pull the changed repo and your package will be available for people to install.
|
||||||
270
docs/build-scripts.md
Normal file
270
docs/build-scripts.md
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
# LURE Build Scripts
|
||||||
|
|
||||||
|
LURE uses build scripts similar to the AUR's PKGBUILDs. This is the documentation for those scripts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Distro Overrides](#distro-overrides)
|
||||||
|
- [Variables](#variables)
|
||||||
|
- [name](#name)
|
||||||
|
- [version](#version)
|
||||||
|
- [release](#release)
|
||||||
|
- [epoch](#epoch)
|
||||||
|
- [desc](#desc)
|
||||||
|
- [homepage](#homepage)
|
||||||
|
- [maintainer](#maintainer)
|
||||||
|
- [architectures](#architectures)
|
||||||
|
- [licenses](#licenses)
|
||||||
|
- [provides](#provides)
|
||||||
|
- [conflicts](#conflicts)
|
||||||
|
- [deps](#deps)
|
||||||
|
- [build_deps](#build_deps)
|
||||||
|
- [replaces](#replaces)
|
||||||
|
- [sources](#sources)
|
||||||
|
- [checksums](#checksums)
|
||||||
|
- [backup](#backup)
|
||||||
|
- [scripts](#scripts)
|
||||||
|
- [Functions](#functions)
|
||||||
|
- [prepare](#prepare)
|
||||||
|
- [version](#version-1)
|
||||||
|
- [build](#build)
|
||||||
|
- [package](#package)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Distro Overrides
|
||||||
|
|
||||||
|
Allowing LURE to run on different distros provides some challenges. For example, some distros use different names for their packages. This is solved using distro overrides. Any variable or function used in a LURE build script may be overridden based on distro and CPU architecture. The way you do this is by appending the distro and/or architecture to the end of the name. For example, [ITD](https://gitea.arsenm.dev/Arsen6331/itd) depends on the `pactl` command as well as DBus and BlueZ. These are named somewhat differently on different distros. For ITD, I use the following for the dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deps=('dbus' 'bluez' 'pulseaudio-utils')
|
||||||
|
deps_arch=('dbus' 'bluez' 'libpulse')
|
||||||
|
deps_opensuse=('dbus-1' 'bluez' 'pulseaudio-utils')
|
||||||
|
```
|
||||||
|
|
||||||
|
Appending `arch` and `opensuse` to the end causes LURE to use the appropriate array based on the distro. If on Arch Linux, it will use `deps_arch`. If on OpenSUSE, it will use `deps_opensuse`, and if on anything else, it will use `deps`.
|
||||||
|
|
||||||
|
Names are checked in the following order:
|
||||||
|
|
||||||
|
- $name_$architecture_$distro
|
||||||
|
- $name_$distro
|
||||||
|
- $name_$architecture
|
||||||
|
- $name
|
||||||
|
|
||||||
|
Distro detection is performed by reading the `/usr/lib/os-release` and `/etc/os-release` files.
|
||||||
|
|
||||||
|
### Like distros
|
||||||
|
|
||||||
|
Inside the `os-release` file, there is a list of "like" distros. LURE takes this into account. For example, if a script contains `deps_debian` but not `deps_ubuntu`, Ubuntu builds will use `deps_debian` because Ubuntu is based on debian.
|
||||||
|
|
||||||
|
Most specificity is preferred, so if both `deps_debian` and `deps_ubuntu` is provided, Ubuntu and all Ubuntu-based distros will use `deps_ubuntu` while Debian and all Debian-based distros
|
||||||
|
that are not Ubuntu-based will use `deps_debian`.
|
||||||
|
|
||||||
|
Like distros are disabled when using the `LURE_DISTRO` environment variable.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
Any variables marked with `(*)` are required
|
||||||
|
|
||||||
|
### name (*)
|
||||||
|
|
||||||
|
The `name` variable contains the name of the package described by the script.
|
||||||
|
|
||||||
|
### version (*)
|
||||||
|
|
||||||
|
The `version` variable contains the version of the package. This should be the same as the version used by the author upstream.
|
||||||
|
|
||||||
|
Versions are compared using the [rpmvercmp](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison) algorithm.
|
||||||
|
|
||||||
|
### release (*)
|
||||||
|
|
||||||
|
The `release` number is meant to differentiate between different builds of the same package version, such as if the script is changed but the version stays the same. The `release` must be an integer.
|
||||||
|
|
||||||
|
### epoch
|
||||||
|
|
||||||
|
The `epoch` number forces the package to be considered newer than versions with a lower epoch. It is meant to be used if the versioning scheme can't be used to determine which package is newer. Its use is discouraged and it should only be used if necessary. The `epoch` must be a positive integer.
|
||||||
|
|
||||||
|
### desc
|
||||||
|
|
||||||
|
The `desc` field contains the description for the package. It should not contain any newlines.
|
||||||
|
|
||||||
|
### homepage
|
||||||
|
|
||||||
|
The `homepage` field contains the URL to the website of the project packaged by this script.
|
||||||
|
|
||||||
|
### maintainer
|
||||||
|
|
||||||
|
The `maintainer` field contains the name and email address of the person maintaining the package. Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Arsen Musayelyan <arsen@arsenm.dev>
|
||||||
|
```
|
||||||
|
|
||||||
|
While LURE does not require this field to be set, Debian has deprecated unset maintainer fields, and may disallow their use in `.deb` packages in the future.
|
||||||
|
|
||||||
|
### architectures
|
||||||
|
|
||||||
|
The `architectures` array contains all the architectures that this package supports. These match Go's GOARCH list, except for a few differences.
|
||||||
|
|
||||||
|
The `all` architecture will be translated to the proper term for the packaging format. For example, it will be changed to `noarch` if building a `.rpm`, or `any` if building an Arch package.
|
||||||
|
|
||||||
|
Since multiple variations of the `arm` architecture exist, the following values should be used:
|
||||||
|
|
||||||
|
`arm5`: armv5
|
||||||
|
`arm6`: armv6
|
||||||
|
`arm7`: armv7
|
||||||
|
|
||||||
|
LURE will attempt to detect which variant your system is using by checking for the existence of various CPU features. If this yields the wrong result or if you simply want to build for a different variant, the `LURE_ARM_VARIANT` variable should be set to the ARM variant you want. Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
LURE_ARM_VARIANT=arm5 lure install ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### licenses
|
||||||
|
|
||||||
|
The `licenses` array contains the licenses used by this package. In order to standardize license names, values should be [SPDX Identifiers](https://spdx.org/licenses/) such as `Apache-2.0`, `MIT`, and `GPL-3.0-only`. If the project uses a license that is not standardized in SPDX, use the value `Custom`. If the project has multiple nonstandard licenses, include `Custom` as many times as there are nonstandard licenses.
|
||||||
|
|
||||||
|
### provides
|
||||||
|
|
||||||
|
The `provides` array specifies what features the package provides. For example, if two packages build `ffmpeg` with different build flags, they should both have `ffmpeg` in the `provides` array.
|
||||||
|
|
||||||
|
### conflicts
|
||||||
|
|
||||||
|
The `conflicts` array contains names of packages that conflict with the one built by this script. If two different packages contain the executable for `ffmpeg`, they cannot be installed at the same time, so they conflict. The `provides` array will also be checked, so this array generally contains the same values as `provides`.
|
||||||
|
|
||||||
|
### deps
|
||||||
|
|
||||||
|
The `deps` array contains the dependencies for the package. LURE repos will be checked first, and if the packages exist there, they will be built and installed. Otherwise, they will be installed from the system repos by your package manager.
|
||||||
|
|
||||||
|
### build_deps
|
||||||
|
|
||||||
|
The `build_deps` array contains the dependencies that are required to build the package. They will be installed before the build starts. Similarly to the `deps` array, LURE repos will be checked first.
|
||||||
|
|
||||||
|
### replaces
|
||||||
|
|
||||||
|
The `replaces` array contains the packages that are replaced by this package. Generally, if package managers find a package with a `replaces` field set, they will remove the listed package(s) and install that one instead. This is only useful if the packages are being stored in a repo for your package manager.
|
||||||
|
|
||||||
|
### sources
|
||||||
|
|
||||||
|
The `sources` array contains URLs which are downloaded into `$srcdir` before the build starts.
|
||||||
|
|
||||||
|
If the URL provided is an archive or compressed file, it will be extracted. To disable this, add the `~archive=false` query parameter. Example:
|
||||||
|
|
||||||
|
Extracted:
|
||||||
|
```text
|
||||||
|
https://example.com/archive.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Not extracted:
|
||||||
|
```text
|
||||||
|
https://example.com/archive.tar.gz?~archive=false
|
||||||
|
```
|
||||||
|
|
||||||
|
If the URL scheme starts with `git+`, the source will be downloaded as a git repo. The git download mode supports multiple parameters:
|
||||||
|
|
||||||
|
- `~tag`: Specify which tag of the repo to check out.
|
||||||
|
- `~branch`: Specify which branch of the repo to check out.
|
||||||
|
- `~commit`: Specify which commit of the repo to check out.
|
||||||
|
- `~depth`: Specify what depth should be used when cloning the repo. Must be an integer.
|
||||||
|
- `~name`: Specify the name of the directory into which the git repo should be cloned.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```text
|
||||||
|
git+https://gitea.arsenm.dev/Arsen6331/itd?~branch=resource-loading&~depth=1
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
git+https://gitea.arsenm.dev/Arsen6331/lure?~tag=v0.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### checksums
|
||||||
|
|
||||||
|
The `checksums` array must be the same length as the `sources` array. It contains sha256 checksums for the source files. The files are checked against the checksums and the build fails if they don't match.
|
||||||
|
|
||||||
|
To skip the check for a particular source, set the corresponding checksum to `SKIP`.
|
||||||
|
|
||||||
|
### backup
|
||||||
|
|
||||||
|
The `backup` array contains files that should be backed up when upgrading and removing. The exact behavior of this depends on your package manager. All files within this array must be full destination paths. For example, if there's a config called `config` in `/etc` that you want to back up, you'd set it like so:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
backup=('/etc/config')
|
||||||
|
```
|
||||||
|
|
||||||
|
### scripts
|
||||||
|
|
||||||
|
The `scripts` variable contains a Bash associative array that specifies the location of various scripts relative to the build script. Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scripts=(
|
||||||
|
['preinstall']='preinstall.sh'
|
||||||
|
['postinstall']='postinstall.sh'
|
||||||
|
['preremove']='preremove.sh'
|
||||||
|
['postremove']='postremove.sh'
|
||||||
|
['preupgrade']='preupgrade.sh'
|
||||||
|
['postupgrade']='postupgrade.sh'
|
||||||
|
['pretrans']='pretrans.sh'
|
||||||
|
['posttrans']='posttrans.sh'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The quotes are required due to limitations with the bash parser used.
|
||||||
|
|
||||||
|
The `preupgrade` and `postupgrade` scripts are only available in `.apk` and Arch Linux packages.
|
||||||
|
|
||||||
|
The `pretrans` and `posttrans` scripts are only available in `.rpm` packages.
|
||||||
|
|
||||||
|
The rest of the scripts are available in all packages.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
Any variables marked with `(*)` are required
|
||||||
|
|
||||||
|
All functions start in the `$srcdir` directory
|
||||||
|
|
||||||
|
### prepare
|
||||||
|
|
||||||
|
The `prepare()` function runs first. It is meant to prepare the sources for building and packaging. This is the function in which patches should be applied, for example, by the `patch` command, and where tools like `go generate` should be executed.
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
The `version()` function updates the `version` variable. This allows for automatically deriving the version from sources. This is most useful for git packages, which usually don't need to be changed, so their `version` variable stays the same.
|
||||||
|
|
||||||
|
An example of using this for git:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
version() {
|
||||||
|
cd "$srcdir/itd"
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The AUR equivalent is the [`pkgver()` function](https://wiki.archlinux.org/title/VCS_package_guidelines#The_pkgver()_function)
|
||||||
|
|
||||||
|
### build
|
||||||
|
|
||||||
|
The `build()` function is where the package is actually built. Use the same commands that would be used to manually compile the software. Often, this function is just one line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
build() {
|
||||||
|
make
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### package (*)
|
||||||
|
|
||||||
|
The `package()` function is where the built files are placed into the directory that will be used by LURE to build the package.
|
||||||
|
|
||||||
|
Any files that should be installed on the filesystem should go in the `$pkgdir` directory in this function. For example, if you have a binary called `bin` that should be placed in `/usr/bin` and a config file called `bin.cfg` that should be placed in `/etc`, the `package()` function might look like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
package() {
|
||||||
|
install -Dm755 bin ${pkgdir}/usr/bin/bin
|
||||||
|
install -Dm644 bin.cfg ${pkgdir}/etc/bin.cfg
|
||||||
|
}
|
||||||
|
```
|
||||||
44
docs/configuration.md
Normal file
44
docs/configuration.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
This page describes the configuration of LURE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Config file](#config-file)
|
||||||
|
- [rootCmd](#rootcmd)
|
||||||
|
- [repo](#repo)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File locations
|
||||||
|
|
||||||
|
| Path | Description
|
||||||
|
| --: | :--
|
||||||
|
| ~/.config/lure/lure.toml | Config file
|
||||||
|
| ~/.cache/lure/pkgs | here the packages are built and stored
|
||||||
|
| ~/.cache/lure/repo | here are the git repos with all the `lure.sh` files
|
||||||
|
| | Example: `~/.cache/lure/repo/default/itd-bin/lure.sh`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Config file
|
||||||
|
|
||||||
|
### rootCmd
|
||||||
|
|
||||||
|
The `rootCmd` field in the config specifies which command should be used for privilege elevation. The default value is `sudo`.
|
||||||
|
|
||||||
|
### repo
|
||||||
|
|
||||||
|
The `repo` array in the config specifies which repos are added to LURE. Each repo must have a name and URL. A repo looks like this in the config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[repo]]
|
||||||
|
name = 'default'
|
||||||
|
url = 'https://github.com/Arsen6331/lure-repo.git'
|
||||||
|
```
|
||||||
|
|
||||||
|
The `default` repo is added by default. Any amount of repos may be added.
|
||||||
|
|
||||||
|
---
|
||||||
160
docs/usage.md
Normal file
160
docs/usage.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# Usage
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Commands](#commands)
|
||||||
|
- [install](#install)
|
||||||
|
- [remove](#remove)
|
||||||
|
- [upgrade](#upgrade)
|
||||||
|
- [info](#info)
|
||||||
|
- [list](#list)
|
||||||
|
- [build](#build)
|
||||||
|
- [addrepo](#addrepo)
|
||||||
|
- [removerepo](#removerepo)
|
||||||
|
- [refresh](#refresh)
|
||||||
|
- [Environment Variables](#environment-variables)
|
||||||
|
- [LURE_DISTRO](#lure_distro)
|
||||||
|
- [LURE_PKG_FORMAT](#lure_pkg_format)
|
||||||
|
- [LURE_ARM_VARIANT](#lure_arm_variant)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### install
|
||||||
|
|
||||||
|
The install command installs a command from the LURE repos. Any packages that aren't found in LURE's repos get forwarded to the system package manager for installation.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure in itd-bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### remove
|
||||||
|
|
||||||
|
The remove command is for convenience. All it does is forwards the remove command to the system package manager.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure rm firefox
|
||||||
|
```
|
||||||
|
|
||||||
|
### upgrade
|
||||||
|
|
||||||
|
The upgrade command looks through the packages installed on your system and sees if any of them match LURE repo packages. If they do, their versions are compared using the `rpmvercmp` algorithm. If LURE repos contain a newer version, the package is upgraded.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure up
|
||||||
|
```
|
||||||
|
|
||||||
|
### info
|
||||||
|
|
||||||
|
The info command displays information about a package in LURE's repos.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure info itd-bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### list
|
||||||
|
|
||||||
|
The list command lists all LURE repo packages as well as their versions
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure ls
|
||||||
|
```
|
||||||
|
|
||||||
|
### build
|
||||||
|
|
||||||
|
The build command builds a package using a `lure.sh` build script in the current directory. The path to the script can be changed with the `-s` flag.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure build
|
||||||
|
```
|
||||||
|
|
||||||
|
### addrepo
|
||||||
|
|
||||||
|
The addrepo command adds a repository to LURE if it doesn't already exist. The `-n` flag sets the name of the repository, and the `-u` flag is the URL to the repository. Both are required.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure ar -n default -u https://github.com/Arsen6331/lure-repo
|
||||||
|
```
|
||||||
|
|
||||||
|
### removerepo
|
||||||
|
|
||||||
|
The removerepo command removes a repository from LURE and deletes its contents if it exists. The `-n` flag specifies the name of the repo to be deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure rr -n default
|
||||||
|
```
|
||||||
|
|
||||||
|
### refresh
|
||||||
|
|
||||||
|
The refresh command pulls all changes from all LURE repos that have changed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
lure ref
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### LURE_DISTRO
|
||||||
|
|
||||||
|
The `LURE_DISTRO` environment variable should be set to the distro for which the package should be built. It tells LURE which overrides to use. Values should be the same as the `ID` field in `/etc/os-release` or `/usr/lib/os-release`. Possible values include:
|
||||||
|
|
||||||
|
- `arch`
|
||||||
|
- `alpine`
|
||||||
|
- `opensuse`
|
||||||
|
- `debian`
|
||||||
|
|
||||||
|
### LURE_PKG_FORMAT
|
||||||
|
|
||||||
|
The `LURE_PKG_FORMAT` environment variable should be set to the packaging format that should be used. Valid values are:
|
||||||
|
|
||||||
|
- `archlinux`
|
||||||
|
- `apk`
|
||||||
|
- `rpm`
|
||||||
|
- `deb`
|
||||||
|
|
||||||
|
### LURE_ARM_VARIANT
|
||||||
|
|
||||||
|
The `LURE_ARM_VARIANT` environment variable dictates which ARM variant to build for, if LURE is running on an ARM system. Possible values include:
|
||||||
|
|
||||||
|
- `arm5`
|
||||||
|
- `arm6`
|
||||||
|
- `arm7`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cross-packaging for other Distributions
|
||||||
|
|
||||||
|
You can create packages for different distributions
|
||||||
|
setting the environment variables `LURE_DISTRO` and `LURE_PKG_FORMAT` as mentioned above.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```
|
||||||
|
LURE_DISTRO=arch LURE_PKG_FORMAT=archlinux lure build
|
||||||
|
LURE_DISTRO=alpine LURE_PKG_FORMAT=apk lure build
|
||||||
|
LURE_DISTRO=opensuse LURE_PKG_FORMAT=rpm lure build
|
||||||
|
LURE_DISTRO=debian LURE_PKG_FORMAT=deb lure build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -67,6 +68,22 @@ func Get(ctx context.Context, opts GetOptions) error {
|
|||||||
}
|
}
|
||||||
query := src.Query()
|
query := src.Query()
|
||||||
|
|
||||||
|
if strings.HasPrefix(src.Scheme, "git+") {
|
||||||
|
err = getGit(ctx, src, query, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = getFile(ctx, src, query, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGit(ctx context.Context, src *url.URL, query url.Values, opts GetOptions) (err error) {
|
||||||
tag := query.Get("~tag")
|
tag := query.Get("~tag")
|
||||||
query.Del("~tag")
|
query.Del("~tag")
|
||||||
|
|
||||||
@@ -79,6 +96,9 @@ func Get(ctx context.Context, opts GetOptions) error {
|
|||||||
depthStr := query.Get("~depth")
|
depthStr := query.Get("~depth")
|
||||||
query.Del("~depth")
|
query.Del("~depth")
|
||||||
|
|
||||||
|
name := query.Get("~name")
|
||||||
|
query.Del("~name")
|
||||||
|
|
||||||
var refName plumbing.ReferenceName
|
var refName plumbing.ReferenceName
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
refName = plumbing.NewTagReferenceName(tag)
|
refName = plumbing.NewTagReferenceName(tag)
|
||||||
@@ -86,169 +106,180 @@ func Get(ctx context.Context, opts GetOptions) error {
|
|||||||
refName = plumbing.NewBranchReferenceName(branch)
|
refName = plumbing.NewBranchReferenceName(branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(src.Scheme, "git+") {
|
src.Scheme = strings.TrimPrefix(src.Scheme, "git+")
|
||||||
src.Scheme = strings.TrimPrefix(src.Scheme, "git+")
|
src.RawQuery = query.Encode()
|
||||||
src.RawQuery = query.Encode()
|
|
||||||
|
|
||||||
name := path.Base(src.Path)
|
if name == "" {
|
||||||
|
name = path.Base(src.Path)
|
||||||
name = strings.TrimSuffix(name, ".git")
|
name = strings.TrimSuffix(name, ".git")
|
||||||
|
}
|
||||||
|
|
||||||
dstDir := opts.Destination
|
dstDir := opts.Destination
|
||||||
if opts.EncloseGit {
|
if opts.EncloseGit {
|
||||||
dstDir = filepath.Join(opts.Destination, name)
|
dstDir = filepath.Join(opts.Destination, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
depth := 0
|
depth := 0
|
||||||
if depthStr != "" {
|
if depthStr != "" {
|
||||||
depth, err = strconv.Atoi(depthStr)
|
depth, err = strconv.Atoi(depthStr)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cloneOpts := &git.CloneOptions{
|
|
||||||
URL: src.String(),
|
|
||||||
Progress: os.Stderr,
|
|
||||||
Depth: depth,
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, err := git.PlainCloneContext(ctx, dstDir, false, cloneOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w, err := repo.Worktree()
|
cloneOpts := &git.CloneOptions{
|
||||||
if err != nil {
|
URL: src.String(),
|
||||||
return err
|
Progress: os.Stderr,
|
||||||
}
|
Depth: depth,
|
||||||
|
}
|
||||||
|
|
||||||
checkoutOpts := &git.CheckoutOptions{}
|
repo, err := git.PlainCloneContext(ctx, dstDir, false, cloneOpts)
|
||||||
if refName != "" {
|
if err != nil {
|
||||||
checkoutOpts.Branch = refName
|
return err
|
||||||
} else if commit != "" {
|
}
|
||||||
checkoutOpts.Hash = plumbing.NewHash(commit)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Checkout(checkoutOpts)
|
w, err := repo.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
checkoutOpts := &git.CheckoutOptions{}
|
||||||
|
if refName != "" {
|
||||||
|
checkoutOpts.Branch = refName
|
||||||
|
} else if commit != "" {
|
||||||
|
checkoutOpts.Hash = plumbing.NewHash(commit)
|
||||||
} else {
|
} else {
|
||||||
name := query.Get("~name")
|
return nil
|
||||||
query.Del("~name")
|
}
|
||||||
|
|
||||||
archive := query.Get("~archive")
|
return w.Checkout(checkoutOpts)
|
||||||
query.Del("~archive")
|
}
|
||||||
|
|
||||||
src.RawQuery = query.Encode()
|
func getFile(ctx context.Context, src *url.URL, query url.Values, opts GetOptions) error {
|
||||||
|
name := query.Get("~name")
|
||||||
|
query.Del("~name")
|
||||||
|
|
||||||
if name == "" {
|
archive := query.Get("~archive")
|
||||||
name = path.Base(src.Path)
|
query.Del("~archive")
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, src.String(), nil)
|
src.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
name = path.Base(src.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, src.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := sha256.New()
|
||||||
|
|
||||||
|
format, input, err := archiver.Identify(name, res.Body)
|
||||||
|
if err == archiver.ErrNoMatch || archive == "false" {
|
||||||
|
fl, err := os.Create(filepath.Join(opts.Destination, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := http.DefaultClient.Do(req)
|
w := io.MultiWriter(hash, fl)
|
||||||
|
|
||||||
|
_, err = io.Copy(w, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := sha256.New()
|
res.Body.Close()
|
||||||
|
fl.Close()
|
||||||
|
|
||||||
format, input, err := archiver.Identify(name, res.Body)
|
if opts.SHA256Sum != nil {
|
||||||
if err == archiver.ErrNoMatch || archive == "false" {
|
sum := hash.Sum(nil)
|
||||||
fl, err := os.Create(filepath.Join(opts.Destination, name))
|
if !bytes.Equal(opts.SHA256Sum, sum) {
|
||||||
if err != nil {
|
return ErrChecksumMismatch
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
w := io.MultiWriter(hash, fl)
|
} else if err != nil {
|
||||||
|
return err
|
||||||
_, err = io.Copy(w, input)
|
} else {
|
||||||
if err != nil {
|
err = extractFile(ctx, input, hash, format, name, opts)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
res.Body.Close()
|
|
||||||
fl.Close()
|
|
||||||
|
|
||||||
if opts.SHA256Sum != nil {
|
|
||||||
sum := hash.Sum(nil)
|
|
||||||
if !bytes.Equal(opts.SHA256Sum, sum) {
|
|
||||||
return ErrChecksumMismatch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else {
|
}
|
||||||
r := io.TeeReader(input, hash)
|
}
|
||||||
fname := format.Name()
|
|
||||||
|
return nil
|
||||||
switch format := format.(type) {
|
}
|
||||||
case archiver.Extractor:
|
|
||||||
err = format.Extract(ctx, r, nil, func(ctx context.Context, f archiver.File) error {
|
func extractFile(ctx context.Context, input io.Reader, hash hash.Hash, format archiver.Format, name string, opts GetOptions) (err error) {
|
||||||
fr, err := f.Open()
|
r := io.TeeReader(input, hash)
|
||||||
if err != nil {
|
fname := format.Name()
|
||||||
return err
|
|
||||||
}
|
switch format := format.(type) {
|
||||||
defer fr.Close()
|
case archiver.Extractor:
|
||||||
|
err = format.Extract(ctx, r, nil, func(ctx context.Context, f archiver.File) error {
|
||||||
path := filepath.Join(opts.Destination, f.NameInArchive)
|
fr, err := f.Open()
|
||||||
|
if err != nil {
|
||||||
err = os.MkdirAll(filepath.Dir(path), 0o755)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
defer fr.Close()
|
||||||
}
|
|
||||||
|
path := filepath.Join(opts.Destination, f.NameInArchive)
|
||||||
if f.IsDir() {
|
|
||||||
err = os.Mkdir(path, 0o755)
|
err = os.MkdirAll(filepath.Dir(path), 0o755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
outFl, err := os.Create(path)
|
if f.IsDir() {
|
||||||
if err != nil {
|
err = os.Mkdir(path, 0o755)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
defer outFl.Close()
|
}
|
||||||
|
} else {
|
||||||
_, err = io.Copy(outFl, fr)
|
outFl, err := os.Create(path)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
return nil
|
}
|
||||||
})
|
defer outFl.Close()
|
||||||
if err != nil {
|
|
||||||
return err
|
_, err = io.Copy(outFl, fr)
|
||||||
}
|
return err
|
||||||
case archiver.Decompressor:
|
}
|
||||||
rc, err := format.OpenReader(r)
|
return nil
|
||||||
if err != nil {
|
})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
defer rc.Close()
|
}
|
||||||
|
case archiver.Decompressor:
|
||||||
path := filepath.Join(opts.Destination, name)
|
rc, err := format.OpenReader(r)
|
||||||
path = strings.TrimSuffix(path, fname)
|
if err != nil {
|
||||||
|
return err
|
||||||
outFl, err := os.Create(path)
|
}
|
||||||
if err != nil {
|
defer rc.Close()
|
||||||
return err
|
|
||||||
}
|
path := filepath.Join(opts.Destination, name)
|
||||||
|
path = strings.TrimSuffix(path, fname)
|
||||||
_, err = io.Copy(outFl, rc)
|
|
||||||
if err != nil {
|
outFl, err := os.Create(path)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.SHA256Sum != nil {
|
_, err = io.Copy(outFl, rc)
|
||||||
sum := hash.Sum(nil)
|
if err != nil {
|
||||||
if !bytes.Equal(opts.SHA256Sum, sum) {
|
return err
|
||||||
return ErrChecksumMismatch
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if opts.SHA256Sum != nil {
|
||||||
|
sum := hash.Sum(nil)
|
||||||
|
if !bytes.Equal(opts.SHA256Sum, sum) {
|
||||||
|
return ErrChecksumMismatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
go.mod
9
go.mod
@@ -1,13 +1,11 @@
|
|||||||
module go.arsenm.dev/lure
|
module go.arsenm.dev/lure
|
||||||
|
|
||||||
go 1.19
|
go 1.18
|
||||||
|
|
||||||
replace github.com/goreleaser/nfpm/v2 => github.com/Arsen6331/nfpm/v2 v2.0.0-20220922210414-eae88e8ea4b5
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.6
|
github.com/AlecAivazis/survey/v2 v2.3.6
|
||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
github.com/goreleaser/nfpm/v2 v2.18.1
|
github.com/goreleaser/nfpm/v2 v2.20.0
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/pelletier/go-toml/v2 v2.0.5
|
github.com/pelletier/go-toml/v2 v2.0.5
|
||||||
@@ -39,7 +37,6 @@ require (
|
|||||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e // indirect
|
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gookit/color v1.5.1 // indirect
|
github.com/gookit/color v1.5.1 // indirect
|
||||||
github.com/goreleaser/chglog v0.2.2 // indirect
|
github.com/goreleaser/chglog v0.2.2 // indirect
|
||||||
@@ -49,7 +46,7 @@ require (
|
|||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.5 // indirect
|
github.com/klauspost/compress v1.15.11 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
|||||||
14
go.sum
14
go.sum
@@ -2,8 +2,6 @@ github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8
|
|||||||
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
|
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
|
||||||
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
||||||
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
||||||
github.com/Arsen6331/nfpm/v2 v2.0.0-20220922210414-eae88e8ea4b5 h1:SFWe7Ho60w43hXEIxCdiAXZvUyM9GF/L90jMK42s8gU=
|
|
||||||
github.com/Arsen6331/nfpm/v2 v2.0.0-20220922210414-eae88e8ea4b5/go.mod h1:O4K1mvEORY78CSCInptGG5MWJ19yr9xFTgWWUtY1R7o=
|
|
||||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
@@ -72,11 +70,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
|
|||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e h1:6Jn9JtfCn20uycra92LxTkq5yfBKNSFlRJPBk8/Cxhg=
|
|
||||||
github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e/go.mod h1:83rLnx5vhPyN/mDzBYJWtiPf+9xnSVQynTpqZWe7OnY=
|
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
|
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
|
||||||
@@ -86,6 +81,8 @@ github.com/goreleaser/chglog v0.2.2 h1:V7nf07baXtGAgGevvqgW2MM4kZ6gOr12vKNSAU3VI
|
|||||||
github.com/goreleaser/chglog v0.2.2/go.mod h1:2s5JwtCOWjZa8AIneL+xdUl9SRuigCjRHNHsX30dupE=
|
github.com/goreleaser/chglog v0.2.2/go.mod h1:2s5JwtCOWjZa8AIneL+xdUl9SRuigCjRHNHsX30dupE=
|
||||||
github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I=
|
github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I=
|
||||||
github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU=
|
github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU=
|
||||||
|
github.com/goreleaser/nfpm/v2 v2.20.0 h1:Q/CrX54KUMluz6+M/pjTbknFd5Dao8qXi0C6ZuFCtfY=
|
||||||
|
github.com/goreleaser/nfpm/v2 v2.20.0/go.mod h1:/Fh6XfwT/T+D4qtNC2iXmHSD/1UT20JkvBXyJ6nFmOY=
|
||||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||||
@@ -103,9 +100,8 @@ github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT
|
|||||||
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
|
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
|
||||||
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||||
github.com/klauspost/compress v1.15.5 h1:qyCLMz2JCrKADihKOh9FxnW3houKeNsp2h5OEz0QSEA=
|
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||||
github.com/klauspost/compress v1.15.5/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
|
|||||||
40
info.go
40
info.go
@@ -23,12 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"go.arsenm.dev/lure/distro"
|
"go.arsenm.dev/lure/distro"
|
||||||
"go.arsenm.dev/lure/internal/shutils"
|
|
||||||
"go.arsenm.dev/lure/internal/shutils/decoder"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func infoCmd(c *cli.Context) error {
|
func infoCmd(c *cli.Context) error {
|
||||||
@@ -50,40 +45,9 @@ func infoCmd(c *cli.Context) error {
|
|||||||
// if multiple are matched, only use the first one
|
// if multiple are matched, only use the first one
|
||||||
script := found[0]
|
script := found[0]
|
||||||
|
|
||||||
fl, err := os.Open(script)
|
vars, err := getBuildVars(c.Context, script, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error opening script").Err(err).Send()
|
log.Fatal("Error getting build variables").Err(err).Send()
|
||||||
}
|
|
||||||
|
|
||||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error parsing script").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
fl.Close()
|
|
||||||
|
|
||||||
runner, err := interp.New(
|
|
||||||
interp.Env(expand.ListEnviron()),
|
|
||||||
interp.ExecHandler(shutils.NopExec),
|
|
||||||
interp.StatHandler(shutils.NopStat),
|
|
||||||
interp.OpenHandler(shutils.NopOpen),
|
|
||||||
interp.ReadDirHandler(shutils.NopReadDir),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error creating runner").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = runner.Run(c.Context, file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error running script").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
dec := decoder.New(info, runner)
|
|
||||||
|
|
||||||
var vars BuildVars
|
|
||||||
err = dec.DecodeVars(&vars)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error decoding script variables").Err(err).Send()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = yaml.NewEncoder(os.Stdout).Encode(vars)
|
err = yaml.NewEncoder(os.Stdout).Encode(vars)
|
||||||
|
|||||||
18
install.go
18
install.go
@@ -36,21 +36,23 @@ func installCmd(c *cli.Context) error {
|
|||||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
installPkgs(c.Context, args.Slice(), mgr)
|
installPkgs(c.Context, args.Slice(), mgr, true)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func installPkgs(ctx context.Context, pkgs []string, mgr manager.Manager) {
|
func installPkgs(ctx context.Context, pkgs []string, mgr manager.Manager, pull bool) {
|
||||||
err := pullRepos(ctx)
|
if pull {
|
||||||
if err != nil {
|
err := pullRepos(ctx)
|
||||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
if err != nil {
|
||||||
|
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scripts, notFound := findPkgs(pkgs)
|
scripts, notFound := findPkgs(pkgs)
|
||||||
|
|
||||||
if len(notFound) > 0 {
|
if len(notFound) > 0 {
|
||||||
err = mgr.Install(notFound...)
|
err := mgr.Install(nil, notFound...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error installing native packages").Err(err).Send()
|
log.Fatal("Error installing native packages").Err(err).Send()
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ func installScripts(ctx context.Context, mgr manager.Manager, scripts []string)
|
|||||||
log.Fatal("Error building package").Err(err).Send()
|
log.Fatal("Error building package").Err(err).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mgr.InstallLocal(builtPkgs...)
|
err = mgr.InstallLocal(nil, builtPkgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error installing package").Err(err).Send()
|
log.Fatal("Error installing package").Err(err).Send()
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,7 @@ func removeCmd(c *cli.Context) error {
|
|||||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mgr.Remove(c.Args().Slice()...)
|
err := mgr.Remove(nil, c.Args().Slice()...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error removing packages").Err(err).Send()
|
log.Fatal("Error removing packages").Err(err).Send()
|
||||||
}
|
}
|
||||||
|
|||||||
44
internal/cpu/cpu.go
Normal file
44
internal/cpu/cpu.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* LURE - Linux User REpository
|
||||||
|
* Copyright (C) 2022 Arsen Musayelyan
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ARMVariant checks which variant of ARM lure is running
|
||||||
|
// on, by using the same detection method as Go itself
|
||||||
|
func ARMVariant() string {
|
||||||
|
armEnv := os.Getenv("LURE_ARM_VARIANT")
|
||||||
|
// ensure value has "arm" prefix, such as arm5 or arm6
|
||||||
|
if strings.HasPrefix(armEnv, "arm") {
|
||||||
|
return armEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
if cpu.ARM.HasVFPv3 {
|
||||||
|
return "arm7"
|
||||||
|
} else if cpu.ARM.HasVFP {
|
||||||
|
return "arm6"
|
||||||
|
} else {
|
||||||
|
return "arm5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"go.arsenm.dev/lure/distro"
|
"go.arsenm.dev/lure/distro"
|
||||||
|
"go.arsenm.dev/lure/internal/cpu"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"mvdan.cc/sh/v3/expand"
|
"mvdan.cc/sh/v3/expand"
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
@@ -46,14 +47,17 @@ func (nfe VarNotFoundError) Error() string {
|
|||||||
|
|
||||||
// Decoder provides methods for decoding variable values
|
// Decoder provides methods for decoding variable values
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
info *distro.OSRelease
|
info *distro.OSRelease
|
||||||
runner *interp.Runner
|
runner *interp.Runner
|
||||||
|
// Enable distro overrides (true by default)
|
||||||
Overrides bool
|
Overrides bool
|
||||||
|
// Enable using like distros for overrides (true by default)
|
||||||
|
LikeDistros bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new variable decoder
|
// New creates a new variable decoder
|
||||||
func New(info *distro.OSRelease, runner *interp.Runner) *Decoder {
|
func New(info *distro.OSRelease, runner *interp.Runner) *Decoder {
|
||||||
return &Decoder{info, runner, true}
|
return &Decoder{info, runner, true, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeVar decodes a variable to val using reflection.
|
// DecodeVar decodes a variable to val using reflection.
|
||||||
@@ -138,7 +142,7 @@ func (d *Decoder) DecodeVars(val any) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScriptFunc func(ctx context.Context, sir string, args ...string) error
|
type ScriptFunc func(ctx context.Context, opts ...interp.RunnerOption) error
|
||||||
|
|
||||||
// GetFunc returns a function corresponding to a bash function
|
// GetFunc returns a function corresponding to a bash function
|
||||||
// with the given name
|
// with the given name
|
||||||
@@ -148,10 +152,11 @@ func (d *Decoder) GetFunc(name string) (ScriptFunc, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx context.Context, dir string, args ...string) error {
|
return func(ctx context.Context, opts ...interp.RunnerOption) error {
|
||||||
sub := d.runner.Subshell()
|
sub := d.runner.Subshell()
|
||||||
interp.Params(args...)(sub)
|
for _, opt := range opts {
|
||||||
interp.Dir(dir)(sub)
|
opt(sub)
|
||||||
|
}
|
||||||
return sub.Run(ctx, fn)
|
return sub.Run(ctx, fn)
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
@@ -196,10 +201,35 @@ func (d *Decoder) genPossibleNames(name string) []string {
|
|||||||
return []string{name}
|
return []string{name}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{
|
architectures := []string{runtime.GOARCH}
|
||||||
fmt.Sprintf("%s_%s_%s", name, runtime.GOARCH, d.info.ID),
|
|
||||||
fmt.Sprintf("%s_%s", name, d.info.ID),
|
if runtime.GOARCH == "arm" {
|
||||||
fmt.Sprintf("%s_%s", name, runtime.GOARCH),
|
// More specific goes first
|
||||||
name,
|
architectures[0] = cpu.ARMVariant()
|
||||||
|
architectures = append(architectures, "arm")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
distros := []string{d.info.ID}
|
||||||
|
if d.LikeDistros {
|
||||||
|
distros = append(distros, d.info.Like...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var out []string
|
||||||
|
for _, arch := range architectures {
|
||||||
|
for _, distro := range distros {
|
||||||
|
out = append(
|
||||||
|
out,
|
||||||
|
fmt.Sprintf("%s_%s_%s", name, arch, distro),
|
||||||
|
fmt.Sprintf("%s_%s", name, distro),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
out = append(out, fmt.Sprintf("%s_%s", name, arch))
|
||||||
|
}
|
||||||
|
out = append(out, name)
|
||||||
|
|
||||||
|
for index, item := range out {
|
||||||
|
out[index] = strings.ReplaceAll(item, "-", "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NopReadDir(context.Context, string) ([]os.FileInfo, error) {
|
func NopReadDir(context.Context, string) ([]os.FileInfo, error) {
|
||||||
@@ -34,7 +33,7 @@ func NopStat(context.Context, string, bool) (os.FileInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NopExec(context.Context, []string) error {
|
func NopExec(context.Context, []string) error {
|
||||||
return exec.ErrNotFound
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NopOpen(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error) {
|
func NopOpen(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error) {
|
||||||
@@ -44,11 +43,11 @@ func NopOpen(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, err
|
|||||||
type NopRWC struct{}
|
type NopRWC struct{}
|
||||||
|
|
||||||
func (NopRWC) Read([]byte) (int, error) {
|
func (NopRWC) Read([]byte) (int, error) {
|
||||||
return 0, os.ErrClosed
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func (NopRWC) Write([]byte) (int, error) {
|
func (NopRWC) Write([]byte) (int, error) {
|
||||||
return 0, os.ErrClosed
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func (NopRWC) Close() error {
|
func (NopRWC) Close() error {
|
||||||
|
|||||||
59
list.go
59
list.go
@@ -1,16 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* LURE - Linux User REpository
|
||||||
|
* Copyright (C) 2022 Arsen Musayelyan
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"go.arsenm.dev/lure/distro"
|
"go.arsenm.dev/lure/distro"
|
||||||
"go.arsenm.dev/lure/internal/shutils"
|
|
||||||
"go.arsenm.dev/lure/internal/shutils/decoder"
|
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func listCmd(c *cli.Context) error {
|
func listCmd(c *cli.Context) error {
|
||||||
@@ -25,40 +37,9 @@ func listCmd(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, script := range pkgs {
|
for _, script := range pkgs {
|
||||||
fl, err := os.Open(script)
|
vars, err := getBuildVars(c.Context, script, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error opening script").Err(err).Send()
|
log.Fatal("Error getting build variables").Err(err).Send()
|
||||||
}
|
|
||||||
|
|
||||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error parsing script").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
fl.Close()
|
|
||||||
|
|
||||||
runner, err := interp.New(
|
|
||||||
interp.Env(expand.ListEnviron()),
|
|
||||||
interp.ExecHandler(shutils.NopExec),
|
|
||||||
interp.StatHandler(shutils.NopStat),
|
|
||||||
interp.OpenHandler(shutils.NopOpen),
|
|
||||||
interp.ReadDirHandler(shutils.NopReadDir),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error creating runner").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = runner.Run(c.Context, file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error running script").Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
dec := decoder.New(info, runner)
|
|
||||||
|
|
||||||
var vars BuildVars
|
|
||||||
err = dec.DecodeVars(&vars)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error decoding script variables").Err(err).Send()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(vars.Name, vars.Version)
|
fmt.Println(vars.Name, vars.Version)
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (a *APK) SetRootCmd(s string) {
|
|||||||
a.rootCmd = s
|
a.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) Sync() error {
|
func (a *APK) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apk", "update")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apk", "update")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (a *APK) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) Install(pkgs ...string) error {
|
func (a *APK) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apk", "add")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apk", "add")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,8 +70,9 @@ func (a *APK) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) InstallLocal(pkgs ...string) error {
|
func (a *APK) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apk", "add", "--allow-untrusted")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apk", "add", "--allow-untrusted")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -79,8 +82,9 @@ func (a *APK) InstallLocal(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) Remove(pkgs ...string) error {
|
func (a *APK) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apt", "del")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apk", "del")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -90,8 +94,9 @@ func (a *APK) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) Upgrade(pkgs ...string) error {
|
func (a *APK) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apk", "upgrade")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apk", "upgrade")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -101,13 +106,21 @@ func (a *APK) Upgrade(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) UpgradeAll() error {
|
func (a *APK) UpgradeAll(opts *Opts) error {
|
||||||
return a.Upgrade()
|
opts = ensureOpts(opts)
|
||||||
|
return a.Upgrade(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APK) ListInstalled() (map[string]string, error) {
|
func (a *APK) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apk", "list", "-I")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(a.rootCmd), "apk", "list", "-I")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("apk", "list", "-I")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -141,3 +154,19 @@ func (a *APK) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *APK) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(a.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "-i")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (a *APT) SetRootCmd(s string) {
|
|||||||
a.rootCmd = s
|
a.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) Sync() error {
|
func (a *APT) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apt", "update", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apt", "update")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (a *APT) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) Install(pkgs ...string) error {
|
func (a *APT) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apt", "install", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apt", "install")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,12 +70,14 @@ func (a *APT) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) InstallLocal(pkgs ...string) error {
|
func (a *APT) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
return a.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return a.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) Remove(pkgs ...string) error {
|
func (a *APT) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apt", "remove", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apt", "remove")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -83,12 +87,14 @@ func (a *APT) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) Upgrade(pkgs ...string) error {
|
func (a *APT) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
return a.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return a.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) UpgradeAll() error {
|
func (a *APT) UpgradeAll(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "apt", "upgrade", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := a.getCmd(opts, "apt", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,9 +103,16 @@ func (a *APT) UpgradeAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APT) ListInstalled() (map[string]string, error) {
|
func (a *APT) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(a.rootCmd), "dpkg-query", "-f", "${Package}\u200b${Version}\\n", "-W")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(a.rootCmd), "dpkg-query", "-f", "${Package}\u200b${Version}\\n", "-W")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("dpkg-query", "-f", "${Package}\u200b${Version}\\n", "-W")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -127,3 +140,19 @@ func (a *APT) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *APT) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(a.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "-y")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (d *DNF) SetRootCmd(s string) {
|
|||||||
d.rootCmd = s
|
d.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) Sync() error {
|
func (d *DNF) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "dnf", "upgrade", "--assumeno")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (d *DNF) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) Install(pkgs ...string) error {
|
func (d *DNF) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "dnf", "install", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := d.getCmd(opts, "dnf", "install")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,12 +70,14 @@ func (d *DNF) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) InstallLocal(pkgs ...string) error {
|
func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
return d.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return d.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) Remove(pkgs ...string) error {
|
func (d *DNF) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "dnf", "remove", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := d.getCmd(opts, "dnf", "remove")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -83,8 +87,9 @@ func (d *DNF) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) Upgrade(pkgs ...string) error {
|
func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "dnf", "upgrade", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -94,8 +99,9 @@ func (d *DNF) Upgrade(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) UpgradeAll() error {
|
func (d *DNF) UpgradeAll(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "dnf", "upgrade", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := d.getCmd(opts, "dnf", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,9 +110,16 @@ func (d *DNF) UpgradeAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNF) ListInstalled() (map[string]string, error) {
|
func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(d.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(d.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -134,3 +147,19 @@ func (d *DNF) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "-y")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Opts struct {
|
||||||
|
AsRoot bool
|
||||||
|
NoConfirm bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultOpts = &Opts{
|
||||||
|
AsRoot: true,
|
||||||
|
NoConfirm: false,
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultRootCmd is the command used for privilege elevation by default
|
// DefaultRootCmd is the command used for privilege elevation by default
|
||||||
var DefaultRootCmd = "sudo"
|
var DefaultRootCmd = "sudo"
|
||||||
|
|
||||||
@@ -52,19 +62,19 @@ type Manager interface {
|
|||||||
// Sets the command used to elevate privileges. Defaults to DefaultRootCmd.
|
// Sets the command used to elevate privileges. Defaults to DefaultRootCmd.
|
||||||
SetRootCmd(string)
|
SetRootCmd(string)
|
||||||
// Sync fetches repositories without installing anything
|
// Sync fetches repositories without installing anything
|
||||||
Sync() error
|
Sync(*Opts) error
|
||||||
// Install installs packages
|
// Install installs packages
|
||||||
Install(...string) error
|
Install(*Opts, ...string) error
|
||||||
// Remove uninstalls packages
|
// Remove uninstalls packages
|
||||||
Remove(...string) error
|
Remove(*Opts, ...string) error
|
||||||
// Upgrade upgrades packages
|
// Upgrade upgrades packages
|
||||||
Upgrade(...string) error
|
Upgrade(*Opts, ...string) error
|
||||||
// InstallLocal installs packages from local files rather than repos
|
// InstallLocal installs packages from local files rather than repos
|
||||||
InstallLocal(...string) error
|
InstallLocal(*Opts, ...string) error
|
||||||
// UpgradeAll upgrades all packages
|
// UpgradeAll upgrades all packages
|
||||||
UpgradeAll() error
|
UpgradeAll(*Opts) error
|
||||||
// ListInstalled returns all installed packages mapped to their versions
|
// ListInstalled returns all installed packages mapped to their versions
|
||||||
ListInstalled() (map[string]string, error)
|
ListInstalled(*Opts) (map[string]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect returns the package manager detected on the system
|
// Detect returns the package manager detected on the system
|
||||||
@@ -101,3 +111,10 @@ func setCmdEnv(cmd *exec.Cmd) {
|
|||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ensureOpts(opts *Opts) *Opts {
|
||||||
|
if opts == nil {
|
||||||
|
return DefaultOpts
|
||||||
|
}
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (p *Pacman) SetRootCmd(s string) {
|
|||||||
p.rootCmd = s
|
p.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) Sync() error {
|
func (p *Pacman) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "--noconfirm", "-Sy")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := p.getCmd(opts, "pacman", "-Sy")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (p *Pacman) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) Install(pkgs ...string) error {
|
func (p *Pacman) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "--noconfirm", "-S")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := p.getCmd(opts, "pacman", "-S", "--needed")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,8 +70,9 @@ func (p *Pacman) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) InstallLocal(pkgs ...string) error {
|
func (p *Pacman) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "--noconfirm", "-U")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := p.getCmd(opts, "pacman", "-U", "--needed")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -79,8 +82,9 @@ func (p *Pacman) InstallLocal(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) Remove(pkgs ...string) error {
|
func (p *Pacman) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "--noconfirm", "-R")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := p.getCmd(opts, "pacman", "-R")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -90,12 +94,14 @@ func (p *Pacman) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) Upgrade(pkgs ...string) error {
|
func (p *Pacman) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
return p.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return p.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) UpgradeAll() error {
|
func (p *Pacman) UpgradeAll(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "--noconfirm", "-Su")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := p.getCmd(opts, "pacman", "-Su")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,9 +110,16 @@ func (p *Pacman) UpgradeAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pacman) ListInstalled() (map[string]string, error) {
|
func (p *Pacman) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(p.rootCmd), "pacman", "-Q")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(p.rootCmd), "pacman", "-Q")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("pacman", "-Q")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -134,3 +147,19 @@ func (p *Pacman) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Pacman) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(p.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "--noconfirm")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (y *YUM) SetRootCmd(s string) {
|
|||||||
y.rootCmd = s
|
y.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) Sync() error {
|
func (y *YUM) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "yum", "upgrade", "--assumeno")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := y.getCmd(opts, "yum", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (y *YUM) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) Install(pkgs ...string) error {
|
func (y *YUM) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "yum", "install", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := y.getCmd(opts, "yum", "install")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,12 +70,14 @@ func (y *YUM) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) InstallLocal(pkgs ...string) error {
|
func (y *YUM) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
return y.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return y.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) Remove(pkgs ...string) error {
|
func (y *YUM) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "yum", "remove", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := y.getCmd(opts, "yum", "remove")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -83,8 +87,9 @@ func (y *YUM) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) Upgrade(pkgs ...string) error {
|
func (y *YUM) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "yum", "upgrade", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := y.getCmd(opts, "yum", "upgrade")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -94,8 +99,9 @@ func (y *YUM) Upgrade(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) UpgradeAll() error {
|
func (y *YUM) UpgradeAll(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "yum", "upgrade", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := y.getCmd(opts, "yum", "upgrade")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,9 +110,16 @@ func (y *YUM) UpgradeAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *YUM) ListInstalled() (map[string]string, error) {
|
func (y *YUM) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(y.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(y.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -134,3 +147,19 @@ func (y *YUM) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (y *YUM) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(y.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "-y")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ func (z *Zypper) SetRootCmd(s string) {
|
|||||||
z.rootCmd = s
|
z.rootCmd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) Sync() error {
|
func (z *Zypper) Sync(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "zypper", "refresh")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := z.getCmd(opts, "zypper", "refresh")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +58,9 @@ func (z *Zypper) Sync() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) Install(pkgs ...string) error {
|
func (z *Zypper) Install(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "zypper", "install", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := z.getCmd(opts, "zypper", "install", "-y")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -68,12 +70,14 @@ func (z *Zypper) Install(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) InstallLocal(pkgs ...string) error {
|
func (z *Zypper) InstallLocal(opts *Opts, pkgs ...string) error {
|
||||||
return z.Install(pkgs...)
|
opts = ensureOpts(opts)
|
||||||
|
return z.Install(opts, pkgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) Remove(pkgs ...string) error {
|
func (z *Zypper) Remove(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "zypper", "remove", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := z.getCmd(opts, "zypper", "remove", "-y")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -83,8 +87,9 @@ func (z *Zypper) Remove(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) Upgrade(pkgs ...string) error {
|
func (z *Zypper) Upgrade(opts *Opts, pkgs ...string) error {
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "zypper", "update", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := z.getCmd(opts, "zypper", "update", "-y")
|
||||||
cmd.Args = append(cmd.Args, pkgs...)
|
cmd.Args = append(cmd.Args, pkgs...)
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
@@ -94,8 +99,9 @@ func (z *Zypper) Upgrade(pkgs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) UpgradeAll() error {
|
func (z *Zypper) UpgradeAll(opts *Opts) error {
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "zypper", "update", "-y")
|
opts = ensureOpts(opts)
|
||||||
|
cmd := z.getCmd(opts, "zypper", "update", "-y")
|
||||||
setCmdEnv(cmd)
|
setCmdEnv(cmd)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,9 +110,16 @@ func (z *Zypper) UpgradeAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zypper) ListInstalled() (map[string]string, error) {
|
func (z *Zypper) ListInstalled(opts *Opts) (map[string]string, error) {
|
||||||
|
opts = ensureOpts(opts)
|
||||||
out := map[string]string{}
|
out := map[string]string{}
|
||||||
cmd := exec.Command(getRootCmd(z.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(z.rootCmd), "rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -134,3 +147,19 @@ func (z *Zypper) ListInstalled() (map[string]string, error) {
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *Zypper) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if opts.AsRoot {
|
||||||
|
cmd = exec.Command(getRootCmd(z.rootCmd), mgrCmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(mgrCmd, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.NoConfirm {
|
||||||
|
cmd.Args = append(cmd.Args, "-y")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|||||||
48
upgrade.go
48
upgrade.go
@@ -21,16 +21,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"go.arsenm.dev/lure/distro"
|
"go.arsenm.dev/lure/distro"
|
||||||
"go.arsenm.dev/lure/internal/shutils"
|
|
||||||
"go.arsenm.dev/lure/internal/shutils/decoder"
|
|
||||||
"go.arsenm.dev/lure/manager"
|
"go.arsenm.dev/lure/manager"
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func upgradeCmd(c *cli.Context) error {
|
func upgradeCmd(c *cli.Context) error {
|
||||||
@@ -44,13 +38,18 @@ func upgradeCmd(c *cli.Context) error {
|
|||||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = pullRepos(c.Context)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error pulling repos").Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
updates, err := checkForUpdates(c.Context, mgr, info)
|
updates, err := checkForUpdates(c.Context, mgr, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error checking for updates").Err(err).Send()
|
log.Fatal("Error checking for updates").Err(err).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(updates) > 0 {
|
if len(updates) > 0 {
|
||||||
installPkgs(c.Context, updates, mgr)
|
installPkgs(c.Context, updates, mgr, false)
|
||||||
} else {
|
} else {
|
||||||
log.Info("There is nothing to do.").Send()
|
log.Info("There is nothing to do.").Send()
|
||||||
}
|
}
|
||||||
@@ -59,7 +58,7 @@ func upgradeCmd(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRelease) ([]string, error) {
|
func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRelease) ([]string, error) {
|
||||||
installed, err := mgr.ListInstalled()
|
installed, err := mgr.ListInstalled(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -74,38 +73,9 @@ func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRe
|
|||||||
// since we're not using a glob, we can assume a single item
|
// since we're not using a glob, we can assume a single item
|
||||||
script := scripts[0]
|
script := scripts[0]
|
||||||
|
|
||||||
fl, err := os.Open(script)
|
vars, err := getBuildVars(ctx, script, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Fatal("Error getting build variables").Err(err).Send()
|
||||||
}
|
|
||||||
|
|
||||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
runner, err := interp.New(
|
|
||||||
interp.Env(expand.ListEnviron()),
|
|
||||||
interp.ExecHandler(shutils.NopExec),
|
|
||||||
interp.StatHandler(shutils.NopStat),
|
|
||||||
interp.OpenHandler(shutils.NopOpen),
|
|
||||||
interp.ReadDirHandler(shutils.NopReadDir),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = runner.Run(ctx, file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dec := decoder.New(info, runner)
|
|
||||||
|
|
||||||
var vars BuildVars
|
|
||||||
err = dec.DecodeVars(&vars)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repoVer := vars.Version
|
repoVer := vars.Version
|
||||||
|
|||||||
Reference in New Issue
Block a user