master
go 90 lines 1.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package multipath
4
5 import (
6 "errors"
7 "fmt"
8 "os"
9 "path/filepath"
10 "slices"
11 "strings"
12
13 "github.com/mitchellh/go-homedir"
14 )
15
16 type ErrNotFound struct{ msg string }
17
18 func (e ErrNotFound) Error() string { return e.msg }
19
20 // IsNotFound returns a boolean indicating whether the error is ErrNotFound or not.
21 func IsNotFound(err error) bool {
22 var errNotFound ErrNotFound
23 return errors.As(err, &errNotFound)
24 }
25
26 // MultiPath multi-paths
27 type MultiPath []string
28
29 // New multi-paths
30 func New(paths ...string) MultiPath {
31 set := map[string]bool{}
32 mPath := make(MultiPath, 0)
33
34 for _, dir := range paths {
35 if dir == "" {
36 continue
37 }
38 if d, err := homedir.Expand(dir); err == nil {
39 dir = d
40 }
41 if !set[dir] {
42 mPath = append(mPath, dir)
43 set[dir] = true
44 }
45 }
46
47 return mPath
48 }
49
50 // Find finds a file in given paths
51 func (p MultiPath) Find(filename string) (string, error) {
52 for _, dir := range p {
53 file := filepath.Join(dir, filename)
54 if _, err := os.Stat(file); !os.IsNotExist(err) {
55 return file, nil
56 }
57 }
58 return "", ErrNotFound{msg: fmt.Sprintf("can't find '%s' in %v", filename, p)}
59 }
60
61 func (p MultiPath) FindFiles(suffixes ...string) ([]string, error) {
62 set := make(map[string]bool)
63 var files []string
64
65 for _, dir := range p {
66 entries, err := os.ReadDir(dir)
67 if err != nil {
68 continue
69 }
70
71 for _, e := range entries {
72 if !e.Type().IsRegular() {
73 continue
74 }
75
76 ext := filepath.Ext(e.Name())
77 name := strings.TrimSuffix(e.Name(), ext)
78
79 if (len(suffixes) != 0 && !slices.Contains(suffixes, ext)) || set[name] {
80 continue
81 }
82
83 set[name] = true
84 file := filepath.Join(dir, e.Name())
85 files = append(files, file)
86 }
87 }
88
89 return files, nil
90 }