11 Commits

Author SHA1 Message Date
80a45cd595 v0.9.1
All checks were successful
ci/woodpecker/push/publish-docs Pipeline was successful
ci/woodpecker/tag/gitea Pipeline was successful
ci/woodpecker/tag/publish-docs Pipeline was successful
ci/woodpecker/release/publish-docs Pipeline was successful
2025-03-01 01:57:51 -06:00
551c8ad441 get S3 profile using env AWS_PROFILE 2025-03-01 01:57:33 -06:00
3823b1bf44 get S3 profile using env AWS_PROFILE 2025-03-01 01:57:05 -06:00
f777c78aad v0.9.0
All checks were successful
ci/woodpecker/push/publish-docs Pipeline was successful
ci/woodpecker/tag/gitea Pipeline was successful
ci/woodpecker/tag/publish-docs Pipeline was successful
ci/woodpecker/release/publish-docs Pipeline was successful
2025-02-28 17:52:28 -06:00
bb693dbb97 bump version
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed
2025-02-28 17:49:51 -06:00
7beda281e0 fixed constant typo
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed
2025-02-28 17:49:01 -06:00
1143d2850b added beginning of tests
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed
2025-02-28 17:40:32 -06:00
8900bd70a4 changed PackageOperation to enums 2025-02-28 17:39:08 -06:00
6db5f73bc0 fetch env file where config file is stored
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed
2025-02-25 21:19:17 -06:00
a163c11129 v0.9.0
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed
ci/woodpecker/push/publish-docs Pipeline was successful
2025-02-23 22:10:42 -06:00
2b4d191271 v0.9.0
Some checks are pending
ci/woodpecker/push/go-lint Pipeline is pending
2025-02-23 21:18:46 -06:00
28 changed files with 406 additions and 111 deletions

View File

@ -1,3 +0,0 @@
kind: Added
body: '`list` command with subcommands `cmds` and `lists`'
time: 2025-02-20T14:45:49.562361581-06:00

View File

@ -1,3 +0,0 @@
kind: Added
body: Deprecation and unsupported warnings for old config keys
time: 2025-02-20T14:50:14.048452348-06:00

View File

@ -1,3 +0,0 @@
kind: Added
body: CLI flag `--cmdStdOut` to output command's stdout/stderr to stdout
time: 2025-02-20T14:52:45.030582408-06:00

View File

@ -1,3 +0,0 @@
kind: Added
body: Command type `remoteScript`. See docs for more info.
time: 2025-02-21T00:30:12.276616792-06:00

View File

@ -1,3 +0,0 @@
kind: Changed
body: change to enums for Command type
time: 2025-02-23T15:30:12.033359922-06:00

View File

@ -1,3 +0,0 @@
kind: Changed
body: Cache now stores resources by URL hash for ease-of-lookup
time: 2025-02-23T15:33:05.33444642-06:00

View File

@ -1,3 +0,0 @@
kind: Fixed
body: Local command's `dir` full path is now found with home directory
time: 2025-02-20T14:48:43.475300515-06:00

12
.changes/v0.9.0.md Normal file
View File

@ -0,0 +1,12 @@
## v0.9.0 - 2025-02-28
### Added
* `list` command with subcommands `cmds` and `lists`
* Deprecation and unsupported warnings for old config keys
* CLI flag `--cmdStdOut` to output command's stdout/stderr to stdout
* Command type `remoteScript`. See docs for more info.
### Changed
* change to enums for Command type
* Cache now stores resources by URL hash for ease-of-lookup
* Changed PackageOperation to enums
### Fixed
* Local command's `dir` full path is now found with home directory

3
.changes/v0.9.1.md Normal file
View File

@ -0,0 +1,3 @@
## v0.9.1 - 2025-03-01
### Changed
* Use EnvVar AWS_PROFILE to get S3 profile

View File

@ -6,6 +6,23 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v0.9.1 - 2025-03-01
### Changed
* Use EnvVar AWS_PROFILE to get S3 profile
## v0.9.0 - 2025-02-28
### Added
* `list` command with subcommands `cmds` and `lists`
* Deprecation and unsupported warnings for old config keys
* CLI flag `--cmdStdOut` to output command's stdout/stderr to stdout
* Command type `remoteScript`. See docs for more info.
### Changed
* change to enums for Command type
* Cache now stores resources by URL hash for ease-of-lookup
* Changed PackageOperation to enums
### Fixed
* Local command's `dir` full path is now found with home directory
## v0.8.0 - 2025-02-15
### Changed
* Breaking: `cmd-lists` key changed to `cmdLists`

View File

@ -7,8 +7,11 @@
],
"settings": {
"cSpell.words": [
"Autorestic",
"changie",
"Cmds",
"CMDSTDOUT",
"goreleaser",
"knadh",
"koanf",
"mattn",

View File

@ -18,7 +18,11 @@ var (
func cron(cmd *cobra.Command, args []string) {
parseS3Config()
opts := backy.NewOpts(cfgFile, backy.EnableCron(), backy.SetLogFile(logFile), backy.SetCmdStdOut(cmdStdOut))
opts := backy.NewOpts(cfgFile,
backy.EnableCron(),
backy.SetLogFile(logFile),
backy.SetCmdStdOut(cmdStdOut))
opts.InitConfig()
opts.ReadConfig()

View File

@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra"
)
const versionStr = "0.8.0"
const versionStr = "0.9.1"
var (
versionCmd = &cobra.Command{

View File

@ -167,3 +167,39 @@ Global Flags:
Use "backy list [command] --help" for more information about a command.
```
## list cmds
```
List commands defined in config file
Usage:
backy list cmds [cmd1 cmd2 cmd3...] [flags]
Flags:
-h, --help help for cmds
Global Flags:
--cmdStdOut Pass to print command output to stdout
-f, --config string config file to read from
--log-file string log file to write to
--s3-endpoint string Sets the S3 endpoint used for config file fetching. Overrides S3_ENDPOINT env variable.
-v, --verbose Sets verbose level
```
## list lists
```
List lists defined in config file
Usage:
backy list lists [list1 list2 ...] [flags]
Flags:
-h, --help help for lists
Global Flags:
--cmdStdOut Pass to print command output to stdout
-f, --config string config file to read from
--log-file string log file to write to
--s3-endpoint string Sets the S3 endpoint used for config file fetching. Overrides S3_ENDPOINT env variable.
-v, --verbose Sets verbose level
```

View File

@ -15,5 +15,5 @@ The `exec` subcommand can do some things that the configuration file can't do ye
The commands have to be defined in the config file. The hosts need to at least be in the ssh_config(5) file.
```sh
backy exec host [--commands command1 -commands command2 ... | -c command1 -c command2 ...] [--hosts host1 --hosts hosts2 ... | -m host1 -c host2 ...] [flags]
backy exec host [--commands=command1 -commands=command2 ... | -c command1 -c command2 ...] [--hosts=host1 --hosts=hosts2 ... | -m host1 -c host2 ...] [flags]
```

View File

@ -12,6 +12,10 @@ For the main config file to be fetched remotely, pass the URL using `-f [url]`.
If using S3, you should use the s3 protocol URI: `s3://bucketName/key/path`. You will also need to set the env variable `S3_ENDPOINT` to the appropriate value. The flag `--s3-endpoint` can be used to override this value or to set this value, if not already set.
## Authentication
Currently, only the AWS authentication credentials file `~/.aws/credentials` is supported. For now, the environment variable `AWS_PROFILE` is used to lookup the profile.
## Scripts
Scripts will be coming later.
Remote script support is currently limited to http/https endpoints.

View File

@ -1,67 +1,83 @@
#!/bin/bash
CLI_PAGE="docs/content/cli/_index.md"
BACKYCOMMAND="go run backy.go"
{
echo "---
title: "CLI"
title: CLI
weight: 4
---
This page lists documentation for the CLI.
" > _index.md
"
BACKYCOMMAND="go run backy.go"
echo "## Backy " >> _index.md
echo " " >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} -h >> _index.md"
echo "\`\`\`" >> _index.md
echo " " >> _index.md
echo "## Backy "
echo " "
echo "\`\`\`"
eval "${BACKYCOMMAND} -h"
echo "\`\`\`"
echo " "
echo "# Subcommands" >> _index.md
echo "" >> _index.md
echo "## backup" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} backup -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "" >> _index.md
echo "# Subcommands"
echo ""
echo "## cron" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} cron -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "" >> _index.md
echo "## backup"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} backup -h"
echo "\`\`\`"
echo ""
echo "## exec" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} exec -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "" >> _index.md
echo "## cron"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} cron -h"
echo "\`\`\`"
echo ""
echo "### exec host" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} exec host -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "" >> _index.md
echo "## exec"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} exec -h"
echo "\`\`\`"
echo ""
echo "### exec host"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} exec host -h"
echo "\`\`\`"
echo ""
echo "## version" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} version -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "" >> _index.md
echo "## version"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} version -h"
echo "\`\`\`"
echo ""
echo "## list" >> _index.md
echo "" >> _index.md
echo "\`\`\`" >> _index.md
eval "${BACKYCOMMAND} list -h >> _index.md"
echo "\`\`\`" >> _index.md
echo "## list"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} list -h"
echo "\`\`\`"
echo "## list cmds"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} list cmds -h"
echo "\`\`\`"
echo "## list lists"
echo ""
echo "\`\`\`"
eval "${BACKYCOMMAND} list lists -h"
echo "\`\`\`"
} >> _index.md
mv _index.md "$CLI_PAGE"

View File

@ -68,7 +68,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
} else {
// Handle package operations
if command.Type == PackageCT && command.PackageOperation == "checkVersion" {
if command.Type == PackageCT && command.PackageOperation == PackOpCheckVersion {
cmdCtxLogger.Info().Str("package", command.PackageName).Msg("Checking package versions")
// Execute the package version command

View File

@ -53,7 +53,7 @@ func (opts *ConfigOpts) InitConfig() {
cacheDir := homeCacheDir
// Load metadata from file
opts.CachedData, err = remotefetcher.LoadMetadataFromFile(path.Join(backyHomeConfDir, "cache.yml"))
opts.CachedData, err = remotefetcher.LoadMetadataFromFile(path.Join(backyHomeConfDir, "cache", "cache.yml"))
if err != nil {
fmt.Println("Error loading metadata:", err)
logging.ExitWithMSG(err.Error(), 1, &opts.Logger)
@ -77,11 +77,13 @@ func (opts *ConfigOpts) InitConfig() {
if err != nil {
logging.ExitWithMSG(fmt.Sprintf("error initializing cache: %v", err), 1, nil)
}
// Initialize the fetcher
// println("Creating new fetcher for source", opts.ConfigFilePath)
fetcher, err := remotefetcher.NewRemoteFetcher(opts.ConfigFilePath, opts.Cache)
// println("Created new fetcher for source", opts.ConfigFilePath)
fetcher, err := remotefetcher.NewRemoteFetcher(opts.ConfigFilePath, opts.Cache)
if isRemoteURL(opts.ConfigFilePath) {
p, _ := getRemoteDir(opts.ConfigFilePath)
opts.ConfigDir = p
}
if err != nil {
logging.ExitWithMSG(fmt.Sprintf("error initializing config fetcher: %v", err), 1, nil)
}
@ -274,20 +276,22 @@ func resolveProxyHosts(host *Host, opts *ConfigOpts) {
}
func loadCommandLists(opts *ConfigOpts, backyKoanf *koanf.Koanf) {
var backyConfigFileDir string
var listConfigFiles []string
var u *url.URL
var p string
// if config file is remote, use the directory of the remote file
if isRemoteURL(opts.ConfigFilePath) {
_, u = getRemoteDir(opts.ConfigFilePath)
p, u = getRemoteDir(opts.ConfigFilePath)
opts.ConfigDir = p
println(p)
// // Still use local list files if a remote config file is used, but use them last
listConfigFiles = []string{u.JoinPath("lists.yml").String(), u.JoinPath("lists.yaml").String()}
} else {
backyConfigFileDir = path.Dir(opts.ConfigFilePath)
opts.ConfigDir = path.Dir(opts.ConfigFilePath)
listConfigFiles = []string{
// "./lists.yml", "./lists.yaml",
path.Join(backyConfigFileDir, "lists.yml"),
path.Join(backyConfigFileDir, "lists.yaml"),
path.Join(opts.ConfigDir, "lists.yml"),
path.Join(opts.ConfigDir, "lists.yaml"),
}
}
@ -327,7 +331,6 @@ func loadListConfigFile(filePath string, k *koanf.Koanf, opts *ConfigOpts) bool
if err != nil {
// if file not found, ignore
if errors.Is(err, remotefetcher.ErrIgnoreFileNotFound) {
println("File not found", filePath)
return true
}
@ -582,7 +585,7 @@ func processCmds(opts *ConfigOpts) error {
if cmd.PackageManager == "" {
return fmt.Errorf("package manager is required for package command %s", cmd.PackageName)
}
if cmd.PackageOperation == "" {
if cmd.PackageOperation.String() == "" {
return fmt.Errorf("package operation is required for package command %s", cmd.PackageName)
}
if cmd.PackageName == "" {
@ -591,15 +594,16 @@ func processCmds(opts *ConfigOpts) error {
var err error
// Validate the operation
switch cmd.PackageOperation {
case "install", "remove", "upgrade", "checkVersion":
if cmd.PackageOperation.IsAPackageOperation() {
cmd.pkgMan, err = pkgman.PackageManagerFactory(cmd.PackageManager, pkgman.WithoutAuth())
if err != nil {
return err
}
default:
} else {
return fmt.Errorf("unsupported package operation %s for command %s", cmd.PackageOperation, cmd.Name)
}
}
// Parse user commands

View File

@ -0,0 +1,145 @@
// Code generated by "enumer -linecomment -yaml -text -json -type=PackageOperation"; DO NOT EDIT.
package backy
import (
"encoding/json"
"fmt"
"strings"
)
const _PackageOperationName = "installupgradepurgeremovecheckVersionisInstalled"
var _PackageOperationIndex = [...]uint8{0, 0, 7, 14, 19, 25, 37, 48}
const _PackageOperationLowerName = "installupgradepurgeremovecheckversionisinstalled"
func (i PackageOperation) String() string {
if i < 0 || i >= PackageOperation(len(_PackageOperationIndex)-1) {
return fmt.Sprintf("PackageOperation(%d)", i)
}
return _PackageOperationName[_PackageOperationIndex[i]:_PackageOperationIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PackageOperationNoOp() {
var x [1]struct{}
_ = x[DefaultPO-(0)]
_ = x[PackOpInstall-(1)]
_ = x[PackOpUpgrade-(2)]
_ = x[PackOpPurge-(3)]
_ = x[PackOpRemove-(4)]
_ = x[PackOpCheckVersion-(5)]
_ = x[PackOpIsInstalled-(6)]
}
var _PackageOperationValues = []PackageOperation{DefaultPO, PackOpInstall, PackOpUpgrade, PackOpPurge, PackOpRemove, PackOpCheckVersion, PackOpIsInstalled}
var _PackageOperationNameToValueMap = map[string]PackageOperation{
_PackageOperationName[0:0]: DefaultPO,
_PackageOperationLowerName[0:0]: DefaultPO,
_PackageOperationName[0:7]: PackOpInstall,
_PackageOperationLowerName[0:7]: PackOpInstall,
_PackageOperationName[7:14]: PackOpUpgrade,
_PackageOperationLowerName[7:14]: PackOpUpgrade,
_PackageOperationName[14:19]: PackOpPurge,
_PackageOperationLowerName[14:19]: PackOpPurge,
_PackageOperationName[19:25]: PackOpRemove,
_PackageOperationLowerName[19:25]: PackOpRemove,
_PackageOperationName[25:37]: PackOpCheckVersion,
_PackageOperationLowerName[25:37]: PackOpCheckVersion,
_PackageOperationName[37:48]: PackOpIsInstalled,
_PackageOperationLowerName[37:48]: PackOpIsInstalled,
}
var _PackageOperationNames = []string{
_PackageOperationName[0:0],
_PackageOperationName[0:7],
_PackageOperationName[7:14],
_PackageOperationName[14:19],
_PackageOperationName[19:25],
_PackageOperationName[25:37],
_PackageOperationName[37:48],
}
// PackageOperationString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PackageOperationString(s string) (PackageOperation, error) {
if val, ok := _PackageOperationNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PackageOperationNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to PackageOperation values", s)
}
// PackageOperationValues returns all values of the enum
func PackageOperationValues() []PackageOperation {
return _PackageOperationValues
}
// PackageOperationStrings returns a slice of all String values of the enum
func PackageOperationStrings() []string {
strs := make([]string, len(_PackageOperationNames))
copy(strs, _PackageOperationNames)
return strs
}
// IsAPackageOperation returns "true" if the value is listed in the enum definition. "false" otherwise
func (i PackageOperation) IsAPackageOperation() bool {
for _, v := range _PackageOperationValues {
if i == v {
return true
}
}
return false
}
// MarshalJSON implements the json.Marshaler interface for PackageOperation
func (i PackageOperation) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
// UnmarshalJSON implements the json.Unmarshaler interface for PackageOperation
func (i *PackageOperation) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return fmt.Errorf("PackageOperation should be a string, got %s", data)
}
var err error
*i, err = PackageOperationString(s)
return err
}
// MarshalText implements the encoding.TextMarshaler interface for PackageOperation
func (i PackageOperation) MarshalText() ([]byte, error) {
return []byte(i.String()), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface for PackageOperation
func (i *PackageOperation) UnmarshalText(text []byte) error {
var err error
*i, err = PackageOperationString(string(text))
return err
}
// MarshalYAML implements a YAML Marshaler for PackageOperation
func (i PackageOperation) MarshalYAML() (interface{}, error) {
return i.String(), nil
}
// UnmarshalYAML implements a YAML Unmarshaler for PackageOperation
func (i *PackageOperation) UnmarshalYAML(unmarshal func(interface{}) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
}
var err error
*i, err = PackageOperationString(s)
return err
}

View File

@ -538,7 +538,7 @@ func (command *Command) RunCmdSSH(cmdCtxLogger zerolog.Logger, opts *ConfigOpts)
case ScriptFileCT:
return command.runScriptFile(commandSession, cmdCtxLogger, &cmdOutBuf)
case PackageCT:
if command.PackageOperation == "checkVersion" {
if command.PackageOperation == PackOpCheckVersion {
commandSession.Stderr = nil
// Execute the package version command remotely
// Parse the output of package version command

View File

@ -106,7 +106,7 @@ type (
PackageVersion string `yaml:"packageVersion,omitempty"`
// PackageOperation specifies the action for package-related commands (e.g., "install" or "remove")
PackageOperation string `yaml:"packageOperation,omitempty"`
PackageOperation PackageOperation `yaml:"packageOperation,omitempty"`
pkgMan pkgman.PackageManager
@ -204,13 +204,12 @@ type (
CmdStdOut bool
// Holds config file
ConfigFilePath string
// Holds log file
ConfigDir string
LogFilePath string
// for command list file
CmdListFile string
// use command lists using cron
@ -294,7 +293,10 @@ type (
ListName string // Name of the command list
Error error // Error encountered, if any
}
// use ints so we can use enums
CommandType int
PackageOperation int
)
//go:generate go run github.com/dmarkham/enumer -linecomment -yaml -text -json -type=CommandType
@ -306,3 +308,14 @@ const (
PackageCT // package
UserCT // user
)
//go:generate go run github.com/dmarkham/enumer -linecomment -yaml -text -json -type=PackageOperation
const (
DefaultPO PackageOperation = iota //
PackOpInstall // install
PackOpUpgrade // upgrade
PackOpPurge // purge
PackOpRemove // remove
PackOpCheckVersion // checkVersion
PackOpIsInstalled // isInstalled
)

View File

@ -15,6 +15,7 @@ import (
"strings"
"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
"git.andrewnw.xyz/CyberShell/backy/pkg/remotefetcher"
"github.com/joho/godotenv"
"github.com/knadh/koanf/v2"
"github.com/rs/zerolog"
@ -216,13 +217,33 @@ func getFullPathWithHomeDir(path string) (string, error) {
// loadEnv loads a .env file from the config file directory
func (opts *ConfigOpts) loadEnv() {
envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.ConfigFilePath))
var backyEnv map[string]string
backyEnv, envFileErr := godotenv.Read(envFileInConfigDir)
var envFileInConfigDir string
var envFileErr error
if isRemoteURL(opts.ConfigFilePath) {
_, u := getRemoteDir(opts.ConfigFilePath)
envFileInConfigDir = u.JoinPath(".env").String()
envFetcher, err := remotefetcher.NewRemoteFetcher(envFileInConfigDir, opts.Cache)
if err != nil {
return
}
data, err := envFetcher.Fetch(envFileInConfigDir)
if err != nil {
return
}
backyEnv, envFileErr = godotenv.UnmarshalBytes(data)
if envFileErr != nil {
return
}
} else {
envFileInConfigDir = fmt.Sprintf("%s/.env", path.Dir(opts.ConfigFilePath))
backyEnv, envFileErr = godotenv.Read(envFileInConfigDir)
if envFileErr != nil {
return
}
}
opts.backyEnv = backyEnv
}
@ -251,21 +272,18 @@ func expandEnvVars(backyEnv map[string]string, envVars []string) {
}
}
// getCommandTypeAndSetCommandInfo checks for command type and if the command has already been set
// Checks for types package and user
// Returns the modified Command with the package- or userManager command as Cmd and the package- or userOperation as args, plus any additional Args
func getCommandTypeAndSetCommandInfo(command *Command) *Command {
if command.Type == PackageCT && !command.packageCmdSet {
command.packageCmdSet = true
switch command.PackageOperation {
case "install":
case PackOpInstall:
command.Cmd, command.Args = command.pkgMan.Install(command.PackageName, command.PackageVersion, command.Args)
case "remove":
case PackOpRemove:
command.Cmd, command.Args = command.pkgMan.Remove(command.PackageName, command.Args)
case "upgrade":
case PackOpUpgrade:
command.Cmd, command.Args = command.pkgMan.Upgrade(command.PackageName, command.PackageVersion)
case "checkVersion":
case PackOpCheckVersion:
command.Cmd, command.Args = command.pkgMan.CheckVersion(command.PackageName, command.PackageVersion)
}
}

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"sync"
@ -72,7 +73,7 @@ func (c *Cache) saveToFile() error {
for _, data := range c.store {
cacheData = append(cacheData, data)
}
cacheData = unique(cacheData)
data, err := yaml.Marshal(cacheData)
if err != nil {
return err
@ -170,6 +171,7 @@ func (cf *CachedFetcher) Hash(data []byte) string {
func LoadMetadataFromFile(filePath string) ([]*CacheData, error) {
if _, err := os.Stat(filePath); os.IsNotExist(err) {
// Create the file if it does not exist
os.MkdirAll(path.Dir(filePath), 0700)
emptyData := []byte("[]")
err := os.WriteFile(filePath, emptyData, 0644)
if err != nil {
@ -184,6 +186,7 @@ func LoadMetadataFromFile(filePath string) ([]*CacheData, error) {
var cacheData []*CacheData
err = yaml.Unmarshal(data, &cacheData)
if err != nil {
return nil, err
}
@ -195,3 +198,23 @@ func HashURL(url string) string {
hash := sha256.Sum256([]byte(url))
return hex.EncodeToString(hash[:])
}
func unique(cache []CacheData) []CacheData {
var unique []CacheData
type key struct{ value1, value2, value3, value4 string }
m := make(map[key]int)
for _, v := range cache {
k := key{v.URL, v.Hash, v.Path, v.Type}
if i, ok := m[k]; ok {
// Overwrite previous value per requirement in
// question to keep last matching value.
unique[i] = v
} else {
// Unique key found. Record position and collect
// in result.
m[k] = len(unique)
unique = append(unique, v)
}
}
return unique
}

View File

@ -59,6 +59,7 @@ func NewRemoteFetcher(source string, cache *Cache, options ...FetcherOption) (Re
URLHash := HashURL(source)
if cachedData, cacheMeta, exists := cache.Get(URLHash); exists {
println(cachedData)
return &CachedFetcher{data: cachedData, path: cacheMeta.Path, dataType: cacheMeta.Type}, nil
}

View File

@ -44,11 +44,11 @@ func NewS3Fetcher(endpoint string, options ...FetcherOption) (*S3Fetcher, error)
*/
s3Endpoint := os.Getenv("S3_ENDPOINT")
creds, err := getS3Credentials("default", s3Endpoint, cfg.HTTPClient)
creds, err := getS3Credentials(os.Getenv("AWS_PROFILE"), s3Endpoint, cfg.HTTPClient)
if err != nil {
println(err.Error())
return nil, err
}
// Initialize S3 client if not provided
if cfg.S3Client == nil {
s3Client, err = minio.New(s3Endpoint, &minio.Options{
@ -128,12 +128,11 @@ func (s *S3Fetcher) Hash(data []byte) string {
}
func getS3Credentials(profile, host string, httpClient *http.Client) (*credentials.Credentials, error) {
// println(s3utils.GetRegionFromURL(*u))
homeDir, hdirErr := homedir.Dir()
if hdirErr != nil {
return nil, hdirErr
}
s3Creds := credentials.NewFileAWSCredentials(path.Join(homeDir, ".aws", "credentials"), "default")
s3Creds := credentials.NewFileAWSCredentials(path.Join(homeDir, ".aws", "credentials"), profile)
credVals, credErr := s3Creds.GetWithContext(&credentials.CredContext{Endpoint: host, Client: httpClient})
if credErr != nil {
return nil, credErr

View File

@ -1,7 +1,7 @@
#!/bin/bash
set -eou pipefail
go generate ./...
export CURRENT_TAG="$(go run backy.go version -V)"
CURRENT_TAG="$(go run backy.go version -V)"
goreleaser -f .goreleaser/github.yml check
goreleaser -f .goreleaser/gitea.yml check
changie batch $CURRENT_TAG

18
tests/backy.yaml Normal file
View File

@ -0,0 +1,18 @@
commands:
echoTestPass:
cmd: echo
shell: bash
Args: hello world
runRemoteShellScriptSuccess:
cmd:
packageCommandSuccess:
packageName: docker-ce
Args:
- docker-ce-cli
packageManager: apt
packageOperation: install