Skip to content

Commit

Permalink
add "profile" flag as an alias for "name" (#357)
Browse files Browse the repository at this point in the history
* add "profile" flag as an alias for "name"
  • Loading branch information
creativeprojects authored Apr 3, 2024
1 parent f9b5dac commit 6b00c2c
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 106 deletions.
2 changes: 1 addition & 1 deletion config/mocks/NamedPropertySet.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion config/mocks/ProfileInfo.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion config/mocks/PropertyInfo.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion config/mocks/SectionInfo.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 50 additions & 19 deletions flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ func loadFlags(args []string) (*pflag.FlagSet, commandLineFlags, error) {
flagset.IntVar(&flags.ignoreOnBattery, "ignore-on-battery", flags.ignoreOnBattery, "don't start the profile when the computer is running on battery. You can specify a value to ignore only when the % charge left is less or equal than the value")
flagset.Lookup("ignore-on-battery").NoOptDefVal = "100" // 0 is flag not set, 100 is for a flag with no value (meaning just battery discharge)

flagset.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
switch name {
case "profile":
name = "name"
}
return pflag.NormalizedName(name)
})

if platform.IsWindows() {
// flag for internal use only
flagset.BoolVar(&flags.isChild, constants.FlagAsChild, false, "run as an elevated user child process")
Expand Down Expand Up @@ -148,27 +156,50 @@ func loadFlags(args []string) (*pflag.FlagSet, commandLineFlags, error) {

// parse first positional argument as <profile>.<command> if the profile was not set via name
nameFlag := flagset.Lookup("name")
if (nameFlag == nil || !nameFlag.Changed) && strings.Contains(flags.resticArgs[0], ".") {
// split first argument at `.`
profileAndCommand := strings.Split(flags.resticArgs[0], ".")
// last element will be used as restic command
command := profileAndCommand[len(profileAndCommand)-1]
// remaining elements will be stiched together with `.` and used as profile name
profile := strings.Join(profileAndCommand[0:len(profileAndCommand)-1], ".")

// set command
if len(command) == 0 {
// take default command by removing it from resticArgs
flags.resticArgs = flags.resticArgs[1:]
} else {
flags.resticArgs[0] = command
}
if nameFlag == nil || !nameFlag.Changed {
if strings.Contains(flags.resticArgs[0], ".") {
// split first argument at `.`
profileAndCommand := strings.Split(flags.resticArgs[0], ".")
// last element will be used as restic command
command := profileAndCommand[len(profileAndCommand)-1]
// remaining elements will be stitched together with `.` and used as profile name
profile := strings.Join(profileAndCommand[0:len(profileAndCommand)-1], ".")

// set command
if len(command) == 0 {
// take default command by removing it from resticArgs
flags.resticArgs = flags.resticArgs[1:]
} else {
flags.resticArgs[0] = command
}

// set profile
if len(profile) == 0 {
profile = constants.DefaultProfileName
// set profile
if len(profile) == 0 {
profile = constants.DefaultProfileName
}
flags.name = profile
} else if strings.Contains(flags.resticArgs[0], "@") {
// split first argument at `@`
commandAndProfile := strings.Split(flags.resticArgs[0], "@")
// first element will be used as restic command
command := commandAndProfile[0]
// last element(s) will be used as profile name
profile := strings.Join(commandAndProfile[1:], "@")

// set command
if len(command) == 0 {
// take default command by removing it from resticArgs
flags.resticArgs = flags.resticArgs[1:]
} else {
flags.resticArgs[0] = command
}

// set profile
if len(profile) == 0 {
profile = constants.DefaultProfileName
}
flags.name = profile
}
flags.name = profile
}

return flagset, flags, nil
Expand Down
218 changes: 138 additions & 80 deletions flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -115,84 +116,141 @@ func TestEnvOverridesError(t *testing.T) {
assert.Contains(t, mem.Logs(), `cannot convert env variable RESTICPROFILE_LOCK_WAIT="no-valid-duration": time: invalid duration "no-valid-duration"`)
}

func TestProfileCommandWithProfileNamePrecedence(t *testing.T) {
_, flags, err := loadFlags([]string{"-n", "profile2", "-v", "some.command"})
require.NoError(t, err)
assert.Equal(t, flags.name, "profile2")
assert.True(t, flags.verbose)
assert.Equal(t, flags.resticArgs, []string{"some.command"})
}

func TestProfileCommandWithProfileNamePrecedenceWithDefaultProfile(t *testing.T) {
_, flags, err := loadFlags([]string{"-n", constants.DefaultProfileName, "-v", "some.other.command"})
require.NoError(t, err)
assert.Equal(t, flags.name, constants.DefaultProfileName)
assert.True(t, flags.verbose)
assert.Equal(t, flags.resticArgs, []string{"some.other.command"})
}

func TestProfileCommandWithResticVerbose(t *testing.T) {
_, flags, err := loadFlags([]string{"profile1.check", "--", "-v"})
require.NoError(t, err)
assert.False(t, flags.help)
assert.Equal(t, flags.name, "profile1")
assert.False(t, flags.verbose)
assert.Equal(t, flags.resticArgs, []string{"check", "--", "-v"})
}

func TestProfileCommandWithResticprofileVerbose(t *testing.T) {
_, flags, err := loadFlags([]string{"-v", "pro.file1.backup"})
require.NoError(t, err)
assert.True(t, flags.verbose)
assert.Equal(t, flags.name, "pro.file1")
assert.Equal(t, flags.resticArgs, []string{"backup"})
}

func TestProfileCommandThreePart(t *testing.T) {
_, flags, err := loadFlags([]string{"bla.foo.backup"})
require.NoError(t, err)
assert.Equal(t, flags.name, "bla.foo")
assert.Equal(t, flags.resticArgs, []string{"backup"})
}

func TestProfileCommandTwoPartCommandMissing(t *testing.T) {
_, flags, err := loadFlags([]string{"bar."})
require.NoError(t, err)
assert.Equal(t, flags.name, "bar")
assert.Equal(t, flags.resticArgs, []string{})
}

func TestProfileCommandTwoPartProfileMissing(t *testing.T) {
_, flags, err := loadFlags([]string{".baz"})
require.NoError(t, err)
assert.Equal(t, flags.name, constants.DefaultProfileName)
assert.Equal(t, flags.resticArgs, []string{"baz"})
}

func TestProfileCommandTwoPartDotPrefix(t *testing.T) {
_, flags, err := loadFlags([]string{".baz.qux"})
require.NoError(t, err)
assert.Equal(t, flags.name, ".baz")
assert.Equal(t, flags.resticArgs, []string{"qux"})
}

func TestProfileCommandThreePartCommandMissing(t *testing.T) {
_, flags, err := loadFlags([]string{"quux.quuz."})
require.NoError(t, err)
assert.Equal(t, flags.name, "quux.quuz")
assert.Equal(t, flags.resticArgs, []string{})
}

func TestProfileCommandTwoPartDotPrefixCommandMissing(t *testing.T) {
_, flags, err := loadFlags([]string{".corge."})
require.NoError(t, err)
assert.Equal(t, flags.name, ".corge")
assert.Equal(t, flags.resticArgs, []string{})
}

func TestProfileCommandTwoPartProfileMissingCommandMissing(t *testing.T) {
_, flags, err := loadFlags([]string{"."})
require.NoError(t, err)
assert.Equal(t, flags.name, constants.DefaultProfileName)
assert.Equal(t, flags.resticArgs, []string{})
func TestCommandProfileOrProfileCommandShortcuts(t *testing.T) {
t.Parallel()
testCases := []struct {
sourceArgs []string
expectedProfile string
expectedArgs []string
expectedVerbose bool
}{
{
sourceArgs: []string{"."},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{},
},
{
sourceArgs: []string{".command"},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"profile."},
expectedProfile: "profile",
expectedArgs: []string{},
},
{
sourceArgs: []string{".profile."},
expectedProfile: ".profile",
expectedArgs: []string{},
},
{
sourceArgs: []string{"pro.file."},
expectedProfile: "pro.file",
expectedArgs: []string{},
},
{
sourceArgs: []string{".profile.command"},
expectedProfile: ".profile",
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"pro.file.command"},
expectedProfile: "pro.file",
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"-v", "pro.file1.backup"},
expectedProfile: "pro.file1",
expectedArgs: []string{"backup"},
expectedVerbose: true,
},
{
sourceArgs: []string{"profile1.check", "--", "-v"},
expectedProfile: "profile1",
expectedArgs: []string{"check", "--", "-v"},
expectedVerbose: false,
},
{
sourceArgs: []string{"-n", constants.DefaultProfileName, "-v", "some.other.command"},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{"some.other.command"},
expectedVerbose: true,
},
{
sourceArgs: []string{"-n", "profile2", "-v", "some.command"},
expectedProfile: "profile2",
expectedArgs: []string{"some.command"},
expectedVerbose: true,
},
{
sourceArgs: []string{"@"},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{},
},
{
sourceArgs: []string{"command@"},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"@profile"},
expectedProfile: "profile",
expectedArgs: []string{},
},
{
sourceArgs: []string{"@profile@"},
expectedProfile: "profile@",
expectedArgs: []string{},
},
{
sourceArgs: []string{"command@profile@"},
expectedProfile: "profile@",
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"@pro@file"},
expectedProfile: "pro@file",
expectedArgs: []string{},
},
{
sourceArgs: []string{"command@pro@file"},
expectedProfile: "pro@file",
expectedArgs: []string{"command"},
},
{
sourceArgs: []string{"-v", "backup@pro@file1"},
expectedProfile: "pro@file1",
expectedArgs: []string{"backup"},
expectedVerbose: true,
},
{
sourceArgs: []string{"check@profile1", "--", "-v"},
expectedProfile: "profile1",
expectedArgs: []string{"check", "--", "-v"},
expectedVerbose: false,
},
{
sourceArgs: []string{"-n", constants.DefaultProfileName, "-v", "some@other@command"},
expectedProfile: constants.DefaultProfileName,
expectedArgs: []string{"some@other@command"},
expectedVerbose: true,
},
{
sourceArgs: []string{"-n", "profile2", "-v", "some@command"},
expectedProfile: "profile2",
expectedArgs: []string{"some@command"},
expectedVerbose: true,
},
}
for _, testCase := range testCases {
t.Run(strings.Join(testCase.sourceArgs, " "), func(t *testing.T) {
t.Parallel()
_, flags, err := loadFlags(testCase.sourceArgs)
require.NoError(t, err)
assert.Equal(t, flags.name, testCase.expectedProfile)
assert.Equal(t, flags.resticArgs, testCase.expectedArgs)
assert.Equal(t, flags.verbose, testCase.expectedVerbose)
})
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/creativeprojects/resticprofile

go 1.21
go 1.22

require (
github.com/Masterminds/semver/v3 v3.2.1
Expand Down
2 changes: 1 addition & 1 deletion monitor/mocks/OutputAnalysis.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion schedule/mocks/Handler.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6b00c2c

Please sign in to comment.