Skip to content

Commit 6da0317

Browse files
also search configuration from ~/.config/resticprofile on macOS (#370)
* also search configuration from ~/.config/resticprofile on macOS
1 parent 0598026 commit 6da0317

File tree

5 files changed

+96
-17
lines changed

5 files changed

+96
-17
lines changed

.goreleaser.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ brews:
197197
commit_author:
198198
name: goreleaser
199199
email: fred@creativeprojects.tech
200-
folder: Formula
200+
directory: Formula
201201
homepage: https://github.com/creativeprojects/{{ .ProjectName }}
202202
description: Configuration profiles for restic backup
203203
license: "GPL-3.0-only"

codecov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ coverage:
2525
default:
2626
target: auto
2727
threshold: "2%"
28-
patch:
28+
patch:
2929
default:
3030
target: "70%"
3131
threshold: "2%"

filesearch/filesearch.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
)
1818

1919
var (
20-
XDGAppName = "resticprofile"
20+
AppName = "resticprofile"
2121

2222
// configurationExtensions list the possible extensions for the config file
2323
configurationExtensions = []string{
@@ -40,6 +40,10 @@ var (
4040
"/opt/local/etc/resticprofile/",
4141
}
4242

43+
addConfigurationLocationsDarwin = []string{
44+
".config/" + AppName + "/",
45+
}
46+
4347
defaultConfigurationLocationsWindows = []string{
4448
"c:\\restic\\",
4549
"c:\\resticprofile\\",
@@ -65,7 +69,7 @@ var (
6569
}
6670
)
6771

68-
var fs afero.Fs
72+
var fs afero.Fs // we could probably change the implementation to use fs.FS instead
6973

7074
func init() {
7175
fs = afero.NewOsFs()
@@ -187,6 +191,8 @@ func FindResticBinary(configLocation string) (string, error) {
187191
return filename, nil
188192
}
189193
}
194+
clog.Tracef("could not find restic binary %q in any of these locations: %s", binaryFile, strings.Join(paths, ", "))
195+
190196
// Last resort, search from the OS PATH
191197
filename, err := exec.LookPath(binaryFile)
192198
if err != nil {
@@ -211,9 +217,11 @@ func ShellExpand(filename string) (string, error) {
211217
}
212218

213219
func getSearchConfigurationLocations() []string {
214-
locations := []string{filepath.Join(xdg.ConfigHome, XDGAppName)}
220+
home, _ := os.UserHomeDir()
221+
222+
locations := []string{filepath.Join(xdg.ConfigHome, AppName)}
215223
for _, configDir := range xdg.ConfigDirs {
216-
locations = append(locations, filepath.Join(configDir, XDGAppName))
224+
locations = append(locations, filepath.Join(configDir, AppName))
217225
}
218226

219227
if platform.IsWindows() {
@@ -222,7 +230,11 @@ func getSearchConfigurationLocations() []string {
222230
locations = append(locations, defaultConfigurationLocationsUnix...)
223231
}
224232

225-
if home, err := os.UserHomeDir(); err == nil {
233+
if platform.IsDarwin() {
234+
locations = append(locations, addRootToRelativePaths(home, addConfigurationLocationsDarwin)...)
235+
}
236+
237+
if home != "" {
226238
locations = append(locations, home)
227239
}
228240

@@ -244,7 +256,7 @@ func getSearchBinaryLocations() []string {
244256
paths = defaultBinaryLocationsUnix
245257
}
246258
if home, err := os.UserHomeDir(); err == nil {
247-
paths = append(paths, filepath.Join(home, ".local/bin/"), filepath.Join(home, "bin/"))
259+
paths = append(paths, addRootToRelativePaths(home, []string{".local/bin/", "bin/"})...)
248260
}
249261
return paths
250262
}
@@ -260,3 +272,22 @@ func fileExists(filename string) bool {
260272
_, err := fs.Stat(filename)
261273
return err == nil || errors.Is(err, iofs.ErrExist)
262274
}
275+
276+
func addRootToRelativePaths(home string, paths []string) []string {
277+
if platform.IsWindows() {
278+
return paths
279+
}
280+
if home == "" {
281+
return paths
282+
}
283+
rootedPaths := make([]string, len(paths))
284+
for i, path := range paths {
285+
if filepath.IsAbs(path) {
286+
rootedPaths[i] = path
287+
continue
288+
}
289+
path = strings.TrimPrefix(path, "~/")
290+
rootedPaths[i] = filepath.Join(home, path)
291+
}
292+
return rootedPaths
293+
}

filesearch/filesearch_test.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ func TestMain(t *testing.M) {
4040
// ConfigDirs: [C:\ProgramData C:\Users\runneradmin\AppData\Roaming]
4141
// ApplicationDirs: [C:\Users\runneradmin\AppData\Roaming\Microsoft\Windows\Start Menu\Programs C:\ProgramData\Microsoft\Windows\Start Menu\Programs]
4242
func TestDefaultConfigDirs(t *testing.T) {
43+
t.Parallel()
44+
4345
t.Log("ConfigHome:", xdg.ConfigHome)
4446
t.Log("ConfigDirs:", xdg.ConfigDirs)
4547
t.Log("ApplicationDirs:", xdg.ApplicationDirs)
@@ -192,6 +194,8 @@ func testLocations(t *testing.T) []testLocation {
192194
}
193195

194196
func TestFindConfigurationFile(t *testing.T) {
197+
t.Parallel()
198+
195199
// Work from a temporary directory
196200
err := os.Chdir(os.TempDir())
197201
require.NoError(t, err)
@@ -206,7 +210,7 @@ func TestFindConfigurationFile(t *testing.T) {
206210
var err error
207211
// Install empty config file
208212
if location.realPath != "" {
209-
err = fs.MkdirAll(location.realPath, 0700)
213+
err = fs.MkdirAll(location.realPath, 0o700)
210214
require.NoError(t, err)
211215
}
212216
file, err := fs.Create(filepath.Join(location.realPath, location.realFile))
@@ -230,12 +234,16 @@ func TestFindConfigurationFile(t *testing.T) {
230234
}
231235

232236
func TestCannotFindConfigurationFile(t *testing.T) {
237+
t.Parallel()
238+
233239
found, err := FindConfigurationFile("some_config_file")
234240
assert.Empty(t, found)
235241
assert.Error(t, err)
236242
}
237243

238244
func TestFindResticBinary(t *testing.T) {
245+
t.Parallel()
246+
239247
binary, err := FindResticBinary("some_other_name")
240248
if binary != "" {
241249
assert.True(t, strings.HasSuffix(binary, getResticBinaryName()))
@@ -246,14 +254,16 @@ func TestFindResticBinary(t *testing.T) {
246254
}
247255

248256
func TestFindResticBinaryWithTilde(t *testing.T) {
257+
t.Parallel()
258+
249259
if runtime.GOOS == "windows" {
250260
t.Skip("not supported on Windows")
251261
return
252262
}
253263
home, err := os.UserHomeDir()
254264
require.NoError(t, err)
255265

256-
tempFile, err := afero.TempFile(fs, home, "TestFindResticBinaryWithTilde")
266+
tempFile, err := afero.TempFile(fs, home, t.Name())
257267
require.NoError(t, err)
258268
tempFile.Close()
259269
defer func() {
@@ -267,6 +277,8 @@ func TestFindResticBinaryWithTilde(t *testing.T) {
267277
}
268278

269279
func TestShellExpand(t *testing.T) {
280+
t.Parallel()
281+
270282
if runtime.GOOS == "windows" {
271283
t.Skip("not supported on Windows")
272284
return
@@ -290,6 +302,8 @@ func TestShellExpand(t *testing.T) {
290302

291303
for _, testItem := range testData {
292304
t.Run(testItem.source, func(t *testing.T) {
305+
t.Parallel()
306+
293307
result, err := ShellExpand(testItem.source)
294308
require.NoError(t, err)
295309
assert.Equal(t, testItem.expected, result)
@@ -298,6 +312,8 @@ func TestShellExpand(t *testing.T) {
298312
}
299313

300314
func TestFindConfigurationIncludes(t *testing.T) {
315+
t.Parallel()
316+
301317
testID := fmt.Sprintf("%d", uint32(time.Now().UnixNano()))
302318
tempDir := os.TempDir()
303319
files := []string{
@@ -309,7 +325,9 @@ func TestFindConfigurationIncludes(t *testing.T) {
309325

310326
for _, file := range files {
311327
require.NoError(t, afero.WriteFile(fs, file, []byte{}, iofs.ModePerm))
312-
defer fs.Remove(file) // defer stack is ok for cleanup
328+
t.Cleanup(func() {
329+
_ = fs.Remove(file)
330+
})
313331
}
314332

315333
testData := []struct {
@@ -335,6 +353,8 @@ func TestFindConfigurationIncludes(t *testing.T) {
335353

336354
for _, test := range testData {
337355
t.Run(strings.Join(test.includes, ","), func(t *testing.T) {
356+
t.Parallel()
357+
338358
result, err := FindConfigurationIncludes(files[0], test.includes)
339359
if test.expected == nil {
340360
assert.Nil(t, result)
@@ -350,3 +370,36 @@ func TestFindConfigurationIncludes(t *testing.T) {
350370
})
351371
}
352372
}
373+
374+
func TestAddRootToRelativePaths(t *testing.T) {
375+
t.Parallel()
376+
377+
if platform.IsWindows() {
378+
t.Skip("not supported on Windows")
379+
}
380+
381+
testCases := []struct {
382+
root string
383+
inputPath []string
384+
outputPath []string
385+
}{
386+
{
387+
root: "",
388+
inputPath: []string{"", "dir", "~/user", "/root"},
389+
outputPath: []string{"", "dir", "~/user", "/root"},
390+
},
391+
{
392+
root: "/home",
393+
inputPath: []string{"", "dir", "~/user", "/root"},
394+
outputPath: []string{"/home", "/home/dir", "/home/user", "/root"},
395+
},
396+
}
397+
for _, testCase := range testCases {
398+
t.Run(testCase.root, func(t *testing.T) {
399+
t.Parallel()
400+
401+
result := addRootToRelativePaths(testCase.root, testCase.inputPath)
402+
assert.Equal(t, testCase.outputPath, result)
403+
})
404+
}
405+
}

schedule/scheduler_config.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77

88
"github.com/creativeprojects/resticprofile/config"
99
"github.com/creativeprojects/resticprofile/constants"
10-
"github.com/spf13/afero"
1110
)
1211

1312
type SchedulerConfig interface {
@@ -35,16 +34,13 @@ type SchedulerWindows struct{}
3534
func (s SchedulerWindows) Type() string { return constants.SchedulerWindows }
3635
func (s SchedulerWindows) Convert(_ string) SchedulerConfig { return s }
3736

38-
type SchedulerLaunchd struct {
39-
Fs afero.Fs
40-
}
37+
type SchedulerLaunchd struct{}
4138

4239
func (s SchedulerLaunchd) Type() string { return constants.SchedulerLaunchd }
4340
func (s SchedulerLaunchd) Convert(_ string) SchedulerConfig { return s }
4441

4542
// SchedulerCrond configures crond compatible schedulers, either needs CrontabBinary or CrontabFile
4643
type SchedulerCrond struct {
47-
Fs afero.Fs
4844
CrontabFile string
4945
CrontabBinary string
5046
Username string
@@ -54,7 +50,6 @@ func (s SchedulerCrond) Type() string { return constants.Sch
5450
func (s SchedulerCrond) Convert(_ string) SchedulerConfig { return s }
5551

5652
type SchedulerSystemd struct {
57-
Fs afero.Fs
5853
UnitTemplate string
5954
TimerTemplate string
6055
}

0 commit comments

Comments
 (0)