Compare commits
27 Commits
v0.0.8
...
8dbdd3edc4
| Author | SHA1 | Date | |
|---|---|---|---|
| 8dbdd3edc4 | |||
| f637dd06a7 | |||
| f66132559d | |||
| c2b875db6c | |||
| 6388180768 | |||
| cf8d08574f | |||
| 0f3718648a | |||
| 81f9a4bf95 | |||
| 45522e3f3a | |||
| d59c4036ef | |||
| ffc79b8ca3 | |||
| dada9d68f2 | |||
| 10893c07c3 | |||
| e7e742d98d | |||
| f2d4d5250a | |||
| 5d566fcf15 | |||
| f44a9509a2 | |||
| 681e5fa95b | |||
| 53f3265c09 | |||
| 365634f4d9 | |||
| e8cb614b2e | |||
| 7a65835816 | |||
| 36d3be72a7 | |||
| d144a7f758 | |||
| 921555b0db | |||
| 17eb37818f | |||
| 3bc4b676d5 |
@@ -43,6 +43,8 @@ nfpms:
|
||||
- linux-user-repository
|
||||
conflicts:
|
||||
- linux-user-repository
|
||||
recommends:
|
||||
- aria2
|
||||
contents:
|
||||
- src: scripts/completion/bash
|
||||
dst: /usr/share/bash-completion/completions/lure
|
||||
@@ -64,6 +66,8 @@ aurs:
|
||||
depends:
|
||||
- sudo
|
||||
- pacman
|
||||
optdepends:
|
||||
- 'aria2: for downloading torrent sources'
|
||||
package: |-
|
||||
# binaries
|
||||
install -Dm755 ./lure "${pkgdir}/usr/bin/lure"
|
||||
|
||||
4
Makefile
4
Makefile
@@ -1,7 +1,7 @@
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
lure: internal/config/version.txt
|
||||
go build
|
||||
CGO_ENABLED=0 go build
|
||||
|
||||
clean:
|
||||
rm -f lure
|
||||
@@ -19,4 +19,4 @@ uninstall:
|
||||
internal/config/version.txt:
|
||||
go generate ./internal/config
|
||||
|
||||
.PHONY: install clean uninstall
|
||||
.PHONY: install clean uninstall installmisc
|
||||
752
build.go
752
build.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -19,719 +19,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||
_ "github.com/goreleaser/nfpm/v2/rpm"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/distro"
|
||||
"go.elara.ws/lure/internal/cliutils"
|
||||
"go.elara.ws/lure/internal/build"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/cpu"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/dl"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/osutils"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/internal/shutils"
|
||||
"go.elara.ws/lure/internal/shutils/decoder"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/manager"
|
||||
"mvdan.cc/sh/v3/expand"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
)
|
||||
|
||||
// BuildVars represents the script variables required
|
||||
// to build a package
|
||||
type BuildVars struct {
|
||||
Name string `sh:"name,required"`
|
||||
Version string `sh:"version,required"`
|
||||
Release int `sh:"release,required"`
|
||||
Epoch uint `sh:"epoch"`
|
||||
Description string `sh:"desc"`
|
||||
Homepage string `sh:"homepage"`
|
||||
Maintainer string `sh:"maintainer"`
|
||||
Architectures []string `sh:"architectures"`
|
||||
Licenses []string `sh:"license"`
|
||||
Provides []string `sh:"provides"`
|
||||
Conflicts []string `sh:"conflicts"`
|
||||
Depends []string `sh:"deps"`
|
||||
BuildDepends []string `sh:"build_deps"`
|
||||
Replaces []string `sh:"replaces"`
|
||||
Sources []string `sh:"sources"`
|
||||
Checksums []string `sh:"checksums"`
|
||||
Backup []string `sh:"backup"`
|
||||
Scripts Scripts `sh:"scripts"`
|
||||
}
|
||||
|
||||
type Scripts struct {
|
||||
PreInstall string `sh:"preinstall"`
|
||||
PostInstall string `sh:"postinstall"`
|
||||
PreRemove string `sh:"preremove"`
|
||||
PostRemove string `sh:"postremove"`
|
||||
PreUpgrade string `sh:"preupgrade"`
|
||||
PostUpgrade string `sh:"postupgrade"`
|
||||
PreTrans string `sh:"pretrans"`
|
||||
PostTrans string `sh:"posttrans"`
|
||||
}
|
||||
|
||||
func buildCmd(c *cli.Context) error {
|
||||
script := c.String("script")
|
||||
|
||||
err := repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
|
||||
pkgPaths, _, err := buildPackage(c.Context, script, mgr, c.Bool("clean"), c.Bool("interactive"))
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).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
|
||||
}
|
||||
|
||||
// buildPackage builds the script at the given path. It returns two slices. One contains the paths
|
||||
// to the built package(s), the other contains the names of the built package(s).
|
||||
func buildPackage(ctx context.Context, script string, mgr manager.Manager, clean, interactive bool) ([]string, []string, error) {
|
||||
info, err := distro.ParseOSRelease(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var distroChanged bool
|
||||
if distID, ok := os.LookupEnv("LURE_DISTRO"); ok {
|
||||
info.ID = distID
|
||||
// Since the distro was overwritten, we don't know what the
|
||||
// like distros are, so set to nil
|
||||
info.Like = nil
|
||||
distroChanged = true
|
||||
}
|
||||
|
||||
fl, err := os.Open(script)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fl.Close()
|
||||
|
||||
scriptDir := filepath.Dir(script)
|
||||
env := genBuildEnv(info, scriptDir)
|
||||
|
||||
// The first pass is just used to get variable values and runs before
|
||||
// the script is displayed, so it is restricted so as to prevent malicious
|
||||
// code from executing.
|
||||
runner, err := interp.New(
|
||||
interp.Env(expand.ListEnviron(env...)),
|
||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
||||
interp.ExecHandler(rHelpers.ExecHandler(shutils.NopExec)),
|
||||
interp.ReadDirHandler(shutils.RestrictedReadDir(scriptDir)),
|
||||
interp.StatHandler(shutils.RestrictedStat(scriptDir)),
|
||||
interp.OpenHandler(shutils.RestrictedOpen(scriptDir)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = runner.Run(ctx, file)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
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
|
||||
err = dec.DecodeVars(&vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
baseDir := filepath.Join(config.PkgsDir, vars.Name)
|
||||
srcdir := filepath.Join(baseDir, "src")
|
||||
pkgdir := filepath.Join(baseDir, "pkg")
|
||||
|
||||
if !clean {
|
||||
builtPkgPath, ok, err := checkForBuiltPackage(mgr, &vars, getPkgFormat(mgr), baseDir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if ok {
|
||||
return []string{builtPkgPath}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = cliutils.PromptViewScript(script, vars.Name, cfg.PagerStyle, interactive, translator)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to prompt user to view build script").Err(err).Send()
|
||||
}
|
||||
|
||||
if !archMatches(vars.Architectures) {
|
||||
buildAnyway, err := cliutils.YesNoPrompt("Your system's CPU architecture doesn't match this package. Do you want to build anyway?", interactive, true, translator)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !buildAnyway {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
||||
|
||||
// The second pass will be used to execute the actual functions,
|
||||
// so it cannot be restricted. The script has already been displayed
|
||||
// to the user by this point, so it should be safe
|
||||
runner, err = interp.New(
|
||||
interp.Env(expand.ListEnviron(env...)),
|
||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
||||
interp.ExecHandler(helpers.ExecHandler(nil)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = runner.Run(ctx, file)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
err = os.RemoveAll(baseDir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(srcdir, 0o755)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(pkgdir, 0o755)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
installed, err := mgr.ListInstalled(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if instVer, ok := installed[vars.Name]; ok {
|
||||
log.Warn("This package is already installed").
|
||||
Str("name", vars.Name).
|
||||
Str("version", instVer).
|
||||
Send()
|
||||
}
|
||||
|
||||
var buildDeps []string
|
||||
if len(vars.BuildDepends) > 0 {
|
||||
found, notFound, err := repos.FindPkgs(gdb, vars.BuildDepends)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
found = filterBuildDeps(found, installed)
|
||||
|
||||
log.Info("Installing build dependencies").Send()
|
||||
|
||||
flattened := cliutils.FlattenPkgs(found, "install", interactive, translator)
|
||||
buildDeps = packageNames(flattened)
|
||||
installPkgs(ctx, flattened, notFound, mgr, clean, interactive)
|
||||
}
|
||||
|
||||
var builtDeps, builtNames, repoDeps []string
|
||||
if len(vars.Depends) > 0 {
|
||||
log.Info("Installing dependencies").Send()
|
||||
|
||||
found, notFound, err := repos.FindPkgs(gdb, vars.Depends)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
scripts := getScriptPaths(cliutils.FlattenPkgs(found, "install", interactive, translator))
|
||||
for _, script := range scripts {
|
||||
pkgPaths, pkgNames, err := buildPackage(ctx, script, mgr, clean, interactive)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
builtDeps = append(builtDeps, pkgPaths...)
|
||||
builtNames = append(builtNames, pkgNames...)
|
||||
builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
|
||||
}
|
||||
repoDeps = notFound
|
||||
}
|
||||
|
||||
log.Info("Downloading sources").Send()
|
||||
|
||||
err = getSources(ctx, srcdir, &vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = setDirVars(ctx, runner, srcdir, pkgdir)
|
||||
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
|
||||
}
|
||||
|
||||
newVer := strings.TrimSpace(buf.String())
|
||||
err = setVersion(ctx, runner, newVer)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
vars.Version = newVer
|
||||
|
||||
log.Info("Updating version").Str("new", newVer).Send()
|
||||
}
|
||||
|
||||
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("build")
|
||||
if ok {
|
||||
log.Info("Executing build()").Send()
|
||||
|
||||
err = fn(ctx, interp.Dir(srcdir))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
fn, ok = dec.GetFunc("package")
|
||||
if ok {
|
||||
log.Info("Executing package()").Send()
|
||||
|
||||
err = fn(ctx, interp.Dir(srcdir))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
log.Fatal("The package() function is required").Send()
|
||||
}
|
||||
|
||||
log.Info("Building package metadata").Str("name", vars.Name).Send()
|
||||
|
||||
uniq(
|
||||
&repoDeps,
|
||||
&builtDeps,
|
||||
&builtNames,
|
||||
)
|
||||
|
||||
pkgInfo := &nfpm.Info{
|
||||
Name: vars.Name,
|
||||
Description: vars.Description,
|
||||
Arch: cpu.Arch(),
|
||||
Version: vars.Version,
|
||||
Release: strconv.Itoa(vars.Release),
|
||||
Homepage: vars.Homepage,
|
||||
License: strings.Join(vars.Licenses, ", "),
|
||||
Maintainer: vars.Maintainer,
|
||||
Overridables: nfpm.Overridables{
|
||||
Conflicts: vars.Conflicts,
|
||||
Replaces: vars.Replaces,
|
||||
Provides: vars.Provides,
|
||||
Depends: append(repoDeps, builtNames...),
|
||||
var buildCmd = &cli.Command{
|
||||
Name: "build",
|
||||
Usage: "Build a local package",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "script",
|
||||
Aliases: []string{"s"},
|
||||
Value: "lure.sh",
|
||||
Usage: "Path to the build script",
|
||||
},
|
||||
}
|
||||
&cli.StringFlag{
|
||||
Name: "package",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Name of the package to build and its repo (example: default/go-bin)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
script := c.String("script")
|
||||
if c.String("package") != "" {
|
||||
script = filepath.Join(config.GetPaths().RepoDir, c.String("package"), "lure.sh")
|
||||
}
|
||||
|
||||
if vars.Epoch != 0 {
|
||||
pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10)
|
||||
}
|
||||
err := repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
setScripts(&vars, pkgInfo, filepath.Dir(script))
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
|
||||
if slices.Contains(vars.Architectures, "all") {
|
||||
pkgInfo.Arch = "all"
|
||||
}
|
||||
pkgPaths, _, err := build.BuildPackage(c.Context, types.BuildOpts{
|
||||
Script: script,
|
||||
Manager: mgr,
|
||||
Clean: c.Bool("clean"),
|
||||
Interactive: c.Bool("interactive"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).Send()
|
||||
}
|
||||
|
||||
contents := []*files.Content{}
|
||||
filepath.Walk(pkgdir, func(path string, fi os.FileInfo, err error) error {
|
||||
trimmed := strings.TrimPrefix(path, pkgdir)
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal("Error getting working directory").Err(err).Send()
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
f, err := os.Open(path)
|
||||
for _, pkgPath := range pkgPaths {
|
||||
name := filepath.Base(pkgPath)
|
||||
err = osutils.Move(pkgPath, filepath.Join(wd, name))
|
||||
if err != nil {
|
||||
return err
|
||||
log.Fatal("Error moving the package").Err(err).Send()
|
||||
}
|
||||
|
||||
_, err = f.Readdirnames(1)
|
||||
if err != io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
Type: "dir",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
},
|
||||
})
|
||||
|
||||
f.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
link, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
link = strings.TrimPrefix(link, pkgdir)
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: link,
|
||||
Destination: trimmed,
|
||||
Type: "symlink",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fileContent := &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
Size: fi.Size(),
|
||||
},
|
||||
}
|
||||
|
||||
if slices.Contains(vars.Backup, trimmed) {
|
||||
fileContent.Type = "config|noreplace"
|
||||
}
|
||||
|
||||
contents = append(contents, fileContent)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
pkgInfo.Overridables.Contents = contents
|
||||
|
||||
packager, err := nfpm.Get(getPkgFormat(mgr))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pkgName := packager.ConventionalFileName(pkgInfo)
|
||||
pkgPath := filepath.Join(baseDir, pkgName)
|
||||
|
||||
pkgPaths := append(builtDeps, pkgPath)
|
||||
pkgNames := append(builtNames, vars.Name)
|
||||
|
||||
pkgFile, err := os.Create(pkgPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Info("Compressing package").Str("name", pkgName).Send()
|
||||
|
||||
err = packager.Package(pkgInfo, pkgFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(buildDeps) > 0 {
|
||||
removeBuildDeps, err := cliutils.YesNoPrompt("Would you like to remove build dependencies?", interactive, false, translator)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if removeBuildDeps {
|
||||
err = mgr.Remove(
|
||||
&manager.Opts{
|
||||
AsRoot: true,
|
||||
NoConfirm: true,
|
||||
},
|
||||
buildDeps...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uniq(&pkgPaths, &pkgNames)
|
||||
|
||||
return pkgPaths, pkgNames, nil
|
||||
}
|
||||
|
||||
func checkForBuiltPackage(mgr manager.Manager, vars *BuildVars, pkgFormat, baseDir string) (string, bool, error) {
|
||||
filename, err := pkgFileName(vars, pkgFormat)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
pkgPath := filepath.Join(baseDir, filename)
|
||||
|
||||
_, err = os.Stat(pkgPath)
|
||||
if err != nil {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return pkgPath, true, nil
|
||||
}
|
||||
|
||||
func pkgFileName(vars *BuildVars, pkgFormat string) (string, error) {
|
||||
pkgInfo := &nfpm.Info{
|
||||
Name: vars.Name,
|
||||
Arch: cpu.Arch(),
|
||||
Version: vars.Version,
|
||||
Release: strconv.Itoa(vars.Release),
|
||||
Epoch: strconv.FormatUint(uint64(vars.Epoch), 10),
|
||||
}
|
||||
|
||||
packager, err := nfpm.Get(pkgFormat)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return packager.ConventionalFileName(pkgInfo), nil
|
||||
}
|
||||
|
||||
func getPkgFormat(mgr manager.Manager) string {
|
||||
pkgFormat := mgr.Format()
|
||||
if format, ok := os.LookupEnv("LURE_PKG_FORMAT"); ok {
|
||||
pkgFormat = format
|
||||
}
|
||||
return pkgFormat
|
||||
}
|
||||
|
||||
func genBuildEnv(info *distro.OSRelease, scriptdir string) []string {
|
||||
env := os.Environ()
|
||||
|
||||
env = append(
|
||||
env,
|
||||
"DISTRO_NAME="+info.Name,
|
||||
"DISTRO_PRETTY_NAME="+info.PrettyName,
|
||||
"DISTRO_ID="+info.ID,
|
||||
"DISTRO_VERSION_ID="+info.VersionID,
|
||||
"DISTRO_ID_LIKE="+strings.Join(info.Like, " "),
|
||||
|
||||
"ARCH="+cpu.Arch(),
|
||||
"NCPU="+strconv.Itoa(runtime.NumCPU()),
|
||||
|
||||
"scriptdir="+scriptdir,
|
||||
)
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func getSources(ctx context.Context, srcdir string, bv *BuildVars) error {
|
||||
if len(bv.Sources) != len(bv.Checksums) {
|
||||
log.Fatal("The checksums array must be the same length as sources")
|
||||
}
|
||||
|
||||
for i, src := range bv.Sources {
|
||||
opts := dl.Options{
|
||||
Name: fmt.Sprintf("%s[%d]", bv.Name, i),
|
||||
URL: src,
|
||||
Destination: srcdir,
|
||||
Progress: os.Stderr,
|
||||
}
|
||||
|
||||
if !strings.EqualFold(bv.Checksums[i], "SKIP") {
|
||||
checksum, err := hex.DecodeString(bv.Checksums[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.SHA256 = checksum
|
||||
}
|
||||
|
||||
err := dl.Download(ctx, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setDirVars sets srcdir and pkgdir. It's a very hacky way of doing so,
|
||||
// but setting the runner's Env and Vars fields doesn't seem to work.
|
||||
func setDirVars(ctx context.Context, runner *interp.Runner, srcdir, pkgdir string) error {
|
||||
cmd := "srcdir='" + srcdir + "'\npkgdir='" + pkgdir + "'\n"
|
||||
fl, err := syntax.NewParser().Parse(strings.NewReader(cmd), "vars")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.Run(ctx, fl)
|
||||
}
|
||||
|
||||
func setScripts(vars *BuildVars, info *nfpm.Info, scriptDir string) {
|
||||
if vars.Scripts.PreInstall != "" {
|
||||
info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostInstall != "" {
|
||||
info.Scripts.PostInstall = filepath.Join(scriptDir, vars.Scripts.PostInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreRemove != "" {
|
||||
info.Scripts.PreRemove = filepath.Join(scriptDir, vars.Scripts.PreRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostRemove != "" {
|
||||
info.Scripts.PostRemove = filepath.Join(scriptDir, vars.Scripts.PostRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
info.APK.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
info.APK.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreTrans != "" {
|
||||
info.RPM.Scripts.PreTrans = filepath.Join(scriptDir, vars.Scripts.PreTrans)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostTrans != "" {
|
||||
info.RPM.Scripts.PostTrans = filepath.Join(scriptDir, vars.Scripts.PostTrans)
|
||||
}
|
||||
}
|
||||
|
||||
// archMatches checks if your system architecture matches
|
||||
// one of the provided architectures
|
||||
func archMatches(architectures []string) bool {
|
||||
if slices.Contains(architectures, "all") {
|
||||
return true
|
||||
}
|
||||
|
||||
if slices.Contains(architectures, "arm") {
|
||||
architectures = append(architectures, cpu.ARMVariant())
|
||||
}
|
||||
|
||||
return slices.Contains(architectures, cpu.Arch())
|
||||
}
|
||||
|
||||
func setVersion(ctx context.Context, r *interp.Runner, to string) error {
|
||||
fl, err := syntax.NewParser().Parse(strings.NewReader("version='"+to+"'"), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Run(ctx, fl)
|
||||
}
|
||||
|
||||
func filterBuildDeps(found map[string][]db.Package, installed map[string]string) map[string][]db.Package {
|
||||
out := map[string][]db.Package{}
|
||||
for name, pkgs := range found {
|
||||
var inner []db.Package
|
||||
for _, pkg := range pkgs {
|
||||
if _, ok := installed[pkg.Name]; !ok {
|
||||
addToFiltered := true
|
||||
for _, provides := range pkg.Provides.Val {
|
||||
if _, ok := installed[provides]; ok {
|
||||
addToFiltered = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if addToFiltered {
|
||||
inner = append(inner, pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(inner) > 0 {
|
||||
out[name] = inner
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func packageNames(pkgs []db.Package) []string {
|
||||
names := make([]string, len(pkgs))
|
||||
for i, p := range pkgs {
|
||||
names[i] = p.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// uniq removes all duplicates from string slices
|
||||
func uniq(ss ...*[]string) {
|
||||
for _, s := range ss {
|
||||
slices.Sort(*s)
|
||||
*s = slices.Compact(*s)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -25,18 +25,15 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/twitchtv/twirp"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/api"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type lureWebAPI struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
type lureWebAPI struct{}
|
||||
|
||||
func (l lureWebAPI) Search(ctx context.Context, req *api.SearchRequest) (*api.SearchResponse, error) {
|
||||
query := "(name LIKE ? OR description LIKE ? OR json_array_contains(provides, ?))"
|
||||
@@ -67,7 +64,7 @@ func (l lureWebAPI) Search(ctx context.Context, req *api.SearchRequest) (*api.Se
|
||||
query += " LIMIT " + strconv.FormatInt(req.Limit, 10)
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(l.db, query, args...)
|
||||
result, err := db.GetPkgs(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -86,7 +83,7 @@ func (l lureWebAPI) Search(ctx context.Context, req *api.SearchRequest) (*api.Se
|
||||
}
|
||||
|
||||
func (l lureWebAPI) GetPkg(ctx context.Context, req *api.GetPackageRequest) (*api.Package, error) {
|
||||
pkg, err := db.GetPkg(l.db, "name = ? AND repository = ?", req.Name, req.Repository)
|
||||
pkg, err := db.GetPkg("name = ? AND repository = ?", req.Name, req.Repository)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,7 +95,7 @@ func (l lureWebAPI) GetBuildScript(ctx context.Context, req *api.GetBuildScriptR
|
||||
return nil, twirp.NewError(twirp.InvalidArgument, "name and repository must not contain . or /")
|
||||
}
|
||||
|
||||
scriptPath := filepath.Join(config.RepoDir, req.Repository, req.Name, "lure.sh")
|
||||
scriptPath := filepath.Join(config.GetPaths().RepoDir, req.Repository, req.Name, "lure.sh")
|
||||
_, err := os.Stat(scriptPath)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, twirp.NewError(twirp.NotFound, "requested package not found")
|
||||
|
||||
1
cmd/lure-api-server/badge-logo.txt
Normal file
1
cmd/lure-api-server/badge-logo.txt
Normal file
File diff suppressed because one or more lines are too long
58
cmd/lure-api-server/badge.go
Normal file
58
cmd/lure-api-server/badge.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
)
|
||||
|
||||
//go:embed badge-logo.txt
|
||||
var logoData string
|
||||
|
||||
var _ http.HandlerFunc
|
||||
|
||||
func handleBadge() http.HandlerFunc {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
repo := chi.URLParam(req, "repo")
|
||||
name := chi.URLParam(req, "pkg")
|
||||
|
||||
pkg, err := db.GetPkg("name = ? AND repository = ?", name, repo)
|
||||
if err != nil {
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(res, req, genBadgeURL(pkg.Name, genVersion(pkg)), http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func genVersion(pkg *db.Package) string {
|
||||
sb := strings.Builder{}
|
||||
if pkg.Epoch != 0 {
|
||||
sb.WriteString(strconv.Itoa(int(pkg.Epoch)))
|
||||
sb.WriteByte(':')
|
||||
}
|
||||
|
||||
sb.WriteString(pkg.Version)
|
||||
|
||||
if pkg.Release != 0 {
|
||||
sb.WriteByte('-')
|
||||
sb.WriteString(strconv.Itoa(pkg.Release))
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func genBadgeURL(pkgName, pkgVersion string) string {
|
||||
v := url.Values{}
|
||||
v.Set("label", pkgName)
|
||||
v.Set("message", pkgVersion)
|
||||
v.Set("logo", logoData)
|
||||
v.Set("color", "blue")
|
||||
u := &url.URL{Scheme: "https", Host: "img.shields.io", Path: "/static/v1", RawQuery: v.Encode()}
|
||||
return u.String()
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
)
|
||||
|
||||
var gdb *sqlx.DB
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
gdb, err = db.Open(config.DBPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening database").Err(err).Send()
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build
|
||||
docker buildx build --platform linux/amd64 --tag arsen6331/lure-api-server:amd64 --no-cache .
|
||||
docker buildx build --platform linux/amd64 --tag elara6331/lure-api-server:amd64 --no-cache .
|
||||
|
||||
CGO_ENABLED=0 GOARCH=arm64 GOOS=linux go build
|
||||
docker buildx build --platform linux/arm64/v8 --tag arsen6331/lure-api-server:arm64 --no-cache .
|
||||
docker buildx build --platform linux/arm64/v8 --tag elara6331/lure-api-server:arm64 --no-cache .
|
||||
|
||||
docker login
|
||||
docker push arsen6331/lure-api-server -a
|
||||
docker push elara6331/lure-api-server -a
|
||||
|
||||
docker manifest rm arsen6331/lure-api-server:latest
|
||||
docker manifest create arsen6331/lure-api-server:latest --amend arsen6331/lure-api-server:arm64 --amend arsen6331/lure-api-server:amd64
|
||||
docker manifest push arsen6331/lure-api-server:latest
|
||||
docker manifest rm elara6331/lure-api-server:latest
|
||||
docker manifest create elara6331/lure-api-server:latest --amend elara6331/lure-api-server:arm64 --amend elara6331/lure-api-server:amd64
|
||||
docker manifest push elara6331/lure-api-server:latest
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -25,10 +25,12 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/twitchtv/twirp"
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/api"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
)
|
||||
|
||||
@@ -53,7 +55,7 @@ func main() {
|
||||
log.Logger = logger.NewMulti(log.Logger, logger.NewJSON(fl))
|
||||
}
|
||||
|
||||
err := repos.Pull(ctx, gdb, cfg.Repos)
|
||||
err := repos.Pull(ctx, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
@@ -61,15 +63,15 @@ func main() {
|
||||
sigCh := make(chan struct{}, 200)
|
||||
go repoPullWorker(ctx, sigCh)
|
||||
|
||||
var handler http.Handler
|
||||
|
||||
handler = api.NewAPIServer(
|
||||
lureWebAPI{db: gdb},
|
||||
apiServer := api.NewAPIServer(
|
||||
lureWebAPI{},
|
||||
twirp.WithServerPathPrefix(""),
|
||||
)
|
||||
handler = withAcceptLanguage(handler)
|
||||
handler = allowAllCORSHandler(handler)
|
||||
handler = handleWebhook(handler, sigCh)
|
||||
|
||||
r := chi.NewRouter()
|
||||
r.With(allowAllCORSHandler, withAcceptLanguage).Handle("/*", apiServer)
|
||||
r.Post("/webhook", handleWebhook(sigCh))
|
||||
r.Get("/badge/{repo}/{pkg}", handleBadge())
|
||||
|
||||
ln, err := net.Listen("tcp", *addr)
|
||||
if err != nil {
|
||||
@@ -78,7 +80,7 @@ func main() {
|
||||
|
||||
log.Info("Starting HTTP API server").Str("addr", ln.Addr().String()).Send()
|
||||
|
||||
err = http.Serve(ln, handler)
|
||||
err = http.Serve(ln, r)
|
||||
if err != nil {
|
||||
log.Fatal("Error while running server").Err(err).Send()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -29,34 +29,26 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
)
|
||||
|
||||
func handleWebhook(next http.Handler, sigCh chan<- struct{}) http.Handler {
|
||||
func handleWebhook(sigCh chan<- struct{}) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
if req.URL.Path == "/webhook" {
|
||||
if req.Method != http.MethodPost {
|
||||
res.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Header.Get("X-GitHub-Event") != "push" {
|
||||
http.Error(res, "Only push events are accepted by this bot", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err := verifySecure(req)
|
||||
if err != nil {
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
sigCh <- struct{}{}
|
||||
if req.Header.Get("X-GitHub-Event") != "push" {
|
||||
http.Error(res, "Only push events are accepted by this bot", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(res, req)
|
||||
err := verifySecure(req)
|
||||
if err != nil {
|
||||
http.Error(res, err.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
sigCh <- struct{}{}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,7 +88,7 @@ func repoPullWorker(ctx context.Context, sigCh <-chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case <-sigCh:
|
||||
err := repos.Pull(ctx, gdb, cfg.Repos)
|
||||
err := repos.Pull(ctx, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Warn("Error while pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
36
config.go
36
config.go
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import (
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/manager"
|
||||
)
|
||||
|
||||
var cfg types.Config
|
||||
|
||||
func init() {
|
||||
err := config.Decode(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error decoding config file").Err(err).Send()
|
||||
}
|
||||
manager.DefaultRootCmd = cfg.RootCmd
|
||||
}
|
||||
36
db.go
36
db.go
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
)
|
||||
|
||||
var gdb *sqlx.DB
|
||||
|
||||
func loadDB() error {
|
||||
ldb, err := db.Open(config.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gdb = ldb
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -103,7 +103,14 @@ func ParseOSRelease(ctx context.Context) (*OSRelease, error) {
|
||||
Logo: runner.Vars["LOGO"].Str,
|
||||
}
|
||||
|
||||
if runner.Vars["ID_LIKE"].IsSet() {
|
||||
distroUpdated := false
|
||||
if distID, ok := os.LookupEnv("LURE_DISTRO"); ok {
|
||||
out.ID = distID
|
||||
}
|
||||
|
||||
if distLike, ok := os.LookupEnv("LURE_DISTRO_LIKE"); ok {
|
||||
out.Like = strings.Split(distLike, " ")
|
||||
} else if runner.Vars["ID_LIKE"].IsSet() && !distroUpdated {
|
||||
out.Like = strings.Split(runner.Vars["ID_LIKE"].Str, " ")
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,9 @@ git+https://gitea.arsenm.dev/Arsen6331/lure?~rev=v0.0.1&~recursive=true
|
||||
|
||||
### 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.
|
||||
The `checksums` array must be the same length as the `sources` array. It contains checksums for the source files. The files are checked against the checksums and the build fails if they don't match.
|
||||
|
||||
By default, checksums are expected to be sha256. To change the algorithm, add it before the hash with a colon in between. For example, `md5:bc0c6f5dcd06bddbca9a0163e4c9f2e1`. The following algorithms are currently supported: `sha256`, `sha224`, `sha512`, `sha384`, `sha1`, and `md5`.
|
||||
|
||||
To skip the check for a particular source, set the corresponding checksum to `SKIP`.
|
||||
|
||||
|
||||
52
fix.go
52
fix.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,42 +22,40 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
)
|
||||
|
||||
func fixCmd(c *cli.Context) error {
|
||||
gdb.Close()
|
||||
var fixCmd = &cli.Command{
|
||||
Name: "fix",
|
||||
Usage: "Attempt to fix problems with LURE",
|
||||
Action: func(c *cli.Context) error {
|
||||
db.Close()
|
||||
paths := config.GetPaths()
|
||||
|
||||
log.Info("Removing cache directory").Send()
|
||||
log.Info("Removing cache directory").Send()
|
||||
|
||||
err := os.RemoveAll(config.CacheDir)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to remove cache directory").Err(err).Send()
|
||||
}
|
||||
err := os.RemoveAll(paths.CacheDir)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to remove cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
log.Info("Rebuilding cache").Send()
|
||||
log.Info("Rebuilding cache").Send()
|
||||
|
||||
err = os.MkdirAll(config.CacheDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create new cache directory").Err(err).Send()
|
||||
}
|
||||
err = os.MkdirAll(paths.CacheDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create new cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
// Make sure the DB is rebuilt when repos are pulled
|
||||
gdb, err = db.Open(config.DBPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error initializing database").Err(err).Send()
|
||||
}
|
||||
config.DBPresent = false
|
||||
err = repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
|
||||
err = repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
log.Info("Done").Send()
|
||||
|
||||
log.Info("Done").Send()
|
||||
|
||||
return nil
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
128
go.mod
128
go.mod
@@ -3,109 +3,123 @@ module go.elara.ws/lure
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
github.com/PuerkitoBio/purell v1.2.0
|
||||
github.com/alecthomas/chroma/v2 v2.4.0
|
||||
github.com/charmbracelet/bubbles v0.14.0
|
||||
github.com/charmbracelet/bubbletea v0.23.1
|
||||
github.com/charmbracelet/lipgloss v0.6.0
|
||||
github.com/go-git/go-billy/v5 v5.3.1
|
||||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/goreleaser/nfpm/v2 v2.20.0
|
||||
github.com/alecthomas/chroma/v2 v2.9.1
|
||||
github.com/charmbracelet/bubbles v0.16.1
|
||||
github.com/charmbracelet/bubbletea v0.24.2
|
||||
github.com/charmbracelet/lipgloss v0.8.0
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.9.0
|
||||
github.com/goreleaser/nfpm/v2 v2.33.0
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/mattn/go-isatty v0.0.18
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/muesli/reflow v0.3.0
|
||||
github.com/pelletier/go-toml/v2 v2.0.7
|
||||
github.com/schollz/progressbar/v3 v3.13.0
|
||||
github.com/pelletier/go-toml/v2 v2.1.0
|
||||
github.com/schollz/progressbar/v3 v3.13.1
|
||||
github.com/twitchtv/twirp v8.1.3+incompatible
|
||||
github.com/urfave/cli/v2 v2.23.7
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090
|
||||
go.elara.ws/translate v0.0.0-20230421025926-32ccfcd110e6
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/text v0.9.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
||||
golang.org/x/sys v0.12.0
|
||||
golang.org/x/text v0.13.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.20.0
|
||||
mvdan.cc/sh/v3 v3.5.1
|
||||
modernc.org/sqlite v1.25.0
|
||||
mvdan.cc/sh/v3 v3.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/AlekSi/pointer v1.2.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
||||
github.com/bodgit/plumbing v1.2.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.3.0 // indirect
|
||||
github.com/bodgit/windows v1.0.0 // indirect
|
||||
github.com/cavaliergopher/cpio v1.0.1 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/connesc/cipherio v0.2.1 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.3 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/rpmpack v0.5.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gookit/color v1.5.3 // indirect
|
||||
github.com/goreleaser/chglog v0.2.2 // indirect
|
||||
github.com/gookit/color v1.5.1 // indirect
|
||||
github.com/goreleaser/chglog v0.5.0 // indirect
|
||||
github.com/goreleaser/fileglob v1.3.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // 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/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/termenv v0.13.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/term v0.12.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.21.5 // indirect
|
||||
modernc.org/libc v1.24.1 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
modernc.org/memory v1.6.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
|
||||
589
go.sum
589
go.sum
@@ -1,152 +1,216 @@
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
||||
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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
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/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
|
||||
github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig=
|
||||
github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk=
|
||||
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw=
|
||||
github.com/alecthomas/chroma/v2 v2.4.0 h1:Loe2ZjT5x3q1bcWwemqyqEi8p11/IV/ncFCeLYDpWC4=
|
||||
github.com/alecthomas/chroma/v2 v2.4.0/go.mod h1:6kHzqF5O6FUSJzBXW7fXELjb+e+7OXW4UpoPqMO7IBQ=
|
||||
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
|
||||
github.com/alecthomas/chroma/v2 v2.9.1 h1:0O3lTQh9FxazJ4BYE/MOi/vDGuHn7B+6Bu902N2UZvU=
|
||||
github.com/alecthomas/chroma/v2 v2.9.1/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
|
||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM=
|
||||
github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8=
|
||||
github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY=
|
||||
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
|
||||
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
|
||||
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/caarlos0/go-rpmutils v0.2.1-0.20211112020245-2cd62ff89b11 h1:IRrDwVlWQr6kS1U8/EtyA1+EHcc4yl8pndcqXWrEamg=
|
||||
github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8=
|
||||
github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk=
|
||||
github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
|
||||
github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc=
|
||||
github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og=
|
||||
github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc=
|
||||
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
|
||||
github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck=
|
||||
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
|
||||
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
|
||||
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
|
||||
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
|
||||
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
|
||||
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
|
||||
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
|
||||
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
|
||||
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
|
||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
|
||||
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
|
||||
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
|
||||
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/rpmpack v0.5.0 h1:L16KZ3QvkFGpYhmp23iQip+mx1X39foEsqszjMNBm8A=
|
||||
github.com/google/rpmpack v0.5.0/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
|
||||
github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/goreleaser/chglog v0.2.2 h1:V7nf07baXtGAgGevvqgW2MM4kZ6gOr12vKNSAU3VIZ0=
|
||||
github.com/goreleaser/chglog v0.2.2/go.mod h1:2s5JwtCOWjZa8AIneL+xdUl9SRuigCjRHNHsX30dupE=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
|
||||
github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/goreleaser/chglog v0.5.0 h1:Sk6BMIpx8+vpAf8KyPit34OgWui8c7nKTMHhYx88jJ4=
|
||||
github.com/goreleaser/chglog v0.5.0/go.mod h1:Ri46M3lrMuv76FHszs3vtABR8J8k1w9JHYAzxeeOl28=
|
||||
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/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/goreleaser/nfpm/v2 v2.33.0 h1:yBv6jgkPwih4va/S42rceSjJ2Znt3Og/Ntc76oP0tfI=
|
||||
github.com/goreleaser/nfpm/v2 v2.33.0/go.mod h1:8wwWWvJWmn84xo/Sqiv0aMvEGTHlHZTXTEuVSgQpkIM=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
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/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
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.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
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/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
@@ -154,186 +218,332 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7 h1:xzByj8G8tj0Oq7ZYYU4+ixL/CVb5ruWCm0EZQ1PjOkE=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7/go.mod h1:Fs8qUkO74HHaidabihzYephJH8qmGD/nCP6tE5xC9BM=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0=
|
||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/schollz/progressbar/v3 v3.13.0 h1:9TeeWRcjW2qd05I8Kf9knPkW4vLM/hYoa6z9ABvxje8=
|
||||
github.com/schollz/progressbar/v3 v3.13.0/go.mod h1:ZBYnSuLAX2LU8P8UiKN/KgF2DY58AJC8yfVYLPC8Ly4=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
||||
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU=
|
||||
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
||||
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
|
||||
github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU=
|
||||
github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
|
||||
github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
|
||||
github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
|
||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090 h1:RVC8XvWo6Yw4HUshqx4TSzuBDScDghafU6QFRJ4xPZg=
|
||||
go.elara.ws/logger v0.0.0-20230421022458-e80700db2090/go.mod h1:qng49owViqsW5Aey93lwBXONw20oGbJIoLVscB16mPM=
|
||||
go.elara.ws/translate v0.0.0-20230421025926-32ccfcd110e6 h1:4xCBxLPBn3Y2DuIcj8zQ1tQOFLrpu6tEIGUWn/Q6zPM=
|
||||
go.elara.ws/translate v0.0.0-20230421025926-32ccfcd110e6/go.mod h1:NmfCFqwq7X/aqa/ZVkIysj17JyMEY4Bb5E921kMswNo=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4 h1:Ep54XceQlKhcCHl9awG+wWP4kz4kIP3c3Lzw/Gc/zwY=
|
||||
go.elara.ws/vercmp v0.0.0-20230622214216-0b2b067575c4/go.mod h1:/7PNW7nFnDR5W7UXZVc04gdVLR/wBNgkm33KgIz0OBk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
@@ -341,9 +551,13 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
||||
@@ -352,21 +566,24 @@ modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
|
||||
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
||||
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
|
||||
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.20.0 h1:80zmD3BGkm8BZ5fUi/4lwJQHiO3GXgIUvZRXpoIfROY=
|
||||
modernc.org/sqlite v1.20.0/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
|
||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34=
|
||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
|
||||
mvdan.cc/sh/v3 v3.5.1 h1:hmP3UOw4f+EYexsJjFxvU38+kn+V/s2CclXHanIBkmQ=
|
||||
mvdan.cc/sh/v3 v3.5.1/go.mod h1:1JcoyAKm1lZw/2bZje/iYKWicU/KMd0rsyJeKHnsK4E=
|
||||
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
|
||||
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
|
||||
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
109
info.go
109
info.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/lure/distro"
|
||||
@@ -33,61 +33,72 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func infoCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command info expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
|
||||
err := repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
found, _, err := repos.FindPkgs(gdb, args.Slice())
|
||||
if err != nil {
|
||||
log.Fatal("Error finding packages").Err(err).Send()
|
||||
}
|
||||
|
||||
if len(found) == 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pkgs := cliutils.FlattenPkgs(found, "show", c.Bool("interactive"), translator)
|
||||
|
||||
var names []string
|
||||
all := c.Bool("all")
|
||||
|
||||
if !all {
|
||||
info, err := distro.ParseOSRelease(c.Context)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing os-release file").Err(err).Send()
|
||||
var infoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "Print information about a package",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Show all information, not just for the current distro",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command info expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
names, err = overrides.Resolve(
|
||||
info,
|
||||
overrides.DefaultOpts.
|
||||
WithLanguages([]string{config.SystemLang()}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Error resolving overrides").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
err := repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
found, _, err := repos.FindPkgs(args.Slice())
|
||||
if err != nil {
|
||||
log.Fatal("Error finding packages").Err(err).Send()
|
||||
}
|
||||
|
||||
if len(found) == 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pkgs := cliutils.FlattenPkgs(found, "show", c.Bool("interactive"))
|
||||
|
||||
var names []string
|
||||
all := c.Bool("all")
|
||||
|
||||
if !all {
|
||||
err = yaml.NewEncoder(os.Stdout).Encode(overrides.ResolvePackage(&pkg, names))
|
||||
info, err := distro.ParseOSRelease(c.Context)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding script variables").Err(err).Send()
|
||||
log.Fatal("Error parsing os-release file").Err(err).Send()
|
||||
}
|
||||
} else {
|
||||
err = yaml.NewEncoder(os.Stdout).Encode(pkg)
|
||||
names, err = overrides.Resolve(
|
||||
info,
|
||||
overrides.DefaultOpts.
|
||||
WithLanguages([]string{config.SystemLang()}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding script variables").Err(err).Send()
|
||||
log.Fatal("Error resolving overrides").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("---")
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
if !all {
|
||||
err = yaml.NewEncoder(os.Stdout).Encode(overrides.ResolvePackage(&pkg, names))
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding script variables").Err(err).Send()
|
||||
}
|
||||
} else {
|
||||
err = yaml.NewEncoder(os.Stdout).Encode(pkg)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding script variables").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
fmt.Println("---")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
156
install.go
156
install.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -19,98 +19,98 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"go.elara.ws/logger/log"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/lure/internal/build"
|
||||
"go.elara.ws/lure/internal/cliutils"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/manager"
|
||||
)
|
||||
|
||||
func installCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command install expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
|
||||
err := repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
found, notFound, err := repos.FindPkgs(gdb, args.Slice())
|
||||
if err != nil {
|
||||
log.Fatal("Error finding packages").Err(err).Send()
|
||||
}
|
||||
|
||||
installPkgs(c.Context, cliutils.FlattenPkgs(found, "install", c.Bool("interactive"), translator), notFound, mgr, c.Bool("clean"), c.Bool("interactive"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// installPkgs installs non-LURE packages via the package manager, then builds and installs LURE
|
||||
// packages
|
||||
func installPkgs(ctx context.Context, pkgs []db.Package, notFound []string, mgr manager.Manager, clean, interactive bool) {
|
||||
if len(notFound) > 0 {
|
||||
err := mgr.Install(nil, notFound...)
|
||||
if err != nil {
|
||||
log.Fatal("Error installing native packages").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
installScripts(ctx, mgr, getScriptPaths(pkgs), clean, interactive)
|
||||
}
|
||||
|
||||
// getScriptPaths generates a slice of script paths corresponding to the
|
||||
// given packages
|
||||
func getScriptPaths(pkgs []db.Package) []string {
|
||||
var scripts []string
|
||||
for _, pkg := range pkgs {
|
||||
scriptPath := filepath.Join(config.RepoDir, pkg.Repository, pkg.Name, "lure.sh")
|
||||
scripts = append(scripts, scriptPath)
|
||||
}
|
||||
return scripts
|
||||
}
|
||||
|
||||
// installScripts builds and installs LURE build scripts
|
||||
func installScripts(ctx context.Context, mgr manager.Manager, scripts []string, clean, interactive bool) {
|
||||
for _, script := range scripts {
|
||||
builtPkgs, _, err := buildPackage(ctx, script, mgr, clean, interactive)
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).Send()
|
||||
var installCmd = &cli.Command{
|
||||
Name: "install",
|
||||
Usage: "Install a new package",
|
||||
Aliases: []string{"in"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command install expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
|
||||
err = mgr.InstallLocal(nil, builtPkgs...)
|
||||
if err != nil {
|
||||
log.Fatal("Error installing package").Err(err).Send()
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
}
|
||||
|
||||
err := repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
found, notFound, err := repos.FindPkgs(args.Slice())
|
||||
if err != nil {
|
||||
log.Fatal("Error finding packages").Err(err).Send()
|
||||
}
|
||||
|
||||
pkgs := cliutils.FlattenPkgs(found, "install", c.Bool("interactive"))
|
||||
build.InstallPkgs(c.Context, pkgs, notFound, types.BuildOpts{
|
||||
Manager: mgr,
|
||||
Clean: c.Bool("clean"),
|
||||
Interactive: c.Bool("interactive"),
|
||||
})
|
||||
return nil
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
result, err := db.GetPkgs("true")
|
||||
if err != nil {
|
||||
log.Fatal("Error getting packages").Err(err).Send()
|
||||
}
|
||||
defer result.Close()
|
||||
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err = result.StructScan(&pkg)
|
||||
if err != nil {
|
||||
log.Fatal("Error iterating over packages").Err(err).Send()
|
||||
}
|
||||
|
||||
fmt.Println(pkg.Name)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func removeCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command remove expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
var removeCmd = &cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "Remove an installed package",
|
||||
Aliases: []string{"rm"},
|
||||
Action: func(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if args.Len() < 1 {
|
||||
log.Fatalf("Command remove expected at least 1 argument, got %d", args.Len()).Send()
|
||||
}
|
||||
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
|
||||
err := mgr.Remove(nil, c.Args().Slice()...)
|
||||
if err != nil {
|
||||
log.Fatal("Error removing packages").Err(err).Send()
|
||||
}
|
||||
err := mgr.Remove(nil, c.Args().Slice()...)
|
||||
if err != nil {
|
||||
log.Fatal("Error removing packages").Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.9
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.24.2
|
||||
// source: lure.proto
|
||||
|
||||
package api
|
||||
|
||||
780
internal/build/build.go
Normal file
780
internal/build/build.go
Normal file
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Elara 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 build
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||
_ "github.com/goreleaser/nfpm/v2/rpm"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"go.elara.ws/lure/distro"
|
||||
"go.elara.ws/lure/internal/cliutils"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/cpu"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/dl"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/internal/shutils"
|
||||
"go.elara.ws/lure/internal/shutils/decoder"
|
||||
"go.elara.ws/lure/internal/shutils/helpers"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/manager"
|
||||
"mvdan.cc/sh/v3/expand"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
)
|
||||
|
||||
// BuildPackage builds the script at the given path. It returns two slices. One contains the paths
|
||||
// to the built package(s), the other contains the names of the built package(s).
|
||||
func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string, error) {
|
||||
info, err := distro.ParseOSRelease(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fl, err := parseScript(info, opts.Script)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
vars, err := executeFirstPass(ctx, info, fl, opts.Script)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dirs := getDirs(vars, opts.Script)
|
||||
|
||||
if !opts.Clean {
|
||||
builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if ok {
|
||||
return []string{builtPkgPath}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = cliutils.PromptViewScript(opts.Script, vars.Name, config.Config().PagerStyle, opts.Interactive)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to prompt user to view build script").Err(err).Send()
|
||||
}
|
||||
|
||||
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
||||
|
||||
dec, err := executeSecondPass(ctx, info, fl, dirs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
installed, err := opts.Manager.ListInstalled(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cont, err := performChecks(vars, opts.Interactive, installed)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if !cont {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = prepareDirs(dirs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
buildDeps, err := installBuildDeps(ctx, vars, opts, installed)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = installOptDeps(ctx, vars, opts, installed)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
builtPaths, builtNames, repoDeps, err := installDeps(ctx, opts, vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Info("Downloading sources").Send()
|
||||
|
||||
err = getSources(ctx, dirs.SrcDir, vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = executeFunctions(ctx, dec, dirs, vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Info("Building package metadata").Str("name", vars.Name).Send()
|
||||
|
||||
pkgInfo, err := buildPkgMetadata(vars, dirs, append(repoDeps, builtNames...))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
packager, err := nfpm.Get(getPkgFormat(opts.Manager))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pkgName := packager.ConventionalFileName(pkgInfo)
|
||||
pkgPath := filepath.Join(dirs.BaseDir, pkgName)
|
||||
|
||||
pkgFile, err := os.Create(pkgPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Info("Compressing package").Str("name", pkgName).Send()
|
||||
|
||||
err = packager.Package(pkgInfo, pkgFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = removeBuildDeps(buildDeps, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Add the path and name of the package we just built to the
|
||||
// appropriate slices
|
||||
pkgPaths := append(builtPaths, pkgPath)
|
||||
pkgNames := append(builtNames, vars.Name)
|
||||
|
||||
pkgPaths = removeDuplicates(pkgPaths)
|
||||
pkgNames = removeDuplicates(pkgNames)
|
||||
|
||||
return pkgPaths, pkgNames, nil
|
||||
}
|
||||
|
||||
func parseScript(info *distro.OSRelease, script string) (*syntax.File, error) {
|
||||
fl, err := os.Open(script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fl.Close()
|
||||
|
||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) {
|
||||
scriptDir := filepath.Dir(script)
|
||||
env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir})
|
||||
|
||||
// The first pass is just used to get variable values and runs before
|
||||
// the script is displayed, so it is restricted so as to prevent malicious
|
||||
// code from executing.
|
||||
runner, err := interp.New(
|
||||
interp.Env(expand.ListEnviron(env...)),
|
||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
||||
interp.ExecHandler(helpers.Restricted.ExecHandler(shutils.NopExec)),
|
||||
interp.ReadDirHandler(shutils.RestrictedReadDir(scriptDir)),
|
||||
interp.StatHandler(shutils.RestrictedStat(scriptDir)),
|
||||
interp.OpenHandler(shutils.RestrictedOpen(scriptDir)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = runner.Run(ctx, fl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dec := decoder.New(info, runner)
|
||||
|
||||
var vars types.BuildVars
|
||||
err = dec.DecodeVars(&vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &vars, nil
|
||||
}
|
||||
|
||||
func getDirs(vars *types.BuildVars, script string) types.Directories {
|
||||
baseDir := filepath.Join(config.GetPaths().PkgsDir, vars.Name)
|
||||
return types.Directories{
|
||||
BaseDir: baseDir,
|
||||
SrcDir: filepath.Join(baseDir, "src"),
|
||||
PkgDir: filepath.Join(baseDir, "pkg"),
|
||||
ScriptDir: filepath.Dir(script),
|
||||
}
|
||||
}
|
||||
|
||||
func executeSecondPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, dirs types.Directories) (*decoder.Decoder, error) {
|
||||
env := createBuildEnvVars(info, dirs)
|
||||
// The second pass will be used to execute the actual functions,
|
||||
// so it cannot be restricted. The script has already been displayed
|
||||
// to the user by this point, so it should be safe
|
||||
runner, err := interp.New(
|
||||
interp.Env(expand.ListEnviron(env...)),
|
||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
||||
interp.ExecHandler(helpers.Helpers.ExecHandler(nil)),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = runner.Run(ctx, fl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decoder.New(info, runner), nil
|
||||
}
|
||||
|
||||
func prepareDirs(dirs types.Directories) error {
|
||||
err := os.RemoveAll(dirs.BaseDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(dirs.SrcDir, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(dirs.PkgDir, 0o755)
|
||||
}
|
||||
|
||||
func performChecks(vars *types.BuildVars, interactive bool, installed map[string]string) (bool, error) {
|
||||
if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) {
|
||||
cont, err := cliutils.YesNoPrompt("Your system's CPU architecture doesn't match this package. Do you want to build anyway?", interactive, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !cont {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if instVer, ok := installed[vars.Name]; ok {
|
||||
log.Warn("This package is already installed").
|
||||
Str("name", vars.Name).
|
||||
Str("version", instVer).
|
||||
Send()
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func installBuildDeps(ctx context.Context, vars *types.BuildVars, opts types.BuildOpts, installed map[string]string) ([]string, error) {
|
||||
var buildDeps []string
|
||||
if len(vars.BuildDepends) > 0 {
|
||||
found, notFound, err := repos.FindPkgs(vars.BuildDepends)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
found = filterBuildDeps(found, installed)
|
||||
|
||||
log.Info("Installing build dependencies").Send()
|
||||
|
||||
flattened := cliutils.FlattenPkgs(found, "install", opts.Interactive)
|
||||
buildDeps = packageNames(flattened)
|
||||
InstallPkgs(ctx, flattened, notFound, opts)
|
||||
}
|
||||
return buildDeps, nil
|
||||
}
|
||||
|
||||
func installOptDeps(ctx context.Context, vars *types.BuildVars, opts types.BuildOpts, installed map[string]string) error {
|
||||
if len(vars.OptDepends) > 0 {
|
||||
optDeps, err := cliutils.ChooseOptDepends(vars.OptDepends, "install", opts.Interactive)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(optDeps) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
found, notFound, err := repos.FindPkgs(optDeps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found = filterBuildDeps(found, installed)
|
||||
flattened := cliutils.FlattenPkgs(found, "install", opts.Interactive)
|
||||
optDeps = packageNames(flattened)
|
||||
InstallPkgs(ctx, flattened, notFound, opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func installDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVars) (builtPaths, builtNames, repoDeps []string, err error) {
|
||||
if len(vars.Depends) > 0 {
|
||||
log.Info("Installing dependencies").Send()
|
||||
|
||||
found, notFound, err := repos.FindPkgs(vars.Depends)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
repoDeps = notFound
|
||||
|
||||
// If there are multiple options for some packages, flatten them all into a single slice
|
||||
pkgs := cliutils.FlattenPkgs(found, "install", opts.Interactive)
|
||||
scripts := GetScriptPaths(pkgs)
|
||||
for _, script := range scripts {
|
||||
newOpts := opts
|
||||
newOpts.Script = script
|
||||
|
||||
// Build the dependency
|
||||
pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Append the paths of all the built packages to builtPaths
|
||||
builtPaths = append(builtPaths, pkgPaths...)
|
||||
// Append the names of all the built packages to builtNames
|
||||
builtNames = append(builtNames, pkgNames...)
|
||||
// Append the name of the current package to builtNames
|
||||
builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
|
||||
}
|
||||
}
|
||||
|
||||
repoDeps = removeDuplicates(repoDeps)
|
||||
builtPaths = removeDuplicates(builtPaths)
|
||||
builtNames = removeDuplicates(builtNames)
|
||||
return builtPaths, builtNames, repoDeps, nil
|
||||
}
|
||||
|
||||
func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Directories, vars *types.BuildVars) (err error) {
|
||||
version, ok := dec.GetFunc("version")
|
||||
if ok {
|
||||
log.Info("Executing version()").Send()
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
err = version(
|
||||
ctx,
|
||||
interp.Dir(dirs.SrcDir),
|
||||
interp.StdIO(os.Stdin, buf, os.Stderr),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newVer := strings.TrimSpace(buf.String())
|
||||
err = setVersion(ctx, dec.Runner, newVer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vars.Version = newVer
|
||||
|
||||
log.Info("Updating version").Str("new", newVer).Send()
|
||||
}
|
||||
|
||||
prepare, ok := dec.GetFunc("prepare")
|
||||
if ok {
|
||||
log.Info("Executing prepare()").Send()
|
||||
|
||||
err = prepare(ctx, interp.Dir(dirs.SrcDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
build, ok := dec.GetFunc("build")
|
||||
if ok {
|
||||
log.Info("Executing build()").Send()
|
||||
|
||||
err = build(ctx, interp.Dir(dirs.SrcDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
packageFn, ok := dec.GetFunc("package")
|
||||
if ok {
|
||||
log.Info("Executing package()").Send()
|
||||
|
||||
err = packageFn(ctx, interp.Dir(dirs.SrcDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Fatal("The package() function is required").Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, deps []string) (*nfpm.Info, error) {
|
||||
pkgInfo := &nfpm.Info{
|
||||
Name: vars.Name,
|
||||
Description: vars.Description,
|
||||
Arch: cpu.Arch(),
|
||||
Platform: "linux",
|
||||
Version: vars.Version,
|
||||
Release: strconv.Itoa(vars.Release),
|
||||
Homepage: vars.Homepage,
|
||||
License: strings.Join(vars.Licenses, ", "),
|
||||
Maintainer: vars.Maintainer,
|
||||
Overridables: nfpm.Overridables{
|
||||
Conflicts: vars.Conflicts,
|
||||
Replaces: vars.Replaces,
|
||||
Provides: vars.Provides,
|
||||
Depends: deps,
|
||||
},
|
||||
}
|
||||
|
||||
if vars.Epoch != 0 {
|
||||
pkgInfo.Epoch = strconv.FormatUint(uint64(vars.Epoch), 10)
|
||||
}
|
||||
|
||||
setScripts(vars, pkgInfo, dirs.ScriptDir)
|
||||
|
||||
if slices.Contains(vars.Architectures, "all") {
|
||||
pkgInfo.Arch = "all"
|
||||
}
|
||||
|
||||
contents, err := buildContents(vars, dirs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkgInfo.Overridables.Contents = contents
|
||||
|
||||
return pkgInfo, nil
|
||||
}
|
||||
|
||||
func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Content, error) {
|
||||
contents := []*files.Content{}
|
||||
err := filepath.Walk(dirs.PkgDir, func(path string, fi os.FileInfo, err error) error {
|
||||
trimmed := strings.TrimPrefix(path, dirs.PkgDir)
|
||||
|
||||
if fi.IsDir() {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Readdirnames(1)
|
||||
if err != io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
Type: "dir",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
},
|
||||
})
|
||||
|
||||
f.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
link, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
link = strings.TrimPrefix(link, dirs.PkgDir)
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: link,
|
||||
Destination: trimmed,
|
||||
Type: "symlink",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fileContent := &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
Size: fi.Size(),
|
||||
},
|
||||
}
|
||||
|
||||
if slices.Contains(vars.Backup, trimmed) {
|
||||
fileContent.Type = "config|noreplace"
|
||||
}
|
||||
|
||||
contents = append(contents, fileContent)
|
||||
|
||||
return nil
|
||||
})
|
||||
return contents, err
|
||||
}
|
||||
|
||||
func removeBuildDeps(buildDeps []string, opts types.BuildOpts) error {
|
||||
if len(buildDeps) > 0 {
|
||||
removeBuildDeps, err := cliutils.YesNoPrompt("Would you like to remove the build dependencies?", opts.Interactive, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if removeBuildDeps {
|
||||
err = opts.Manager.Remove(
|
||||
&manager.Opts{
|
||||
AsRoot: true,
|
||||
NoConfirm: true,
|
||||
},
|
||||
buildDeps...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkForBuiltPackage(mgr manager.Manager, vars *types.BuildVars, pkgFormat, baseDir string) (string, bool, error) {
|
||||
filename, err := pkgFileName(vars, pkgFormat)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
pkgPath := filepath.Join(baseDir, filename)
|
||||
|
||||
_, err = os.Stat(pkgPath)
|
||||
if err != nil {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return pkgPath, true, nil
|
||||
}
|
||||
|
||||
func pkgFileName(vars *types.BuildVars, pkgFormat string) (string, error) {
|
||||
pkgInfo := &nfpm.Info{
|
||||
Name: vars.Name,
|
||||
Arch: cpu.Arch(),
|
||||
Version: vars.Version,
|
||||
Release: strconv.Itoa(vars.Release),
|
||||
Epoch: strconv.FormatUint(uint64(vars.Epoch), 10),
|
||||
}
|
||||
|
||||
packager, err := nfpm.Get(pkgFormat)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return packager.ConventionalFileName(pkgInfo), nil
|
||||
}
|
||||
|
||||
func getPkgFormat(mgr manager.Manager) string {
|
||||
pkgFormat := mgr.Format()
|
||||
if format, ok := os.LookupEnv("LURE_PKG_FORMAT"); ok {
|
||||
pkgFormat = format
|
||||
}
|
||||
return pkgFormat
|
||||
}
|
||||
|
||||
func createBuildEnvVars(info *distro.OSRelease, dirs types.Directories) []string {
|
||||
env := os.Environ()
|
||||
|
||||
env = append(
|
||||
env,
|
||||
"DISTRO_NAME="+info.Name,
|
||||
"DISTRO_PRETTY_NAME="+info.PrettyName,
|
||||
"DISTRO_ID="+info.ID,
|
||||
"DISTRO_VERSION_ID="+info.VersionID,
|
||||
"DISTRO_ID_LIKE="+strings.Join(info.Like, " "),
|
||||
"ARCH="+cpu.Arch(),
|
||||
"NCPU="+strconv.Itoa(runtime.NumCPU()),
|
||||
)
|
||||
|
||||
if dirs.ScriptDir != "" {
|
||||
env = append(env, "scriptdir="+dirs.ScriptDir)
|
||||
}
|
||||
|
||||
if dirs.PkgDir != "" {
|
||||
env = append(env, "pkgdir="+dirs.PkgDir)
|
||||
}
|
||||
|
||||
if dirs.SrcDir != "" {
|
||||
env = append(env, "srcdir="+dirs.SrcDir)
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func getSources(ctx context.Context, srcdir string, bv *types.BuildVars) error {
|
||||
if len(bv.Sources) != len(bv.Checksums) {
|
||||
log.Fatal("The checksums array must be the same length as sources").Send()
|
||||
}
|
||||
|
||||
for i, src := range bv.Sources {
|
||||
opts := dl.Options{
|
||||
Name: fmt.Sprintf("%s[%d]", bv.Name, i),
|
||||
URL: src,
|
||||
Destination: srcdir,
|
||||
Progress: os.Stderr,
|
||||
}
|
||||
|
||||
if !strings.EqualFold(bv.Checksums[i], "SKIP") {
|
||||
algo, hashData, ok := strings.Cut(bv.Checksums[i], ":")
|
||||
if ok {
|
||||
checksum, err := hex.DecodeString(hashData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Hash = checksum
|
||||
opts.HashAlgorithm = algo
|
||||
} else {
|
||||
checksum, err := hex.DecodeString(bv.Checksums[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.Hash = checksum
|
||||
}
|
||||
}
|
||||
|
||||
err := dl.Download(ctx, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setScripts(vars *types.BuildVars, info *nfpm.Info, scriptDir string) {
|
||||
if vars.Scripts.PreInstall != "" {
|
||||
info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostInstall != "" {
|
||||
info.Scripts.PostInstall = filepath.Join(scriptDir, vars.Scripts.PostInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreRemove != "" {
|
||||
info.Scripts.PreRemove = filepath.Join(scriptDir, vars.Scripts.PreRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostRemove != "" {
|
||||
info.Scripts.PostRemove = filepath.Join(scriptDir, vars.Scripts.PostRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
info.APK.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
info.APK.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreTrans != "" {
|
||||
info.RPM.Scripts.PreTrans = filepath.Join(scriptDir, vars.Scripts.PreTrans)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostTrans != "" {
|
||||
info.RPM.Scripts.PostTrans = filepath.Join(scriptDir, vars.Scripts.PostTrans)
|
||||
}
|
||||
}
|
||||
|
||||
func setVersion(ctx context.Context, r *interp.Runner, to string) error {
|
||||
fl, err := syntax.NewParser().Parse(strings.NewReader("version='"+to+"'"), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Run(ctx, fl)
|
||||
}
|
||||
|
||||
// filterBuildDeps returns a map without any dependencies that are already installed
|
||||
func filterBuildDeps(found map[string][]db.Package, installed map[string]string) map[string][]db.Package {
|
||||
out := map[string][]db.Package{}
|
||||
for name, pkgs := range found {
|
||||
var inner []db.Package
|
||||
for _, pkg := range pkgs {
|
||||
if _, ok := installed[pkg.Name]; !ok {
|
||||
addToFiltered := true
|
||||
for _, provides := range pkg.Provides.Val {
|
||||
if _, ok := installed[provides]; ok {
|
||||
addToFiltered = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if addToFiltered {
|
||||
inner = append(inner, pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(inner) > 0 {
|
||||
out[name] = inner
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func packageNames(pkgs []db.Package) []string {
|
||||
names := make([]string, len(pkgs))
|
||||
for i, p := range pkgs {
|
||||
names[i] = p.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func removeDuplicates(slice []string) []string {
|
||||
seen := map[string]struct{}{}
|
||||
result := []string{}
|
||||
|
||||
for _, s := range slice {
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
69
internal/build/install.go
Normal file
69
internal/build/install.go
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Elara 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 build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
)
|
||||
|
||||
// InstallPkgs installs non-LURE packages via the package manager, then builds and installs LURE
|
||||
// packages
|
||||
func InstallPkgs(ctx context.Context, lurePkgs []db.Package, nativePkgs []string, opts types.BuildOpts) {
|
||||
if len(nativePkgs) > 0 {
|
||||
err := opts.Manager.Install(nil, nativePkgs...)
|
||||
if err != nil {
|
||||
log.Fatal("Error installing native packages").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
InstallScripts(ctx, GetScriptPaths(lurePkgs), opts)
|
||||
}
|
||||
|
||||
// GetScriptPaths generates a slice of script paths corresponding to the
|
||||
// given packages
|
||||
func GetScriptPaths(pkgs []db.Package) []string {
|
||||
var scripts []string
|
||||
for _, pkg := range pkgs {
|
||||
scriptPath := filepath.Join(config.GetPaths().RepoDir, pkg.Repository, pkg.Name, "lure.sh")
|
||||
scripts = append(scripts, scriptPath)
|
||||
}
|
||||
return scripts
|
||||
}
|
||||
|
||||
// InstallScripts builds and installs LURE build scripts
|
||||
func InstallScripts(ctx context.Context, scripts []string, opts types.BuildOpts) {
|
||||
for _, script := range scripts {
|
||||
opts.Script = script
|
||||
builtPkgs, _, err := BuildPackage(ctx, opts)
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).Send()
|
||||
}
|
||||
|
||||
err = opts.Manager.InstallLocal(nil, builtPkgs...)
|
||||
if err != nil {
|
||||
log.Fatal("Error installing package").Err(err).Send()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -20,22 +20,23 @@ package cliutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/pager"
|
||||
"go.elara.ws/translate"
|
||||
"go.elara.ws/lure/internal/translations"
|
||||
)
|
||||
|
||||
// YesNoPrompt asks the user a yes or no question, using def as the default answer
|
||||
func YesNoPrompt(msg string, interactive, def bool, t translate.Translator) (bool, error) {
|
||||
func YesNoPrompt(msg string, interactive, def bool) (bool, error) {
|
||||
if interactive {
|
||||
var answer bool
|
||||
err := survey.AskOne(
|
||||
&survey.Confirm{
|
||||
Message: t.TranslateTo(msg, config.Language),
|
||||
Message: translations.Translator().TranslateTo(msg, config.Language()),
|
||||
Default: def,
|
||||
},
|
||||
&answer,
|
||||
@@ -49,12 +50,13 @@ func YesNoPrompt(msg string, interactive, def bool, t translate.Translator) (boo
|
||||
// PromptViewScript asks the user if they'd like to see a script,
|
||||
// shows it if they answer yes, then asks if they'd still like to
|
||||
// continue, and exits if they answer no.
|
||||
func PromptViewScript(script, name, style string, interactive bool, t translate.Translator) error {
|
||||
func PromptViewScript(script, name, style string, interactive bool) error {
|
||||
if !interactive {
|
||||
return nil
|
||||
}
|
||||
|
||||
view, err := YesNoPrompt(t.TranslateTo("Would you like to view the build script for", config.Language)+" "+name, interactive, false, t)
|
||||
scriptPrompt := translations.Translator().TranslateTo("Would you like to view the build script for", config.Language()) + " " + name
|
||||
view, err := YesNoPrompt(scriptPrompt, interactive, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -65,13 +67,13 @@ func PromptViewScript(script, name, style string, interactive bool, t translate.
|
||||
return err
|
||||
}
|
||||
|
||||
cont, err := YesNoPrompt("Would you still like to continue?", interactive, false, t)
|
||||
cont, err := YesNoPrompt("Would you still like to continue?", interactive, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !cont {
|
||||
log.Fatal(t.TranslateTo("User chose not to continue after reading script", config.Language)).Send()
|
||||
log.Fatal(translations.Translator().TranslateTo("User chose not to continue after reading script", config.Language())).Send()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,15 +100,15 @@ func ShowScript(path, name, style string) error {
|
||||
|
||||
// FlattenPkgs attempts to flatten the a map of slices of packages into a single slice
|
||||
// of packages by prompting the user if multiple packages match.
|
||||
func FlattenPkgs(found map[string][]db.Package, verb string, interactive bool, t translate.Translator) []db.Package {
|
||||
func FlattenPkgs(found map[string][]db.Package, verb string, interactive bool) []db.Package {
|
||||
var outPkgs []db.Package
|
||||
for _, pkgs := range found {
|
||||
if len(pkgs) > 1 && interactive {
|
||||
choices, err := PkgPrompt(pkgs, verb, interactive, t)
|
||||
choice, err := PkgPrompt(pkgs, verb, interactive)
|
||||
if err != nil {
|
||||
log.Fatal("Error prompting for choice of package").Send()
|
||||
}
|
||||
outPkgs = append(outPkgs, choices...)
|
||||
outPkgs = append(outPkgs, choice)
|
||||
} else if len(pkgs) == 1 || !interactive {
|
||||
outPkgs = append(outPkgs, pkgs[0])
|
||||
}
|
||||
@@ -115,10 +117,9 @@ func FlattenPkgs(found map[string][]db.Package, verb string, interactive bool, t
|
||||
}
|
||||
|
||||
// PkgPrompt asks the user to choose between multiple packages.
|
||||
// The user may choose multiple packages.
|
||||
func PkgPrompt(options []db.Package, verb string, interactive bool, t translate.Translator) ([]db.Package, error) {
|
||||
func PkgPrompt(options []db.Package, verb string, interactive bool) (db.Package, error) {
|
||||
if !interactive {
|
||||
return []db.Package{options[0]}, nil
|
||||
return options[0], nil
|
||||
}
|
||||
|
||||
names := make([]string, len(options))
|
||||
@@ -126,9 +127,30 @@ func PkgPrompt(options []db.Package, verb string, interactive bool, t translate.
|
||||
names[i] = option.Repository + "/" + option.Name + " " + option.Version
|
||||
}
|
||||
|
||||
prompt := &survey.MultiSelect{
|
||||
prompt := &survey.Select{
|
||||
Options: names,
|
||||
Message: t.TranslateTo("Choose which package(s) to "+verb, config.Language),
|
||||
Message: translations.Translator().TranslateTo("Choose which package to "+verb, config.Language()),
|
||||
}
|
||||
|
||||
var choice int
|
||||
err := survey.AskOne(prompt, &choice)
|
||||
if err != nil {
|
||||
return db.Package{}, err
|
||||
}
|
||||
|
||||
return options[choice], nil
|
||||
}
|
||||
|
||||
// ChooseOptDepends asks the user to choose between multiple optional dependencies.
|
||||
// The user may choose multiple items.
|
||||
func ChooseOptDepends(options []string, verb string, interactive bool) ([]string, error) {
|
||||
if !interactive {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
prompt := &survey.MultiSelect{
|
||||
Options: options,
|
||||
Message: translations.Translator().TranslateTo("Choose which optional package(s) to install", config.Language()),
|
||||
}
|
||||
|
||||
var choices []int
|
||||
@@ -137,9 +159,9 @@ func PkgPrompt(options []db.Package, verb string, interactive bool, t translate.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make([]db.Package, len(choices))
|
||||
out := make([]string, len(choices))
|
||||
for i, choiceIndex := range choices {
|
||||
out[i] = options[choiceIndex]
|
||||
out[i], _, _ = strings.Cut(options[choiceIndex], ": ")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,10 +22,11 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
)
|
||||
|
||||
var defaultConfig = types.Config{
|
||||
var defaultConfig = &types.Config{
|
||||
RootCmd: "sudo",
|
||||
PagerStyle: "native",
|
||||
IgnorePkgUpdates: []string{},
|
||||
@@ -37,18 +38,30 @@ var defaultConfig = types.Config{
|
||||
},
|
||||
}
|
||||
|
||||
// Decode decodes the config file into the given
|
||||
// pointer
|
||||
func Decode(cfg *types.Config) error {
|
||||
cfgFl, err := os.Open(ConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cfgFl.Close()
|
||||
var config *types.Config
|
||||
|
||||
// Write defaults to pointer in case some values are not set in the config
|
||||
*cfg = defaultConfig
|
||||
// Set repos to nil so as to avoid a duplicate default
|
||||
cfg.Repos = nil
|
||||
return toml.NewDecoder(cfgFl).Decode(cfg)
|
||||
func Config() *types.Config {
|
||||
if config == nil {
|
||||
cfgFl, err := os.Open(GetPaths().ConfigPath)
|
||||
if err != nil {
|
||||
log.Warn("Error opening config file, using defaults").Err(err).Send()
|
||||
return defaultConfig
|
||||
}
|
||||
defer cfgFl.Close()
|
||||
|
||||
// Copy the default configuration into config
|
||||
defCopy := *defaultConfig
|
||||
config = &defCopy
|
||||
config.Repos = nil
|
||||
|
||||
err = toml.NewDecoder(cfgFl).Decode(config)
|
||||
if err != nil {
|
||||
log.Warn("Error decoding config file, using defaults").Err(err).Send()
|
||||
// Set config back to nil so that we try again next time
|
||||
config = nil
|
||||
return defaultConfig
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -23,72 +23,72 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
)
|
||||
|
||||
var (
|
||||
type Paths struct {
|
||||
ConfigDir string
|
||||
ConfigPath string
|
||||
CacheDir string
|
||||
RepoDir string
|
||||
PkgsDir string
|
||||
DBPath string
|
||||
)
|
||||
|
||||
// DBPresent is true if the database
|
||||
// was present when LURE was started
|
||||
var DBPresent bool
|
||||
|
||||
func init() {
|
||||
cfgDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to detect user config directory").Err(err).Send()
|
||||
}
|
||||
|
||||
ConfigDir = filepath.Join(cfgDir, "lure")
|
||||
|
||||
err = os.MkdirAll(ConfigDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create LURE config directory").Err(err).Send()
|
||||
}
|
||||
|
||||
ConfigPath = filepath.Join(ConfigDir, "lure.toml")
|
||||
|
||||
if _, err := os.Stat(ConfigPath); err != nil {
|
||||
cfgFl, err := os.Create(ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create LURE config file").Err(err).Send()
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding default configuration").Err(err).Send()
|
||||
}
|
||||
|
||||
cfgFl.Close()
|
||||
}
|
||||
|
||||
cacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to detect cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
CacheDir = filepath.Join(cacheDir, "lure")
|
||||
RepoDir = filepath.Join(CacheDir, "repo")
|
||||
PkgsDir = filepath.Join(CacheDir, "pkgs")
|
||||
|
||||
err = os.MkdirAll(RepoDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create repo cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
err = os.MkdirAll(PkgsDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create package cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
DBPath = filepath.Join(CacheDir, "db")
|
||||
|
||||
fi, err := os.Stat(DBPath)
|
||||
DBPresent = err == nil && !fi.IsDir()
|
||||
}
|
||||
|
||||
var paths *Paths
|
||||
|
||||
func GetPaths() *Paths {
|
||||
if paths == nil {
|
||||
paths = &Paths{}
|
||||
|
||||
cfgDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to detect user config directory").Err(err).Send()
|
||||
}
|
||||
|
||||
paths.ConfigDir = filepath.Join(cfgDir, "lure")
|
||||
|
||||
err = os.MkdirAll(paths.ConfigDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create LURE config directory").Err(err).Send()
|
||||
}
|
||||
|
||||
paths.ConfigPath = filepath.Join(paths.ConfigDir, "lure.toml")
|
||||
|
||||
if _, err := os.Stat(paths.ConfigPath); err != nil {
|
||||
cfgFl, err := os.Create(paths.ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create LURE config file").Err(err).Send()
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding default configuration").Err(err).Send()
|
||||
}
|
||||
|
||||
cfgFl.Close()
|
||||
}
|
||||
|
||||
cacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to detect cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
paths.CacheDir = filepath.Join(cacheDir, "lure")
|
||||
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
|
||||
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
|
||||
|
||||
err = os.MkdirAll(paths.RepoDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create repo cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
err = os.MkdirAll(paths.PkgsDir, 0o755)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create package cache directory").Err(err).Send()
|
||||
}
|
||||
|
||||
paths.DBPath = filepath.Join(paths.CacheDir, "db")
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,20 +22,27 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var Language language.Tag
|
||||
var (
|
||||
lang language.Tag
|
||||
langSet bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
lang := SystemLang()
|
||||
tag, err := language.Parse(lang)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing system language").Err(err).Send()
|
||||
func Language() language.Tag {
|
||||
if !langSet {
|
||||
syslang := SystemLang()
|
||||
tag, err := language.Parse(syslang)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing system language").Err(err).Send()
|
||||
}
|
||||
base, _ := tag.Base()
|
||||
lang = language.Make(base.String())
|
||||
langSet = true
|
||||
}
|
||||
base, _ := tag.Base()
|
||||
Language = language.Make(base.String())
|
||||
return lang
|
||||
}
|
||||
|
||||
func SystemLang() string {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -20,5 +20,7 @@ package config
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:generate ../../scripts/gen-version.sh
|
||||
|
||||
//go:embed version.txt
|
||||
var Version string
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -21,14 +21,15 @@ package cpu
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
// ARMVariant checks which variant of ARM lure is running
|
||||
// armVariant checks which variant of ARM lure is running
|
||||
// on, by using the same detection method as Go itself
|
||||
func ARMVariant() string {
|
||||
func armVariant() string {
|
||||
armEnv := os.Getenv("LURE_ARM_VARIANT")
|
||||
// ensure value has "arm" prefix, such as arm5 or arm6
|
||||
if strings.HasPrefix(armEnv, "arm") {
|
||||
@@ -46,9 +47,70 @@ func ARMVariant() string {
|
||||
|
||||
// Arch returns the canonical CPU architecture of the system
|
||||
func Arch() string {
|
||||
arch := runtime.GOARCH
|
||||
arch := os.Getenv("LURE_ARCH")
|
||||
if arch == "" {
|
||||
arch = runtime.GOARCH
|
||||
}
|
||||
if arch == "arm" {
|
||||
arch = ARMVariant()
|
||||
arch = armVariant()
|
||||
}
|
||||
return arch
|
||||
}
|
||||
|
||||
func IsCompatibleWith(target string, list []string) bool {
|
||||
if target == "all" {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, arch := range list {
|
||||
if strings.HasPrefix(target, "arm") && strings.HasPrefix(arch, "arm") {
|
||||
targetVer, err := getARMVersion(target)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
archVer, err := getARMVersion(arch)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if targetVer >= archVer {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if target == arch {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func CompatibleArches(arch string) ([]string, error) {
|
||||
if strings.HasPrefix(arch, "arm") {
|
||||
ver, err := getARMVersion(arch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ver > 5 {
|
||||
var out []string
|
||||
for i := ver; i >= 5; i-- {
|
||||
out = append(out, "arm"+strconv.Itoa(i))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
return []string{arch}, nil
|
||||
}
|
||||
|
||||
func getARMVersion(arch string) (int, error) {
|
||||
// Extract the version number from ARM architecture
|
||||
version := strings.TrimPrefix(arch, "arm")
|
||||
if version == "" {
|
||||
return 5, nil // Default to arm5 if version is not specified
|
||||
}
|
||||
return strconv.Atoi(version)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -24,16 +24,15 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"golang.org/x/exp/slices"
|
||||
"modernc.org/sqlite"
|
||||
)
|
||||
|
||||
const CurrentVersion = 1
|
||||
const CurrentVersion = 2
|
||||
|
||||
func init() {
|
||||
sqlite.MustRegisterScalarFunction("json_array_contains", 2, JsonArrayContains)
|
||||
@@ -55,6 +54,7 @@ type Package struct {
|
||||
Replaces JSON[[]string] `sh:"replaces" db:"replaces"`
|
||||
Depends JSON[map[string][]string] `db:"depends"`
|
||||
BuildDepends JSON[map[string][]string] `db:"builddepends"`
|
||||
OptDepends JSON[map[string][]string] `db:"optdepends"`
|
||||
Repository string `db:"repository"`
|
||||
}
|
||||
|
||||
@@ -62,40 +62,52 @@ type version struct {
|
||||
Version int `db:"version"`
|
||||
}
|
||||
|
||||
func Open(dsn string) (*sqlx.DB, error) {
|
||||
if dsn != ":memory:" {
|
||||
fi, err := os.Stat(config.DBPath)
|
||||
if err == nil {
|
||||
// TODO: This should be removed by the first stable release.
|
||||
if fi.IsDir() {
|
||||
log.Warn("Your database is using the old database engine; rebuilding").Send()
|
||||
var (
|
||||
conn *sqlx.DB
|
||||
closed = true
|
||||
)
|
||||
|
||||
err = os.RemoveAll(config.DBPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error removing old database").Err(err).Send()
|
||||
}
|
||||
config.DBPresent = false
|
||||
}
|
||||
}
|
||||
func DB() *sqlx.DB {
|
||||
if conn != nil && !closed {
|
||||
return conn
|
||||
}
|
||||
|
||||
db, err := sqlx.Open("sqlite", dsn)
|
||||
db, err := Open(config.GetPaths().DBPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening database").Err(err).Send()
|
||||
}
|
||||
conn = db
|
||||
return conn
|
||||
}
|
||||
|
||||
err = Init(db, dsn)
|
||||
func Open(dsn string) (*sqlx.DB, error) {
|
||||
db, err := sqlx.Open("sqlite", dsn)
|
||||
if err != nil {
|
||||
log.Fatal("Error initializing database").Err(err).Send()
|
||||
return nil, err
|
||||
}
|
||||
conn = db
|
||||
closed = false
|
||||
|
||||
err = initDB(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
closed = true
|
||||
if conn != nil {
|
||||
return conn.Close()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the database
|
||||
func Init(db *sqlx.DB, dsn string) error {
|
||||
*db = *db.Unsafe()
|
||||
_, err := db.Exec(`
|
||||
func initDB(dsn string) error {
|
||||
conn = conn.Unsafe()
|
||||
_, err := conn.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS pkgs (
|
||||
name TEXT NOT NULL,
|
||||
repository TEXT NOT NULL,
|
||||
@@ -112,6 +124,7 @@ func Init(db *sqlx.DB, dsn string) error {
|
||||
replaces TEXT CHECK(replaces = 'null' OR (JSON_VALID(replaces) AND JSON_TYPE(replaces) = 'array')),
|
||||
depends TEXT CHECK(depends = 'null' OR (JSON_VALID(depends) AND JSON_TYPE(depends) = 'object')),
|
||||
builddepends TEXT CHECK(builddepends = 'null' OR (JSON_VALID(builddepends) AND JSON_TYPE(builddepends) = 'object')),
|
||||
optdepends TEXT CHECK(optdepends = 'null' OR (JSON_VALID(optdepends) AND JSON_TYPE(optdepends) = 'object')),
|
||||
UNIQUE(name, repository)
|
||||
);
|
||||
|
||||
@@ -123,49 +136,54 @@ func Init(db *sqlx.DB, dsn string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ver, ok := GetVersion(db)
|
||||
if !ok {
|
||||
ver, ok := GetVersion()
|
||||
if ok && ver != CurrentVersion {
|
||||
log.Warn("Database version mismatch; resetting").Int("version", ver).Int("expected", CurrentVersion).Send()
|
||||
Reset()
|
||||
return initDB(dsn)
|
||||
} else if !ok {
|
||||
log.Warn("Database version does not exist. Run lure fix if something isn't working.").Send()
|
||||
return addVersion(db, CurrentVersion)
|
||||
}
|
||||
|
||||
if ver != CurrentVersion {
|
||||
log.Warn("Database version mismatch; rebuilding").Int("version", ver).Int("expected", CurrentVersion).Send()
|
||||
|
||||
db.Close()
|
||||
err = os.Remove(config.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.DBPresent = false
|
||||
|
||||
tdb, err := Open(dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*db = *tdb
|
||||
return addVersion(CurrentVersion)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetVersion(db *sqlx.DB) (int, bool) {
|
||||
func Reset() error {
|
||||
_, err := DB().Exec("DROP TABLE IF EXISTS pkgs;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = DB().Exec("DROP TABLE IF EXISTS lure_db_version;")
|
||||
return err
|
||||
}
|
||||
|
||||
func IsEmpty() bool {
|
||||
var count int
|
||||
err := DB().Get(&count, "SELECT count(1) FROM pkgs;")
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return count == 0
|
||||
}
|
||||
|
||||
func GetVersion() (int, bool) {
|
||||
var ver version
|
||||
err := db.Get(&ver, "SELECT * FROM lure_db_version LIMIT 1;")
|
||||
err := DB().Get(&ver, "SELECT * FROM lure_db_version LIMIT 1;")
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return ver.Version, true
|
||||
}
|
||||
|
||||
func addVersion(db *sqlx.DB, ver int) error {
|
||||
_, err := db.Exec(`INSERT INTO lure_db_version(version) VALUES (?);`, ver)
|
||||
func addVersion(ver int) error {
|
||||
_, err := DB().Exec(`INSERT INTO lure_db_version(version) VALUES (?);`, ver)
|
||||
return err
|
||||
}
|
||||
|
||||
// InsertPackage adds a package to the database
|
||||
func InsertPackage(db *sqlx.DB, pkg Package) error {
|
||||
_, err := db.NamedExec(`
|
||||
func InsertPackage(pkg Package) error {
|
||||
_, err := DB().NamedExec(`
|
||||
INSERT OR REPLACE INTO pkgs (
|
||||
name,
|
||||
repository,
|
||||
@@ -181,7 +199,8 @@ func InsertPackage(db *sqlx.DB, pkg Package) error {
|
||||
conflicts,
|
||||
replaces,
|
||||
depends,
|
||||
builddepends
|
||||
builddepends,
|
||||
optdepends
|
||||
) VALUES (
|
||||
:name,
|
||||
:repository,
|
||||
@@ -197,15 +216,16 @@ func InsertPackage(db *sqlx.DB, pkg Package) error {
|
||||
:conflicts,
|
||||
:replaces,
|
||||
:depends,
|
||||
:builddepends
|
||||
:builddepends,
|
||||
:optdepends
|
||||
);
|
||||
`, pkg)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetPkgs returns a result containing packages that match the where conditions
|
||||
func GetPkgs(db *sqlx.DB, where string, args ...any) (*sqlx.Rows, error) {
|
||||
stream, err := db.Queryx("SELECT * FROM pkgs WHERE "+where, args...)
|
||||
func GetPkgs(where string, args ...any) (*sqlx.Rows, error) {
|
||||
stream, err := DB().Queryx("SELECT * FROM pkgs WHERE "+where, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -213,15 +233,15 @@ func GetPkgs(db *sqlx.DB, where string, args ...any) (*sqlx.Rows, error) {
|
||||
}
|
||||
|
||||
// GetPkg returns a single package that match the where conditions
|
||||
func GetPkg(db *sqlx.DB, where string, args ...any) (*Package, error) {
|
||||
func GetPkg(where string, args ...any) (*Package, error) {
|
||||
out := &Package{}
|
||||
err := db.Get(out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
|
||||
err := DB().Get(out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// DeletePkgs deletes all packages matching the where conditions
|
||||
func DeletePkgs(db *sqlx.DB, where string, args ...any) error {
|
||||
_, err := db.Exec("DELETE FROM pkgs WHERE "+where, args...)
|
||||
func DeletePkgs(where string, args ...any) error {
|
||||
_, err := DB().Exec("DELETE FROM pkgs WHERE "+where, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -37,11 +37,11 @@ var testPkg = db.Package{
|
||||
"ru": "Проверочный пакет",
|
||||
}),
|
||||
Homepage: db.NewJSON(map[string]string{
|
||||
"en": "https://lure.arsenm.dev",
|
||||
"en": "https://lure.elara.ws/",
|
||||
}),
|
||||
Maintainer: db.NewJSON(map[string]string{
|
||||
"en": "Arsen Musayelyan <arsen@arsenm.dev>",
|
||||
"ru": "Арсен Мусаелян <arsen@arsenm.dev>",
|
||||
"en": "Elara Musayelyan <elara@elara.ws>",
|
||||
"ru": "Элара Мусаелян <arsen@arsenm.dev>",
|
||||
}),
|
||||
Architectures: db.NewJSON([]string{"arm64", "amd64"}),
|
||||
Licenses: db.NewJSON([]string{"GPL-3.0-or-later"}),
|
||||
@@ -59,23 +59,18 @@ var testPkg = db.Package{
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
gdb, err := sqlx.Open("sqlite", ":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
err = db.Init(gdb, ":memory:")
|
||||
_, err = db.DB().Exec("SELECT * FROM pkgs")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
_, err = gdb.Exec("SELECT * FROM pkgs")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
ver, ok := db.GetVersion(gdb)
|
||||
ver, ok := db.GetVersion()
|
||||
if !ok {
|
||||
t.Errorf("Expected version to be present")
|
||||
} else if ver != db.CurrentVersion {
|
||||
@@ -84,19 +79,19 @@ func TestInit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInsertPackage(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
err = db.InsertPackage(gdb, testPkg)
|
||||
err = db.InsertPackage(testPkg)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
dbPkg := db.Package{}
|
||||
err = sqlx.Get(gdb, &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'")
|
||||
err = sqlx.Get(db.DB(), &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
@@ -107,28 +102,28 @@ func TestInsertPackage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetPkgs(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
x1 := testPkg
|
||||
x1.Name = "x1"
|
||||
x2 := testPkg
|
||||
x2.Name = "x2"
|
||||
|
||||
err = db.InsertPackage(gdb, x1)
|
||||
err = db.InsertPackage(x1)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.InsertPackage(gdb, x2)
|
||||
err = db.InsertPackage(x2)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(gdb, "name LIKE 'x%'")
|
||||
result, err := db.GetPkgs("name LIKE 'x%'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
@@ -147,28 +142,28 @@ func TestGetPkgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetPkg(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
x1 := testPkg
|
||||
x1.Name = "x1"
|
||||
x2 := testPkg
|
||||
x2.Name = "x2"
|
||||
|
||||
err = db.InsertPackage(gdb, x1)
|
||||
err = db.InsertPackage(x1)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.InsertPackage(gdb, x2)
|
||||
err = db.InsertPackage(x2)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
pkg, err := db.GetPkg(gdb, "name LIKE 'x%' ORDER BY name")
|
||||
pkg, err := db.GetPkg("name LIKE 'x%' ORDER BY name")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
@@ -183,34 +178,34 @@ func TestGetPkg(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDeletePkgs(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
x1 := testPkg
|
||||
x1.Name = "x1"
|
||||
x2 := testPkg
|
||||
x2.Name = "x2"
|
||||
|
||||
err = db.InsertPackage(gdb, x1)
|
||||
err = db.InsertPackage(x1)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.InsertPackage(gdb, x2)
|
||||
err = db.InsertPackage(x2)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.DeletePkgs(gdb, "name = 'x1'")
|
||||
err = db.DeletePkgs("name = 'x1'")
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
var dbPkg db.Package
|
||||
err = gdb.Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
|
||||
err = db.DB().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
@@ -221,11 +216,11 @@ func TestDeletePkgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJsonArrayContains(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
x1 := testPkg
|
||||
x1.Name = "x1"
|
||||
@@ -233,18 +228,18 @@ func TestJsonArrayContains(t *testing.T) {
|
||||
x2.Name = "x2"
|
||||
x2.Provides.Val = append(x2.Provides.Val, "x")
|
||||
|
||||
err = db.InsertPackage(gdb, x1)
|
||||
err = db.InsertPackage(x1)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.InsertPackage(gdb, x2)
|
||||
err = db.InsertPackage(x2)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
var dbPkg db.Package
|
||||
err = gdb.Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');")
|
||||
err = db.DB().Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,27 +22,39 @@ package dl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/purell"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/dlcache"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const manifestFileName = ".lure_cache_manifest"
|
||||
|
||||
// ErrChecksumMismatch occurs when the checksum of a downloaded file
|
||||
// does not match the expected checksum provided in the Options struct.
|
||||
var ErrChecksumMismatch = errors.New("dl: checksums did not match")
|
||||
var (
|
||||
ErrChecksumMismatch = errors.New("dl: checksums did not match")
|
||||
ErrNoSuchHashAlgo = errors.New("dl: invalid hashing algorithm")
|
||||
)
|
||||
|
||||
// Downloaders contains all the downloaders in the order in which
|
||||
// they should be checked
|
||||
var Downloaders = []Downloader{
|
||||
GitDownloader{},
|
||||
TorrentDownloader{},
|
||||
FileDownloader{},
|
||||
}
|
||||
|
||||
@@ -67,7 +79,8 @@ func (t Type) String() string {
|
||||
// Options contains the options for downloading
|
||||
// files and directories
|
||||
type Options struct {
|
||||
SHA256 []byte
|
||||
Hash []byte
|
||||
HashAlgorithm string
|
||||
Name string
|
||||
URL string
|
||||
Destination string
|
||||
@@ -76,6 +89,27 @@ type Options struct {
|
||||
Progress io.Writer
|
||||
}
|
||||
|
||||
func (opts Options) NewHash() (hash.Hash, error) {
|
||||
if opts.HashAlgorithm == "" {
|
||||
opts.HashAlgorithm = "sha256"
|
||||
}
|
||||
switch opts.HashAlgorithm {
|
||||
case "sha256":
|
||||
return sha256.New(), nil
|
||||
case "sha224":
|
||||
return sha256.New224(), nil
|
||||
case "sha512":
|
||||
return sha512.New(), nil
|
||||
case "sha384":
|
||||
return sha512.New384(), nil
|
||||
case "sha1":
|
||||
return sha1.New(), nil
|
||||
case "md5":
|
||||
return md5.New(), nil
|
||||
}
|
||||
return nil, fmt.Errorf("%w: %s", ErrNoSuchHashAlgo, opts.HashAlgorithm)
|
||||
}
|
||||
|
||||
// Manifest holds information about the type and name
|
||||
// of a downloaded file or directory. It is stored inside
|
||||
// each cache directory for later use.
|
||||
@@ -141,10 +175,12 @@ func Download(ctx context.Context, opts Options) (err error) {
|
||||
log.Info("Source can be updated, updating if required").Str("source", opts.Name).Str("downloader", d.Name()).Send()
|
||||
|
||||
updated, err = d.Update(Options{
|
||||
Name: opts.Name,
|
||||
URL: opts.URL,
|
||||
Destination: cacheDir,
|
||||
Progress: opts.Progress,
|
||||
Hash: opts.Hash,
|
||||
HashAlgorithm: opts.HashAlgorithm,
|
||||
Name: opts.Name,
|
||||
URL: opts.URL,
|
||||
Destination: cacheDir,
|
||||
Progress: opts.Progress,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -156,7 +192,7 @@ func Download(ctx context.Context, opts Options) (err error) {
|
||||
t = m.Type
|
||||
|
||||
dest := filepath.Join(opts.Destination, m.Name)
|
||||
ok, err := handleCache(cacheDir, dest, t)
|
||||
ok, err := handleCache(cacheDir, dest, m.Name, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -186,10 +222,12 @@ func Download(ctx context.Context, opts Options) (err error) {
|
||||
}
|
||||
|
||||
t, name, err := d.Download(Options{
|
||||
Name: opts.Name,
|
||||
URL: opts.URL,
|
||||
Destination: cacheDir,
|
||||
Progress: opts.Progress,
|
||||
Hash: opts.Hash,
|
||||
HashAlgorithm: opts.HashAlgorithm,
|
||||
Name: opts.Name,
|
||||
URL: opts.URL,
|
||||
Destination: cacheDir,
|
||||
Progress: opts.Progress,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -201,7 +239,7 @@ func Download(ctx context.Context, opts Options) (err error) {
|
||||
}
|
||||
|
||||
dest := filepath.Join(opts.Destination, name)
|
||||
_, err = handleCache(cacheDir, dest, t)
|
||||
_, err = handleCache(cacheDir, dest, name, t)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -228,7 +266,7 @@ func getManifest(cacheDir string) (m Manifest, err error) {
|
||||
}
|
||||
|
||||
// handleCache links the cache directory or a file within it to the destination
|
||||
func handleCache(cacheDir, dest string, t Type) (bool, error) {
|
||||
func handleCache(cacheDir, dest, name string, t Type) (bool, error) {
|
||||
switch t {
|
||||
case TypeFile:
|
||||
cd, err := os.Open(cacheDir)
|
||||
@@ -236,7 +274,7 @@ func handleCache(cacheDir, dest string, t Type) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
names, err := cd.Readdirnames(2)
|
||||
names, err := cd.Readdirnames(0)
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
@@ -245,17 +283,13 @@ func handleCache(cacheDir, dest string, t Type) (bool, error) {
|
||||
|
||||
cd.Close()
|
||||
|
||||
for _, name := range names {
|
||||
if name == manifestFileName {
|
||||
continue
|
||||
}
|
||||
|
||||
err = os.Link(filepath.Join(cacheDir, names[0]), filepath.Join(dest, filepath.Base(names[0])))
|
||||
if slices.Contains(names, name) {
|
||||
err = os.Link(filepath.Join(cacheDir, name), dest)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return true, nil
|
||||
case TypeDir:
|
||||
err := linkDir(cacheDir, dest)
|
||||
if err != nil {
|
||||
@@ -321,5 +355,12 @@ func normalizeURL(u string) (string, error) {
|
||||
purell.FlagDecodeUnnecessaryEscapes |
|
||||
purell.FlagRemoveEmptyPortSeparator
|
||||
|
||||
return purell.NormalizeURLString(u, normalizationFlags)
|
||||
u, err := purell.NormalizeURLString(u, normalizationFlags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Fix magnet URLs after normalization
|
||||
u = strings.Replace(u, "magnet://", "magnet:", 1)
|
||||
return u, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -21,7 +21,6 @@ package dl
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -109,10 +108,13 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
|
||||
bar = shutils.NopRWC{}
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
h, err := opts.NewHash()
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
var w io.Writer
|
||||
if opts.SHA256 != nil {
|
||||
if opts.Hash != nil {
|
||||
w = io.MultiWriter(fl, h, bar)
|
||||
} else {
|
||||
w = io.MultiWriter(fl, bar)
|
||||
@@ -124,15 +126,15 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
if opts.SHA256 != nil {
|
||||
if opts.Hash != nil {
|
||||
sum := h.Sum(nil)
|
||||
if !bytes.Equal(sum, opts.SHA256) {
|
||||
if !bytes.Equal(sum, opts.Hash) {
|
||||
return 0, "", ErrChecksumMismatch
|
||||
}
|
||||
}
|
||||
|
||||
if opts.PostprocDisabled {
|
||||
return TypeFile, "", nil
|
||||
return TypeFile, name, nil
|
||||
}
|
||||
|
||||
_, err = fl.Seek(0, io.SeekStart)
|
||||
@@ -142,7 +144,7 @@ func (FileDownloader) Download(opts Options) (Type, string, error) {
|
||||
|
||||
format, r, err := archiver.Identify(name, fl)
|
||||
if err == archiver.ErrNoMatch {
|
||||
return TypeFile, "", nil
|
||||
return TypeFile, name, nil
|
||||
} else if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
90
internal/dl/torrent.go
Normal file
90
internal/dl/torrent.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package dl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
urlMatchRegex = regexp.MustCompile(`(magnet|torrent\+https?):.*`)
|
||||
ErrAria2NotFound = errors.New("aria2 must be installed for torrent functionality")
|
||||
ErrDestinationEmpty = errors.New("the destination directory is empty")
|
||||
)
|
||||
|
||||
type TorrentDownloader struct{}
|
||||
|
||||
// Name always returns "file"
|
||||
func (TorrentDownloader) Name() string {
|
||||
return "torrent"
|
||||
}
|
||||
|
||||
// MatchURL returns true if the URL is a magnet link
|
||||
// or an http(s) link with a "torrent+" prefix
|
||||
func (TorrentDownloader) MatchURL(u string) bool {
|
||||
return urlMatchRegex.MatchString(u)
|
||||
}
|
||||
|
||||
// Download downloads a file over the BitTorrent protocol.
|
||||
func (TorrentDownloader) Download(opts Options) (Type, string, error) {
|
||||
aria2Path, err := exec.LookPath("aria2c")
|
||||
if err != nil {
|
||||
return 0, "", ErrAria2NotFound
|
||||
}
|
||||
|
||||
opts.URL = strings.TrimPrefix(opts.URL, "torrent+")
|
||||
|
||||
cmd := exec.Command(aria2Path, "--summary-interval=0", "--log-level=warn", "--seed-time=0", "--dir="+opts.Destination, opts.URL)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return 0, "", fmt.Errorf("aria2c returned an error: %w", err)
|
||||
}
|
||||
|
||||
err = removeTorrentFiles(opts.Destination)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
return determineType(opts.Destination)
|
||||
}
|
||||
|
||||
func removeTorrentFiles(path string) error {
|
||||
filePaths, err := filepath.Glob(filepath.Join(path, "*.torrent"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, filePath := range filePaths {
|
||||
err = os.Remove(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func determineType(path string) (Type, string, error) {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
if len(files) > 1 {
|
||||
return TypeDir, "", nil
|
||||
} else if len(files) == 1 {
|
||||
if files[0].IsDir() {
|
||||
return TypeDir, files[0].Name(), nil
|
||||
} else {
|
||||
return TypeFile, files[0].Name(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, "", ErrDestinationEmpty
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -28,8 +28,10 @@ import (
|
||||
"go.elara.ws/lure/internal/config"
|
||||
)
|
||||
|
||||
// BasePath stores the base path to the download cache
|
||||
var BasePath = filepath.Join(config.CacheDir, "dl")
|
||||
// BasePath returns the base path of the download cache
|
||||
func BasePath() string {
|
||||
return filepath.Join(config.GetPaths().RepoDir, "dl")
|
||||
}
|
||||
|
||||
// New creates a new directory with the given ID in the cache.
|
||||
// If a directory with the same ID already exists,
|
||||
@@ -39,7 +41,7 @@ func New(id string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
itemPath := filepath.Join(BasePath, h)
|
||||
itemPath := filepath.Join(BasePath(), h)
|
||||
|
||||
fi, err := os.Stat(itemPath)
|
||||
if err == nil || (fi != nil && !fi.IsDir()) {
|
||||
@@ -67,7 +69,7 @@ func Get(id string) (string, bool) {
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
itemPath := filepath.Join(BasePath, h)
|
||||
itemPath := filepath.Join(BasePath(), h)
|
||||
|
||||
_, err = os.Stat(itemPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/dlcache"
|
||||
)
|
||||
|
||||
@@ -34,7 +35,7 @@ func init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dlcache.BasePath = dir
|
||||
config.GetPaths().RepoDir = dir
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@@ -44,7 +45,7 @@ func TestNew(t *testing.T) {
|
||||
t.Errorf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
exp := filepath.Join(dlcache.BasePath, sha1sum(id))
|
||||
exp := filepath.Join(dlcache.BasePath(), sha1sum(id))
|
||||
if dir != exp {
|
||||
t.Errorf("Expected %s, got %s", exp, dir)
|
||||
}
|
||||
|
||||
102
internal/log/log.go
Normal file
102
internal/log/log.go
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Elara 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 log
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"go.elara.ws/logger"
|
||||
)
|
||||
|
||||
var Logger logger.Logger = logger.NewCLI(os.Stderr)
|
||||
|
||||
// NoPanic prevents the logger from panicking on panic events
|
||||
func NoPanic() {
|
||||
Logger.NoPanic()
|
||||
}
|
||||
|
||||
// NoExit prevents the logger from exiting on fatal events
|
||||
func NoExit() {
|
||||
Logger.NoExit()
|
||||
}
|
||||
|
||||
// SetLevel sets the log level of the logger
|
||||
func SetLevel(l logger.LogLevel) {
|
||||
Logger.SetLevel(l)
|
||||
}
|
||||
|
||||
// Debug creates a new debug event with the given message
|
||||
func Debug(msg string) logger.LogBuilder {
|
||||
return Logger.Debug(msg)
|
||||
}
|
||||
|
||||
// Debugf creates a new debug event with the formatted message
|
||||
func Debugf(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
// Info creates a new info event with the given message
|
||||
func Info(msg string) logger.LogBuilder {
|
||||
return Logger.Info(msg)
|
||||
}
|
||||
|
||||
// Infof creates a new info event with the formatted message
|
||||
func Infof(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Infof(format, v...)
|
||||
}
|
||||
|
||||
// Warn creates a new warn event with the given message
|
||||
func Warn(msg string) logger.LogBuilder {
|
||||
return Logger.Warn(msg)
|
||||
}
|
||||
|
||||
// Warnf creates a new warn event with the formatted message
|
||||
func Warnf(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Warnf(format, v...)
|
||||
}
|
||||
|
||||
// Error creates a new error event with the given message
|
||||
func Error(msg string) logger.LogBuilder {
|
||||
return Logger.Error(msg)
|
||||
}
|
||||
|
||||
// Errorf creates a new error event with the formatted message
|
||||
func Errorf(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
// Fatal creates a new fatal event with the given message
|
||||
func Fatal(msg string) logger.LogBuilder {
|
||||
return Logger.Fatal(msg)
|
||||
}
|
||||
|
||||
// Fatalf creates a new fatal event with the formatted message
|
||||
func Fatalf(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Fatalf(format, v...)
|
||||
}
|
||||
|
||||
// Fatal creates a new fatal event with the given message
|
||||
func Panic(msg string) logger.LogBuilder {
|
||||
return Logger.Panic(msg)
|
||||
}
|
||||
|
||||
// Fatalf creates a new fatal event with the formatted message
|
||||
func Panicf(format string, v ...any) logger.LogBuilder {
|
||||
return Logger.Panicf(format, v...)
|
||||
}
|
||||
110
internal/osutils/move.go
Normal file
110
internal/osutils/move.go
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Elara 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 osutils
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Move attempts to use os.Rename and if that fails (such as for a cross-device move),
|
||||
// it instead copies the source to the destination and then removes the source.
|
||||
func Move(sourcePath, destPath string) error {
|
||||
// Try to rename the source to the destination
|
||||
err := os.Rename(sourcePath, destPath)
|
||||
if err == nil {
|
||||
return nil // Successful move
|
||||
}
|
||||
|
||||
// Rename failed, so copy the source to the destination
|
||||
err = copyDirOrFile(sourcePath, destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy successful, remove the original source
|
||||
err = os.RemoveAll(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyDirOrFile(sourcePath, destPath string) error {
|
||||
sourceInfo, err := os.Stat(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sourceInfo.IsDir() {
|
||||
return copyDir(sourcePath, destPath, sourceInfo)
|
||||
} else if sourceInfo.Mode().IsRegular() {
|
||||
return copyFile(sourcePath, destPath, sourceInfo)
|
||||
} else {
|
||||
// ignore non-regular files
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func copyDir(sourcePath, destPath string, sourceInfo os.FileInfo) error {
|
||||
err := os.MkdirAll(destPath, sourceInfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
sourceEntry := filepath.Join(sourcePath, entry.Name())
|
||||
destEntry := filepath.Join(destPath, entry.Name())
|
||||
|
||||
err = copyDirOrFile(sourceEntry, destEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(sourcePath, destPath string, sourceInfo os.FileInfo) error {
|
||||
sourceFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
destFile, err := os.OpenFile(destPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, sourceInfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, sourceFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -20,7 +20,6 @@ package overrides
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"go.elara.ws/lure/distro"
|
||||
@@ -59,12 +58,9 @@ func Resolve(info *distro.OSRelease, opts *Opts) ([]string, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
architectures := []string{runtime.GOARCH}
|
||||
|
||||
if runtime.GOARCH == "arm" {
|
||||
// More specific goes first
|
||||
architectures[0] = cpu.ARMVariant()
|
||||
architectures = append(architectures, "arm")
|
||||
architectures, err := cpu.CompatibleArches(cpu.Arch())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
distros := []string{info.ID}
|
||||
@@ -73,47 +69,38 @@ func Resolve(info *distro.OSRelease, opts *Opts) ([]string, error) {
|
||||
}
|
||||
|
||||
var out []string
|
||||
for _, arch := range architectures {
|
||||
for _, lang := range langs {
|
||||
for _, distro := range distros {
|
||||
if opts.Name == "" {
|
||||
out = append(
|
||||
out,
|
||||
arch+"_"+distro,
|
||||
distro,
|
||||
)
|
||||
} else {
|
||||
out = append(
|
||||
out,
|
||||
opts.Name+"_"+arch+"_"+distro,
|
||||
opts.Name+"_"+distro,
|
||||
)
|
||||
for _, arch := range architectures {
|
||||
out = append(out, opts.Name+"_"+arch+"_"+distro+"_"+lang)
|
||||
}
|
||||
|
||||
out = append(out, opts.Name+"_"+distro+"_"+lang)
|
||||
}
|
||||
if opts.Name == "" {
|
||||
out = append(out, arch)
|
||||
} else {
|
||||
out = append(out, opts.Name+"_"+arch)
|
||||
|
||||
for _, arch := range architectures {
|
||||
out = append(out, opts.Name+"_"+arch+"_"+lang)
|
||||
}
|
||||
|
||||
out = append(out, opts.Name+"_"+lang)
|
||||
}
|
||||
|
||||
for _, distro := range distros {
|
||||
for _, arch := range architectures {
|
||||
out = append(out, opts.Name+"_"+arch+"_"+distro)
|
||||
}
|
||||
|
||||
out = append(out, opts.Name+"_"+distro)
|
||||
}
|
||||
|
||||
for _, arch := range architectures {
|
||||
out = append(out, opts.Name+"_"+arch)
|
||||
}
|
||||
|
||||
out = append(out, opts.Name)
|
||||
|
||||
for index, item := range out {
|
||||
out[index] = strings.ReplaceAll(item, "-", "_")
|
||||
}
|
||||
|
||||
if len(langs) > 0 {
|
||||
tmp := out
|
||||
out = make([]string, 0, len(tmp)+(len(tmp)*len(langs)))
|
||||
for _, lang := range langs {
|
||||
for _, val := range tmp {
|
||||
if val == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, val+"_"+lang)
|
||||
}
|
||||
}
|
||||
out = append(out, tmp...)
|
||||
out[index] = strings.TrimPrefix(strings.ReplaceAll(item, "-", "_"), "_")
|
||||
}
|
||||
|
||||
return out, nil
|
||||
@@ -176,6 +163,7 @@ type ResolvedPackage struct {
|
||||
Replaces []string `sh:"replaces"`
|
||||
Depends []string `sh:"deps"`
|
||||
BuildDepends []string `sh:"build_deps"`
|
||||
OptDepends []string `sh:"opt_deps"`
|
||||
}
|
||||
|
||||
func ResolvePackage(pkg *db.Package, overrides []string) *ResolvedPackage {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -19,6 +19,7 @@
|
||||
package overrides_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -46,6 +47,7 @@ func TestResolve(t *testing.T) {
|
||||
"amd64_fedora_en",
|
||||
"fedora_en",
|
||||
"amd64_en",
|
||||
"en",
|
||||
"amd64_centos",
|
||||
"centos",
|
||||
"amd64_rhel",
|
||||
@@ -87,6 +89,43 @@ func TestResolveName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveArch(t *testing.T) {
|
||||
os.Setenv("LURE_ARCH", "arm7")
|
||||
defer os.Setenv("LURE_ARCH", "")
|
||||
|
||||
names, err := overrides.Resolve(info, &overrides.Opts{
|
||||
Name: "deps",
|
||||
Overrides: true,
|
||||
LikeDistros: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"deps_arm7_centos",
|
||||
"deps_arm6_centos",
|
||||
"deps_arm5_centos",
|
||||
"deps_centos",
|
||||
"deps_arm7_rhel",
|
||||
"deps_arm6_rhel",
|
||||
"deps_arm5_rhel",
|
||||
"deps_rhel",
|
||||
"deps_arm7_fedora",
|
||||
"deps_arm6_fedora",
|
||||
"deps_arm5_fedora",
|
||||
"deps_fedora",
|
||||
"deps_arm7",
|
||||
"deps_arm6",
|
||||
"deps_arm5",
|
||||
"deps",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(names, expected) {
|
||||
t.Errorf("expected %v, got %v", expected, names)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveNoLikeDistros(t *testing.T) {
|
||||
names, err := overrides.Resolve(info, &overrides.Opts{
|
||||
Overrides: true,
|
||||
@@ -139,9 +178,11 @@ func TestResolveLangs(t *testing.T) {
|
||||
"amd64_centos_en",
|
||||
"centos_en",
|
||||
"amd64_en",
|
||||
"en",
|
||||
"amd64_centos_ru",
|
||||
"centos_ru",
|
||||
"amd64_ru",
|
||||
"ru",
|
||||
"amd64_centos",
|
||||
"centos",
|
||||
"amd64",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -34,13 +34,13 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
b := lipgloss.RoundedBorder()
|
||||
b.Right = "\u251C"
|
||||
titleStyle = lipgloss.NewStyle().BorderStyle(b).Padding(0, 1)
|
||||
b1 := lipgloss.RoundedBorder()
|
||||
b1.Right = "\u251C"
|
||||
titleStyle = lipgloss.NewStyle().BorderStyle(b1).Padding(0, 1)
|
||||
|
||||
b = lipgloss.RoundedBorder()
|
||||
b.Left = "\u2524"
|
||||
infoStyle = titleStyle.Copy().BorderStyle(b)
|
||||
b2 := lipgloss.RoundedBorder()
|
||||
b2.Left = "\u2524"
|
||||
infoStyle = titleStyle.Copy().BorderStyle(b2)
|
||||
}
|
||||
|
||||
type Pager struct {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -18,15 +18,12 @@
|
||||
|
||||
package repos
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
)
|
||||
import "go.elara.ws/lure/internal/db"
|
||||
|
||||
// FindPkgs looks for packages matching the inputs inside the database.
|
||||
// It returns a map that maps the package name input to the packages found for it.
|
||||
// It also returns a slice that contains the names of all packages that were not found.
|
||||
func FindPkgs(gdb *sqlx.DB, pkgs []string) (map[string][]db.Package, []string, error) {
|
||||
func FindPkgs(pkgs []string) (map[string][]db.Package, []string, error) {
|
||||
found := map[string][]db.Package{}
|
||||
notFound := []string(nil)
|
||||
|
||||
@@ -35,7 +32,7 @@ func FindPkgs(gdb *sqlx.DB, pkgs []string) (map[string][]db.Package, []string, e
|
||||
continue
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(gdb, "name LIKE ?", pkgName)
|
||||
result, err := db.GetPkgs("name LIKE ?", pkgName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -54,7 +51,7 @@ func FindPkgs(gdb *sqlx.DB, pkgs []string) (map[string][]db.Package, []string, e
|
||||
result.Close()
|
||||
|
||||
if added == 0 {
|
||||
result, err := db.GetPkgs(gdb, "json_array_contains(provides, ?)", pkgName)
|
||||
result, err := db.GetPkgs("json_array_contains(provides, ?)", pkgName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -30,18 +30,18 @@ import (
|
||||
)
|
||||
|
||||
func TestFindPkgs(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
setCfgDirs(t)
|
||||
defer removeCacheDir(t)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
err = repos.Pull(ctx, gdb, []types.Repo{
|
||||
err = repos.Pull(ctx, []types.Repo{
|
||||
{
|
||||
Name: "default",
|
||||
URL: "https://github.com/Arsen6331/lure-repo.git",
|
||||
@@ -51,7 +51,7 @@ func TestFindPkgs(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
found, notFound, err := repos.FindPkgs(gdb, []string{"itd", "nonexistentpackage1", "nonexistentpackage2"})
|
||||
found, notFound, err := repos.FindPkgs([]string{"itd", "nonexistentpackage1", "nonexistentpackage2"})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
@@ -81,16 +81,16 @@ func TestFindPkgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindPkgsEmpty(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
setCfgDirs(t)
|
||||
defer removeCacheDir(t)
|
||||
|
||||
err = db.InsertPackage(gdb, db.Package{
|
||||
err = db.InsertPackage(db.Package{
|
||||
Name: "test1",
|
||||
Repository: "default",
|
||||
Version: "0.0.1",
|
||||
@@ -105,7 +105,7 @@ func TestFindPkgsEmpty(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = db.InsertPackage(gdb, db.Package{
|
||||
err = db.InsertPackage(db.Package{
|
||||
Name: "test2",
|
||||
Repository: "default",
|
||||
Version: "0.0.1",
|
||||
@@ -120,7 +120,7 @@ func TestFindPkgsEmpty(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
found, notFound, err := repos.FindPkgs(gdb, []string{"test", ""})
|
||||
found, notFound, err := repos.FindPkgs([]string{"test", ""})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -33,16 +33,15 @@ import (
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/format/diff"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/distro"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/shutils"
|
||||
"go.elara.ws/lure/internal/shutils/decoder"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/vercmp"
|
||||
"go.elara.ws/vercmp"
|
||||
"mvdan.cc/sh/v3/expand"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
@@ -51,7 +50,7 @@ import (
|
||||
// Pull pulls the provided repositories. If a repo doesn't exist, it will be cloned
|
||||
// and its packages will be written to the DB. If it does exist, it will be pulled.
|
||||
// In this case, only changed packages will be processed.
|
||||
func Pull(ctx context.Context, gdb *sqlx.DB, repos []types.Repo) error {
|
||||
func Pull(ctx context.Context, repos []types.Repo) error {
|
||||
for _, repo := range repos {
|
||||
repoURL, err := url.Parse(repo.URL)
|
||||
if err != nil {
|
||||
@@ -59,7 +58,7 @@ func Pull(ctx context.Context, gdb *sqlx.DB, repos []types.Repo) error {
|
||||
}
|
||||
|
||||
log.Info("Pulling repository").Str("name", repo.Name).Send()
|
||||
repoDir := filepath.Join(config.RepoDir, repo.Name)
|
||||
repoDir := filepath.Join(config.GetPaths().RepoDir, repo.Name)
|
||||
|
||||
var repoFS billy.Filesystem
|
||||
gitDir := filepath.Join(repoDir, ".git")
|
||||
@@ -89,7 +88,7 @@ func Pull(ctx context.Context, gdb *sqlx.DB, repos []types.Repo) error {
|
||||
repoFS = w.Filesystem
|
||||
|
||||
// Make sure the DB is created even if the repo is up to date
|
||||
if !errors.Is(err, git.NoErrAlreadyUpToDate) || !config.DBPresent {
|
||||
if !errors.Is(err, git.NoErrAlreadyUpToDate) || db.IsEmpty() {
|
||||
new, err := r.Head()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -98,13 +97,13 @@ func Pull(ctx context.Context, gdb *sqlx.DB, repos []types.Repo) error {
|
||||
// If the DB was not present at startup, that means it's
|
||||
// empty. In this case, we need to update the DB fully
|
||||
// rather than just incrementally.
|
||||
if config.DBPresent {
|
||||
err = processRepoChanges(ctx, repo, r, w, old, new, gdb)
|
||||
if db.IsEmpty() {
|
||||
err = processRepoFull(ctx, repo, repoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = processRepoFull(ctx, repo, repoDir, gdb)
|
||||
err = processRepoChanges(ctx, repo, r, w, old, new)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -129,7 +128,7 @@ func Pull(ctx context.Context, gdb *sqlx.DB, repos []types.Repo) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = processRepoFull(ctx, repo, repoDir, gdb)
|
||||
err = processRepoFull(ctx, repo, repoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -171,7 +170,7 @@ type action struct {
|
||||
File string
|
||||
}
|
||||
|
||||
func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository, w *git.Worktree, old, new *plumbing.Reference, gdb *sqlx.DB) error {
|
||||
func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository, w *git.Worktree, old, new *plumbing.Reference) error {
|
||||
oldCommit, err := r.CommitObject(old.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -265,7 +264,7 @@ func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository,
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.DeletePkgs(gdb, "name = ? AND repository = ?", pkg.Name, repo.Name)
|
||||
err = db.DeletePkgs("name = ? AND repository = ?", pkg.Name, repo.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -300,7 +299,7 @@ func processRepoChanges(ctx context.Context, repo types.Repo, r *git.Repository,
|
||||
|
||||
resolveOverrides(runner, &pkg)
|
||||
|
||||
err = db.InsertPackage(gdb, pkg)
|
||||
err = db.InsertPackage(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -326,7 +325,7 @@ func isValid(from, to diff.File) bool {
|
||||
return match
|
||||
}
|
||||
|
||||
func processRepoFull(ctx context.Context, repo types.Repo, repoDir string, gdb *sqlx.DB) error {
|
||||
func processRepoFull(ctx context.Context, repo types.Repo, repoDir string) error {
|
||||
glob := filepath.Join(repoDir, "/*/lure.sh")
|
||||
matches, err := filepath.Glob(glob)
|
||||
if err != nil {
|
||||
@@ -370,7 +369,7 @@ func processRepoFull(ctx context.Context, repo types.Repo, repoDir string, gdb *
|
||||
|
||||
resolveOverrides(runner, &pkg)
|
||||
|
||||
err = db.InsertPackage(gdb, pkg)
|
||||
err = db.InsertPackage(pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -33,50 +33,52 @@ import (
|
||||
func setCfgDirs(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
paths := config.GetPaths()
|
||||
|
||||
var err error
|
||||
config.CacheDir, err = os.MkdirTemp("/tmp", "lure-pull-test.*")
|
||||
paths.CacheDir, err = os.MkdirTemp("/tmp", "lure-pull-test.*")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
config.RepoDir = filepath.Join(config.CacheDir, "repo")
|
||||
config.PkgsDir = filepath.Join(config.CacheDir, "pkgs")
|
||||
paths.RepoDir = filepath.Join(paths.CacheDir, "repo")
|
||||
paths.PkgsDir = filepath.Join(paths.CacheDir, "pkgs")
|
||||
|
||||
err = os.MkdirAll(config.RepoDir, 0o755)
|
||||
err = os.MkdirAll(paths.RepoDir, 0o755)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(config.PkgsDir, 0o755)
|
||||
err = os.MkdirAll(paths.PkgsDir, 0o755)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
config.DBPath = filepath.Join(config.CacheDir, "db")
|
||||
paths.DBPath = filepath.Join(paths.CacheDir, "db")
|
||||
}
|
||||
|
||||
func removeCacheDir(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
err := os.RemoveAll(config.CacheDir)
|
||||
err := os.RemoveAll(config.GetPaths().CacheDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPull(t *testing.T) {
|
||||
gdb, err := db.Open(":memory:")
|
||||
_, err := db.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
defer gdb.Close()
|
||||
defer db.Close()
|
||||
|
||||
setCfgDirs(t)
|
||||
defer removeCacheDir(t)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
err = repos.Pull(ctx, gdb, []types.Repo{
|
||||
err = repos.Pull(ctx, []types.Repo{
|
||||
{
|
||||
Name: "default",
|
||||
URL: "https://github.com/Arsen6331/lure-repo.git",
|
||||
@@ -86,7 +88,7 @@ func TestPull(t *testing.T) {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(gdb, "name LIKE 'itd%'")
|
||||
result, err := db.GetPkgs("name LIKE 'itd%'")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %s", err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -56,16 +56,16 @@ func (ite InvalidTypeError) Error() string {
|
||||
// Decoder provides methods for decoding variable values
|
||||
type Decoder struct {
|
||||
info *distro.OSRelease
|
||||
runner *interp.Runner
|
||||
Runner *interp.Runner
|
||||
// Enable distro overrides (true by default)
|
||||
Overrides bool
|
||||
// Enable using like distros for overrides (true by default)
|
||||
// Enable using like distros for overrides
|
||||
LikeDistros bool
|
||||
}
|
||||
|
||||
// New creates a new variable decoder
|
||||
func New(info *distro.OSRelease, runner *interp.Runner) *Decoder {
|
||||
return &Decoder{info, runner, true, true}
|
||||
return &Decoder{info, runner, true, len(info.Like) > 0}
|
||||
}
|
||||
|
||||
// DecodeVar decodes a variable to val using reflection.
|
||||
@@ -173,7 +173,7 @@ func (d *Decoder) GetFunc(name string) (ScriptFunc, bool) {
|
||||
}
|
||||
|
||||
return func(ctx context.Context, opts ...interp.RunnerOption) error {
|
||||
sub := d.runner.Subshell()
|
||||
sub := d.Runner.Subshell()
|
||||
for _, opt := range opts {
|
||||
opt(sub)
|
||||
}
|
||||
@@ -188,7 +188,7 @@ func (d *Decoder) getFunc(name string) *syntax.Stmt {
|
||||
}
|
||||
|
||||
for _, fnName := range names {
|
||||
fn, ok := d.runner.Funcs[fnName]
|
||||
fn, ok := d.Runner.Funcs[fnName]
|
||||
if ok {
|
||||
return fn
|
||||
}
|
||||
@@ -205,11 +205,11 @@ func (d *Decoder) getVar(name string) *expand.Variable {
|
||||
}
|
||||
|
||||
for _, varName := range names {
|
||||
val, ok := d.runner.Vars[varName]
|
||||
val, ok := d.Runner.Vars[varName]
|
||||
if ok {
|
||||
// Resolve nameref variables
|
||||
_, resolved := val.Resolve(expand.FuncEnviron(func(s string) string {
|
||||
if val, ok := d.runner.Vars[s]; ok {
|
||||
if val, ok := d.Runner.Vars[s]; ok {
|
||||
return val.String()
|
||||
}
|
||||
return ""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -36,8 +36,8 @@ const testScript = `
|
||||
release=1
|
||||
epoch=2
|
||||
desc="Test package"
|
||||
homepage='https://lure.arsenm.dev'
|
||||
maintainer='Arsen Musayelyan <arsen@arsenm.dev>'
|
||||
homepage='https://lure.elara.ws'
|
||||
maintainer='Elara Musayelyan <elara@elara.ws>'
|
||||
architectures=('arm64' 'amd64')
|
||||
license=('GPL-3.0-or-later')
|
||||
provides=('test')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -40,21 +40,24 @@ var (
|
||||
ErrNoDetectManNum = errors.New("manual number cannot be detected from the filename")
|
||||
)
|
||||
|
||||
var helpers = shutils.ExecFuncs{
|
||||
// Helpers contains all the helper commands
|
||||
var Helpers = shutils.ExecFuncs{
|
||||
"install-binary": installHelperCmd("/usr/bin", 0o755),
|
||||
"install-systemd-user": installHelperCmd("/usr/lib/systemd/user", 0o644),
|
||||
"install-systemd": installHelperCmd("/usr/lib/systemd/system", 0o644),
|
||||
"install-config": installHelperCmd("/etc", 0o644),
|
||||
"install-license": installHelperCmd("/usr/share/licenses", 0o644),
|
||||
"install-desktop": installHelperCmd("/usr/share/applications", 0o644),
|
||||
"install-icon": installHelperCmd("/usr/share/pixmaps", 0o644),
|
||||
"install-manual": installManualCmd,
|
||||
"install-completion": installCompletionCmd,
|
||||
"install-library": installLibraryCmd,
|
||||
"git-version": gitVersionCmd,
|
||||
}
|
||||
|
||||
// rHelpers contains restricted read-only helpers that don't modify any state
|
||||
var rHelpers = shutils.ExecFuncs{
|
||||
// Restricted contains restricted read-only helper commands
|
||||
// that don't modify any state
|
||||
var Restricted = shutils.ExecFuncs{
|
||||
"git-version": gitVersionCmd,
|
||||
}
|
||||
|
||||
@@ -205,10 +208,12 @@ func getLibPrefix(hc interp.HandlerContext) string {
|
||||
|
||||
architecture := hc.Env.Get("ARCH").Str
|
||||
|
||||
if distroID == "debian" || slices.Contains(distroLike, "debian") {
|
||||
triple, ok := multiarchTupleMap[architecture]
|
||||
if distroID == "debian" || slices.Contains(distroLike, "debian") ||
|
||||
distroID == "ubuntu" || slices.Contains(distroLike, "ubuntu") {
|
||||
|
||||
tuple, ok := multiarchTupleMap[architecture]
|
||||
if ok {
|
||||
out = filepath.Join("/usr/lib", triple)
|
||||
out = filepath.Join("/usr/lib", tuple)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -21,7 +21,8 @@ package shutils
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -30,33 +31,36 @@ import (
|
||||
)
|
||||
|
||||
func RestrictedReadDir(allowedPrefixes ...string) interp.ReadDirHandlerFunc {
|
||||
return func(ctx context.Context, s string) ([]os.FileInfo, error) {
|
||||
return func(ctx context.Context, s string) ([]fs.FileInfo, error) {
|
||||
path := filepath.Clean(s)
|
||||
for _, allowedPrefix := range allowedPrefixes {
|
||||
if strings.HasPrefix(s, allowedPrefix) {
|
||||
if strings.HasPrefix(path, allowedPrefix) {
|
||||
return interp.DefaultReadDirHandler()(ctx, s)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
}
|
||||
|
||||
func RestrictedStat(allowedPrefixes ...string) interp.StatHandlerFunc {
|
||||
return func(ctx context.Context, s string, b bool) (os.FileInfo, error) {
|
||||
return func(ctx context.Context, s string, b bool) (fs.FileInfo, error) {
|
||||
path := filepath.Clean(s)
|
||||
for _, allowedPrefix := range allowedPrefixes {
|
||||
if strings.HasPrefix(s, allowedPrefix) {
|
||||
if strings.HasPrefix(path, allowedPrefix) {
|
||||
return interp.DefaultStatHandler()(ctx, s, b)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, os.ErrNotExist
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
}
|
||||
|
||||
func RestrictedOpen(allowedPrefixes ...string) interp.OpenHandlerFunc {
|
||||
return func(ctx context.Context, s string, i int, fm os.FileMode) (io.ReadWriteCloser, error) {
|
||||
return func(ctx context.Context, s string, i int, fm fs.FileMode) (io.ReadWriteCloser, error) {
|
||||
path := filepath.Clean(s)
|
||||
for _, allowedPrefix := range allowedPrefixes {
|
||||
if strings.HasPrefix(s, allowedPrefix) {
|
||||
if strings.HasPrefix(path, allowedPrefix) {
|
||||
return interp.DefaultOpenHandler()(ctx, s, i, fm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,14 @@ value = 'Building package metadata'
|
||||
id = 3121791194
|
||||
value = 'Running LURE as root is forbidden as it may cause catastrophic damage to your system'
|
||||
|
||||
[[translation]]
|
||||
id = 1256604213
|
||||
value = 'Waiting for torrent metadata'
|
||||
|
||||
[[translation]]
|
||||
id = 432261354
|
||||
value = 'Downloading torrent file'
|
||||
|
||||
[[translation]]
|
||||
id = 1579384326
|
||||
value = 'name'
|
||||
@@ -118,6 +118,14 @@ value = 'Создание метаданных пакета'
|
||||
id = 3121791194
|
||||
value = 'Запуск LURE от имени root запрещен, так как это может привести к катастрофическому повреждению вашей системы'
|
||||
|
||||
[[translation]]
|
||||
id = 1256604213
|
||||
value = 'Ожидание метаданных торрента'
|
||||
|
||||
[[translation]]
|
||||
id = 432261354
|
||||
value = 'Скачивание торрент-файла'
|
||||
|
||||
[[translation]]
|
||||
id = 1579384326
|
||||
value = 'название'
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -16,19 +16,33 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
package translations
|
||||
|
||||
import (
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"embed"
|
||||
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/translate"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var cfg types.Config
|
||||
//go:embed files
|
||||
var translationFS embed.FS
|
||||
|
||||
func init() {
|
||||
err := config.Decode(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error decoding config file").Err(err).Send()
|
||||
var translator *translate.Translator
|
||||
|
||||
func Translator() *translate.Translator {
|
||||
if translator == nil {
|
||||
t, err := translate.NewFromFS(translationFS)
|
||||
if err != nil {
|
||||
log.Fatal("Error creating new translator").Err(err).Send()
|
||||
}
|
||||
translator = &t
|
||||
}
|
||||
return translator
|
||||
}
|
||||
|
||||
func NewLogger(l logger.Logger, lang language.Tag) *translate.TranslatedLogger {
|
||||
return translate.NewLogger(l, *Translator(), lang)
|
||||
}
|
||||
70
internal/types/build.go
Normal file
70
internal/types/build.go
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Elara 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 types
|
||||
|
||||
import "go.elara.ws/lure/manager"
|
||||
|
||||
type BuildOpts struct {
|
||||
Script string
|
||||
Manager manager.Manager
|
||||
Clean bool
|
||||
Interactive bool
|
||||
}
|
||||
|
||||
// BuildVars represents the script variables required
|
||||
// to build a package
|
||||
type BuildVars struct {
|
||||
Name string `sh:"name,required"`
|
||||
Version string `sh:"version,required"`
|
||||
Release int `sh:"release,required"`
|
||||
Epoch uint `sh:"epoch"`
|
||||
Description string `sh:"desc"`
|
||||
Homepage string `sh:"homepage"`
|
||||
Maintainer string `sh:"maintainer"`
|
||||
Architectures []string `sh:"architectures"`
|
||||
Licenses []string `sh:"license"`
|
||||
Provides []string `sh:"provides"`
|
||||
Conflicts []string `sh:"conflicts"`
|
||||
Depends []string `sh:"deps"`
|
||||
BuildDepends []string `sh:"build_deps"`
|
||||
OptDepends []string `sh:"opt_deps"`
|
||||
Replaces []string `sh:"replaces"`
|
||||
Sources []string `sh:"sources"`
|
||||
Checksums []string `sh:"checksums"`
|
||||
Backup []string `sh:"backup"`
|
||||
Scripts Scripts `sh:"scripts"`
|
||||
}
|
||||
|
||||
type Scripts struct {
|
||||
PreInstall string `sh:"preinstall"`
|
||||
PostInstall string `sh:"postinstall"`
|
||||
PreRemove string `sh:"preremove"`
|
||||
PostRemove string `sh:"postremove"`
|
||||
PreUpgrade string `sh:"preupgrade"`
|
||||
PostUpgrade string `sh:"postupgrade"`
|
||||
PreTrans string `sh:"pretrans"`
|
||||
PostTrans string `sh:"posttrans"`
|
||||
}
|
||||
|
||||
type Directories struct {
|
||||
BaseDir string
|
||||
SrcDir string
|
||||
PkgDir string
|
||||
ScriptDir string
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
114
list.go
114
list.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -22,72 +22,84 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/manager"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func listCmd(c *cli.Context) error {
|
||||
err := repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
where := "true"
|
||||
args := []any(nil)
|
||||
if c.NArg() > 0 {
|
||||
where = "name LIKE ? OR json_array_contains(provides, ?)"
|
||||
args = []any{c.Args().First(), c.Args().First()}
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(gdb, where, args...)
|
||||
if err != nil {
|
||||
log.Fatal("Error getting packages").Err(err).Send()
|
||||
}
|
||||
defer result.Close()
|
||||
|
||||
var installed map[string]string
|
||||
if c.Bool("installed") {
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
|
||||
installed, err = mgr.ListInstalled(&manager.Opts{AsRoot: false})
|
||||
var listCmd = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List LURE repo packages",
|
||||
Aliases: []string{"ls"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "installed",
|
||||
Aliases: []string{"I"},
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
err := repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error listing installed packages").Err(err).Send()
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err := result.StructScan(&pkg)
|
||||
where := "true"
|
||||
args := []any(nil)
|
||||
if c.NArg() > 0 {
|
||||
where = "name LIKE ? OR json_array_contains(provides, ?)"
|
||||
args = []any{c.Args().First(), c.Args().First()}
|
||||
}
|
||||
|
||||
result, err := db.GetPkgs(where, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Fatal("Error getting packages").Err(err).Send()
|
||||
}
|
||||
defer result.Close()
|
||||
|
||||
if slices.Contains(cfg.IgnorePkgUpdates, pkg.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
version := pkg.Version
|
||||
var installed map[string]string
|
||||
if c.Bool("installed") {
|
||||
instVersion, ok := installed[pkg.Name]
|
||||
if !ok {
|
||||
continue
|
||||
} else {
|
||||
version = instVersion
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
|
||||
installed, err = mgr.ListInstalled(&manager.Opts{AsRoot: false})
|
||||
if err != nil {
|
||||
log.Fatal("Error listing installed packages").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s/%s %s\n", pkg.Repository, pkg.Name, version)
|
||||
}
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err := result.StructScan(&pkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Error iterating over packages").Err(err).Send()
|
||||
}
|
||||
if slices.Contains(config.Config().IgnorePkgUpdates, pkg.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil
|
||||
version := pkg.Version
|
||||
if c.Bool("installed") {
|
||||
instVersion, ok := installed[pkg.Name]
|
||||
if !ok {
|
||||
continue
|
||||
} else {
|
||||
version = instVersion
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s/%s %s\n", pkg.Repository, pkg.Name, version)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Error iterating over packages").Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
274
main.go
274
main.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -20,247 +20,89 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/logger"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/translations"
|
||||
"go.elara.ws/lure/manager"
|
||||
"go.elara.ws/translate"
|
||||
)
|
||||
|
||||
//go:generate scripts/gen-version.sh
|
||||
var app = &cli.App{
|
||||
Name: "lure",
|
||||
Usage: "Linux User REpository",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "pm-args",
|
||||
Aliases: []string{"P"},
|
||||
Usage: "Arguments to be passed on to the package manager",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "interactive",
|
||||
Aliases: []string{"i"},
|
||||
Value: isatty.IsTerminal(os.Stdin.Fd()),
|
||||
Usage: "Enable interactive questions and prompts",
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
installCmd,
|
||||
removeCmd,
|
||||
upgradeCmd,
|
||||
infoCmd,
|
||||
listCmd,
|
||||
buildCmd,
|
||||
addrepoCmd,
|
||||
removerepoCmd,
|
||||
refreshCmd,
|
||||
fixCmd,
|
||||
versionCmd,
|
||||
},
|
||||
Before: func(c *cli.Context) error {
|
||||
args := strings.Split(c.String("pm-args"), " ")
|
||||
if len(args) == 1 && args[0] == "" {
|
||||
return nil
|
||||
}
|
||||
manager.Args = append(manager.Args, args...)
|
||||
return nil
|
||||
},
|
||||
After: func(ctx *cli.Context) error {
|
||||
return db.Close()
|
||||
},
|
||||
EnableBashCompletion: true,
|
||||
}
|
||||
|
||||
//go:embed translations
|
||||
var translationFS embed.FS
|
||||
|
||||
var translator translate.Translator
|
||||
|
||||
func init() {
|
||||
logger := logger.NewCLI(os.Stderr)
|
||||
|
||||
t, err := translate.NewFromFS(translationFS)
|
||||
if err != nil {
|
||||
logger.Fatal("Error creating new translator").Err(err).Send()
|
||||
}
|
||||
translator = t
|
||||
|
||||
log.Logger = translate.NewLogger(logger, t, config.Language)
|
||||
var versionCmd = &cli.Command{
|
||||
Name: "version",
|
||||
Usage: "Print the current LURE version and exit",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
println(config.Version)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
if !cfg.Unsafe.AllowRunAsRoot && os.Geteuid() == 0 {
|
||||
log.Logger = translations.NewLogger(logger.NewCLI(os.Stderr), config.Language())
|
||||
|
||||
if !config.Config().Unsafe.AllowRunAsRoot && os.Geteuid() == 0 {
|
||||
log.Fatal("Running LURE as root is forbidden as it may cause catastrophic damage to your system").Send()
|
||||
}
|
||||
|
||||
err := loadDB()
|
||||
if err != nil {
|
||||
log.Fatal("Error loading database").Err(err).Send()
|
||||
}
|
||||
// Set the root command to the one set in the LURE config
|
||||
manager.DefaultRootCmd = config.Config().RootCmd
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
// Exit the program after a maximum of 200ms
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
gdb.Close()
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
app := &cli.App{
|
||||
Name: "lure",
|
||||
Usage: "Linux User REpository",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "pm-args",
|
||||
Aliases: []string{"P"},
|
||||
Usage: "Arguments to be passed on to the package manager",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "interactive",
|
||||
Aliases: []string{"i"},
|
||||
Value: isatty.IsTerminal(os.Stdin.Fd()),
|
||||
Usage: "Enable interactive questions and prompts",
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Name: "install",
|
||||
Usage: "Install a new package",
|
||||
Aliases: []string{"in"},
|
||||
Action: installCmd,
|
||||
BashComplete: completionInstall,
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Usage: "Remove an installed package",
|
||||
Aliases: []string{"rm"},
|
||||
Action: removeCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Name: "upgrade",
|
||||
Usage: "Upgrade all installed packages",
|
||||
Aliases: []string{"up"},
|
||||
Action: upgradeCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Show all information, not just for the current distro",
|
||||
},
|
||||
},
|
||||
Name: "info",
|
||||
Usage: "Print information about a package",
|
||||
Action: infoCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "installed",
|
||||
Aliases: []string{"I"},
|
||||
},
|
||||
},
|
||||
Name: "list",
|
||||
Usage: "List LURE repo packages",
|
||||
Aliases: []string{"ls"},
|
||||
Action: listCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "script",
|
||||
Aliases: []string{"s"},
|
||||
Value: "lure.sh",
|
||||
Usage: "Path to the build script",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Name: "build",
|
||||
Usage: "Build a local package",
|
||||
Action: buildCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
Required: true,
|
||||
Usage: "Name of the new repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Aliases: []string{"u"},
|
||||
Required: true,
|
||||
Usage: "URL of the new repo",
|
||||
},
|
||||
},
|
||||
Name: "addrepo",
|
||||
Usage: "Add a new repository",
|
||||
Aliases: []string{"ar"},
|
||||
Action: addrepoCmd,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
Required: true,
|
||||
Usage: "Name of the repo to be deleted",
|
||||
},
|
||||
},
|
||||
Name: "removerepo",
|
||||
Usage: "Remove an existing repository",
|
||||
Aliases: []string{"rr"},
|
||||
Action: removerepoCmd,
|
||||
},
|
||||
{
|
||||
Name: "refresh",
|
||||
Usage: "Pull all repositories that have changed",
|
||||
Aliases: []string{"ref"},
|
||||
Action: refreshCmd,
|
||||
},
|
||||
{
|
||||
Name: "fix",
|
||||
Usage: "Attempt to fix problems with LURE",
|
||||
Action: fixCmd,
|
||||
},
|
||||
{
|
||||
Name: "version",
|
||||
Usage: "Display the current LURE version and exit",
|
||||
Action: displayVersion,
|
||||
},
|
||||
},
|
||||
Before: func(c *cli.Context) error {
|
||||
args := strings.Split(c.String("pm-args"), " ")
|
||||
if len(args) == 1 && args[0] == "" {
|
||||
args = nil
|
||||
}
|
||||
|
||||
manager.Args = append(manager.Args, args...)
|
||||
return nil
|
||||
},
|
||||
After: func(ctx *cli.Context) error {
|
||||
return gdb.Close()
|
||||
},
|
||||
EnableBashCompletion: true,
|
||||
}
|
||||
|
||||
err = app.RunContext(ctx, os.Args)
|
||||
err := app.RunContext(ctx, os.Args)
|
||||
if err != nil {
|
||||
log.Error("Error while running app").Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
func displayVersion(c *cli.Context) error {
|
||||
print(config.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func completionInstall(c *cli.Context) {
|
||||
result, err := db.GetPkgs(gdb, "true")
|
||||
if err != nil {
|
||||
log.Fatal("Error getting packages").Err(err).Send()
|
||||
}
|
||||
defer result.Close()
|
||||
|
||||
for result.Next() {
|
||||
var pkg db.Package
|
||||
err = result.StructScan(&pkg)
|
||||
if err != nil {
|
||||
log.Fatal("Error iterating over packages").Err(err).Send()
|
||||
}
|
||||
|
||||
fmt.Println(pkg.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
|
||||
182
repo.go
182
repo.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -24,91 +24,131 @@ import (
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func addrepoCmd(c *cli.Context) error {
|
||||
name := c.String("name")
|
||||
repoURL := c.String("url")
|
||||
var addrepoCmd = &cli.Command{
|
||||
Name: "addrepo",
|
||||
Usage: "Add a new repository",
|
||||
Aliases: []string{"ar"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
Required: true,
|
||||
Usage: "Name of the new repo",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "url",
|
||||
Aliases: []string{"u"},
|
||||
Required: true,
|
||||
Usage: "URL of the new repo",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
name := c.String("name")
|
||||
repoURL := c.String("url")
|
||||
|
||||
for _, repo := range cfg.Repos {
|
||||
if repo.URL == repoURL {
|
||||
log.Fatal("Repo already exists").Str("name", repo.Name).Send()
|
||||
cfg := config.Config()
|
||||
|
||||
for _, repo := range cfg.Repos {
|
||||
if repo.URL == repoURL {
|
||||
log.Fatal("Repo already exists").Str("name", repo.Name).Send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Repos = append(cfg.Repos, types.Repo{
|
||||
Name: name,
|
||||
URL: repoURL,
|
||||
})
|
||||
cfg.Repos = append(cfg.Repos, types.Repo{
|
||||
Name: name,
|
||||
URL: repoURL,
|
||||
})
|
||||
|
||||
cfgFl, err := os.Create(config.ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening config file").Err(err).Send()
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding config").Err(err).Send()
|
||||
}
|
||||
|
||||
err = repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removerepoCmd(c *cli.Context) error {
|
||||
name := c.String("name")
|
||||
|
||||
found := false
|
||||
index := 0
|
||||
for i, repo := range cfg.Repos {
|
||||
if repo.Name == name {
|
||||
index = i
|
||||
found = true
|
||||
cfgFl, err := os.Create(config.GetPaths().ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening config file").Err(err).Send()
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Fatal("Repo does not exist").Str("name", name).Send()
|
||||
}
|
||||
|
||||
cfg.Repos = slices.Delete(cfg.Repos, index, index+1)
|
||||
err = toml.NewEncoder(cfgFl).Encode(cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding config").Err(err).Send()
|
||||
}
|
||||
|
||||
cfgFl, err := os.Create(config.ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening config file").Err(err).Send()
|
||||
}
|
||||
err = repos.Pull(c.Context, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding config").Err(err).Send()
|
||||
}
|
||||
|
||||
err = os.RemoveAll(filepath.Join(config.RepoDir, name))
|
||||
if err != nil {
|
||||
log.Fatal("Error removing repo directory").Err(err).Send()
|
||||
}
|
||||
|
||||
err = db.DeletePkgs(gdb, "repository = ?", name)
|
||||
if err != nil {
|
||||
log.Fatal("Error removing packages from database").Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func refreshCmd(c *cli.Context) error {
|
||||
err := repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
return nil
|
||||
var removerepoCmd = &cli.Command{
|
||||
Name: "removerepo",
|
||||
Usage: "Remove an existing repository",
|
||||
Aliases: []string{"rr"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Aliases: []string{"n"},
|
||||
Required: true,
|
||||
Usage: "Name of the repo to be deleted",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
name := c.String("name")
|
||||
cfg := config.Config()
|
||||
|
||||
found := false
|
||||
index := 0
|
||||
for i, repo := range cfg.Repos {
|
||||
if repo.Name == name {
|
||||
index = i
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Fatal("Repo does not exist").Str("name", name).Send()
|
||||
}
|
||||
|
||||
cfg.Repos = slices.Delete(cfg.Repos, index, index+1)
|
||||
|
||||
cfgFl, err := os.Create(config.GetPaths().ConfigPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening config file").Err(err).Send()
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding config").Err(err).Send()
|
||||
}
|
||||
|
||||
err = os.RemoveAll(filepath.Join(config.GetPaths().RepoDir, name))
|
||||
if err != nil {
|
||||
log.Fatal("Error removing repo directory").Err(err).Send()
|
||||
}
|
||||
|
||||
err = db.DeletePkgs("repository = ?", name)
|
||||
if err != nil {
|
||||
log.Fatal("Error removing packages from database").Err(err).Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var refreshCmd = &cli.Command{
|
||||
Name: "refresh",
|
||||
Usage: "Pull all repositories that have changed",
|
||||
Aliases: []string{"ref"},
|
||||
Action: func(c *cli.Context) error {
|
||||
err := repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
git describe --tags > internal/config/version.txt
|
||||
git describe --tags > version.txt
|
||||
@@ -1,5 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# LURE - Linux User REpository
|
||||
# Copyright (C) 2023 Elara 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/>.
|
||||
|
||||
info() {
|
||||
echo $'\x1b[32m[INFO]\x1b[0m' $@
|
||||
}
|
||||
@@ -64,7 +80,7 @@ else
|
||||
error "No supported package manager detected!"
|
||||
fi
|
||||
|
||||
latestVersion=$(curl -sI 'https://gitea.elara.ws/Elara6331/lure/releases/latest' | grep -o 'location: .*' | rev | cut -d '/' -f1 | rev | tr -d '[:space:]')
|
||||
latestVersion=$(curl -sI 'https://gitea.elara.ws/Elara6331/lure/releases/latest' | grep -io 'location: .*' | rev | cut -d '/' -f1 | rev | tr -d '[:space:]')
|
||||
info "Found latest LURE version:" $latestVersion
|
||||
|
||||
fname="$(mktemp -u -p /tmp "lure.XXXXXXXXXX").${pkgFormat}"
|
||||
|
||||
79
upgrade.go
79
upgrade.go
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara 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
|
||||
@@ -23,44 +23,63 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.elara.ws/logger/log"
|
||||
"go.elara.ws/lure/distro"
|
||||
"go.elara.ws/lure/internal/build"
|
||||
"go.elara.ws/lure/internal/config"
|
||||
"go.elara.ws/lure/internal/db"
|
||||
"go.elara.ws/lure/internal/log"
|
||||
"go.elara.ws/lure/internal/repos"
|
||||
"go.elara.ws/lure/internal/types"
|
||||
"go.elara.ws/lure/manager"
|
||||
"go.elara.ws/lure/vercmp"
|
||||
"go.elara.ws/vercmp"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func upgradeCmd(c *cli.Context) error {
|
||||
info, err := distro.ParseOSRelease(c.Context)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing os-release file").Err(err).Send()
|
||||
}
|
||||
var upgradeCmd = &cli.Command{
|
||||
Name: "upgrade",
|
||||
Usage: "Upgrade all installed packages",
|
||||
Aliases: []string{"up"},
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
info, err := distro.ParseOSRelease(c.Context)
|
||||
if err != nil {
|
||||
log.Fatal("Error parsing os-release file").Err(err).Send()
|
||||
}
|
||||
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
|
||||
err = repos.Pull(c.Context, gdb, cfg.Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
err = repos.Pull(c.Context, config.Config().Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repos").Err(err).Send()
|
||||
}
|
||||
|
||||
updates, err := checkForUpdates(c.Context, mgr, info)
|
||||
if err != nil {
|
||||
log.Fatal("Error checking for updates").Err(err).Send()
|
||||
}
|
||||
updates, err := checkForUpdates(c.Context, mgr, info)
|
||||
if err != nil {
|
||||
log.Fatal("Error checking for updates").Err(err).Send()
|
||||
}
|
||||
|
||||
if len(updates) > 0 {
|
||||
installPkgs(c.Context, updates, nil, mgr, c.Bool("clean"), c.Bool("interactive"))
|
||||
} else {
|
||||
log.Info("There is nothing to do.").Send()
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
build.InstallPkgs(c.Context, updates, nil, types.BuildOpts{
|
||||
Manager: mgr,
|
||||
Clean: c.Bool("clean"),
|
||||
Interactive: c.Bool("interactive"),
|
||||
})
|
||||
} else {
|
||||
log.Info("There is nothing to do.").Send()
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRelease) ([]db.Package, error) {
|
||||
@@ -70,21 +89,21 @@ func checkForUpdates(ctx context.Context, mgr manager.Manager, info *distro.OSRe
|
||||
}
|
||||
|
||||
pkgNames := maps.Keys(installed)
|
||||
found, _, err := repos.FindPkgs(gdb, pkgNames)
|
||||
found, _, err := repos.FindPkgs(pkgNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []db.Package
|
||||
for pkgName, pkgs := range found {
|
||||
if slices.Contains(cfg.IgnorePkgUpdates, pkgName) {
|
||||
if slices.Contains(config.Config().IgnorePkgUpdates, pkgName) {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(pkgs) > 1 {
|
||||
// Puts the element with the highest version first
|
||||
slices.SortFunc(pkgs, func(a, b db.Package) bool {
|
||||
return vercmp.Compare(a.Version, b.Version) == 1
|
||||
slices.SortFunc(pkgs, func(a, b db.Package) int {
|
||||
return vercmp.Compare(a.Version, b.Version)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
165
vercmp/vercmp.go
165
vercmp/vercmp.go
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 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 vercmp
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Compare compares two version strings.
|
||||
// It returns 1 if v1 is greater,
|
||||
// 0 if the versions are equal,
|
||||
// and -1 if v2 is greater
|
||||
func Compare(v1, v2 string) int {
|
||||
if v1 == v2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return sepVerCmp(sepLabel(v1), sepLabel(v2))
|
||||
}
|
||||
|
||||
func sepVerCmp(e1, e2 []string) int {
|
||||
if slices.Equal(e1, e2) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// proc stores the amount of elements processed
|
||||
proc := 0
|
||||
|
||||
for i := 0; i < len(e1); i++ {
|
||||
proc++
|
||||
|
||||
if i >= len(e2) {
|
||||
return 1
|
||||
}
|
||||
|
||||
elem1 := e1[i]
|
||||
elem2 := e2[i]
|
||||
|
||||
if elem1 == elem2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if isNumElem(elem1) && isNumElem(elem2) {
|
||||
elem1v, err := strconv.ParseInt(elem1, 10, 64)
|
||||
if err != nil {
|
||||
// error should never happen due to isNumElem()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
elem2v, err := strconv.ParseInt(elem2, 10, 64)
|
||||
if err != nil {
|
||||
// error should never happen due to isNumElem()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if elem1v > elem2v {
|
||||
return 1
|
||||
} else if elem1v < elem2v {
|
||||
return -1
|
||||
}
|
||||
} else if isNumElem(elem1) && isAlphaElem(elem2) {
|
||||
return 1
|
||||
} else if isAlphaElem(elem1) && isNumElem(elem2) {
|
||||
return -1
|
||||
} else if isAlphaElem(elem1) && isAlphaElem(elem2) {
|
||||
if elem1 > elem2 {
|
||||
return 1
|
||||
} else if elem1 < elem2 {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if proc < len(e2) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func sepLabel(label string) []string {
|
||||
const (
|
||||
other = iota
|
||||
alpha
|
||||
num
|
||||
)
|
||||
|
||||
var (
|
||||
curType uint8
|
||||
out []string
|
||||
sb strings.Builder
|
||||
)
|
||||
|
||||
for _, char := range label {
|
||||
if isNum(char) {
|
||||
if curType != num && curType != other {
|
||||
out = append(out, sb.String())
|
||||
sb.Reset()
|
||||
}
|
||||
|
||||
sb.WriteRune(char)
|
||||
curType = num
|
||||
} else if isAlpha(char) {
|
||||
if curType != alpha && curType != other {
|
||||
out = append(out, sb.String())
|
||||
sb.Reset()
|
||||
}
|
||||
|
||||
sb.WriteRune(char)
|
||||
curType = alpha
|
||||
} else {
|
||||
if curType != other {
|
||||
out = append(out, sb.String())
|
||||
sb.Reset()
|
||||
}
|
||||
curType = other
|
||||
}
|
||||
}
|
||||
|
||||
if sb.Len() != 0 {
|
||||
out = append(out, sb.String())
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func isNumElem(s string) bool {
|
||||
// Check only the first rune as all elements
|
||||
// should consist of the same type of rune
|
||||
return isNum([]rune(s[:1])[0])
|
||||
}
|
||||
|
||||
func isNum(r rune) bool {
|
||||
return r >= '0' && r <= '9'
|
||||
}
|
||||
|
||||
func isAlphaElem(s string) bool {
|
||||
// Check only the first rune as all elements
|
||||
// should consist of the same type of rune
|
||||
return isAlpha([]rune(s[:1])[0])
|
||||
}
|
||||
|
||||
func isAlpha(r rune) bool {
|
||||
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2023 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 vercmp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func TestSepLabel(t *testing.T) {
|
||||
type item struct {
|
||||
label string
|
||||
expected []string
|
||||
}
|
||||
|
||||
table := []item{
|
||||
{"2.0.1", []string{"2", "0", "1"}},
|
||||
{"v0.0.1", []string{"v", "0", "0", "1"}},
|
||||
{"2xFg33.+f.5", []string{"2", "xFg", "33", "f", "5"}},
|
||||
}
|
||||
|
||||
for _, it := range table {
|
||||
t.Run(it.label, func(t *testing.T) {
|
||||
s := sepLabel(it.label)
|
||||
if !slices.Equal(s, it.expected) {
|
||||
t.Errorf("Expected %v, got %v", it.expected, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerCmp(t *testing.T) {
|
||||
type item struct {
|
||||
v1, v2 string
|
||||
expected int
|
||||
}
|
||||
|
||||
table := []item{
|
||||
{"1.0010", "1.9", 1},
|
||||
{"1.05", "1.5", 0},
|
||||
{"1.0", "1", 1},
|
||||
{"1", "1.0", -1},
|
||||
{"2.50", "2.5", 1},
|
||||
{"FC5", "fc4", -1},
|
||||
{"2a", "2.0", -1},
|
||||
{"1.0", "1.fc4", 1},
|
||||
{"3.0.0_fc", "3.0.0.fc", 0},
|
||||
{"4.1__", "4.1+", 0},
|
||||
}
|
||||
|
||||
for _, it := range table {
|
||||
t.Run(it.v1+"/"+it.v2, func(t *testing.T) {
|
||||
c := Compare(it.v1, it.v2)
|
||||
if c != it.expected {
|
||||
t.Errorf("Expected %d, got %d", it.expected, c)
|
||||
}
|
||||
|
||||
// Ensure opposite comparison gives opposite value
|
||||
c = -Compare(it.v2, it.v1)
|
||||
if c != it.expected {
|
||||
t.Errorf("Expected %d, got %d (opposite)", it.expected, c)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user