Skip to content

Commit d518f3b

Browse files
authored
[filesystem] Add a way to determine all parents of a path (#503)
<!-- Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved. SPDX-License-Identifier: Apache-2.0 --> ### Description try to give the same functionality as [pathlib](https://github.com/python/cpython/blob/3.12/Lib/pathlib.py#L263) ### Test Coverage <!-- Please put an `x` in the correct box e.g. `[x]` to indicate the testing coverage of this change. --> - [x] This change is covered by existing or additional automated tests. - [ ] Manual testing has been performed (and evidence provided) as automated testing was not feasible. - [ ] Additional tests are not required for this change (e.g. documentation update).
1 parent 2f440e0 commit d518f3b

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

changes/20240905230606.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:sparkles: [filesystem] Add a way to determine all parents of a path similar to python's [pathlib](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.parents)

utils/filesystem/filepath.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,39 @@ import (
1313
"github.com/ARM-software/golang-utils/utils/reflection"
1414
)
1515

16-
// FilepathStem returns the final path component, without its suffix.
16+
// FilepathStem returns the final path component, without its suffix. It's similar to `stem` in python's [pathlib](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.stem)
1717
func FilepathStem(fp string) string {
1818
return strings.TrimSuffix(filepath.Base(fp), filepath.Ext(fp))
1919
}
2020

21+
// FilepathParents returns a list of to the logical ancestors of the path and it's similar to `parents` in python's [pathlib](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.parents)
22+
func FilepathParents(fp string) []string {
23+
return FilePathParentsOnFilesystem(GetGlobalFileSystem(), fp)
24+
}
25+
26+
// FilePathParentsOnFilesystem is similar to FilepathParents but with the ability to be applied to a particular filesystem.
27+
func FilePathParentsOnFilesystem(fs FS, fp string) (parents []string) {
28+
cleanFp := filepath.Clean(fp)
29+
elements := strings.Split(cleanFp, string(fs.PathSeparator()))
30+
if len(elements) <= 1 {
31+
return
32+
}
33+
path := elements[0]
34+
if path == "" {
35+
elements = elements[1:]
36+
if len(elements) <= 1 {
37+
return
38+
}
39+
path = elements[0]
40+
}
41+
parents = append(parents, path)
42+
for i := 1; i < len(elements)-1; i++ {
43+
path = strings.Join([]string{path, elements[i]}, string(fs.PathSeparator()))
44+
parents = append(parents, path)
45+
}
46+
return
47+
}
48+
2149
// FileTreeDepth returns the depth of a file in a tree starting from root
2250
func FileTreeDepth(fs FS, root, filePath string) (depth int64, err error) {
2351
if reflection.IsEmpty(filePath) {

utils/filesystem/filepath_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/ARM-software/golang-utils/utils/commonerrors"
1414
"github.com/ARM-software/golang-utils/utils/commonerrors/errortest"
15+
"github.com/ARM-software/golang-utils/utils/platform"
1516
)
1617

1718
func TestFilepathStem(t *testing.T) {
@@ -29,6 +30,61 @@ func TestFilepathStem(t *testing.T) {
2930
})
3031
}
3132

33+
func TestFilepathParents(t *testing.T) {
34+
type PathTest struct {
35+
path string
36+
expectedParents []string
37+
}
38+
tests := []PathTest{
39+
{},
40+
{
41+
path: " ",
42+
expectedParents: nil,
43+
},
44+
{
45+
path: "/",
46+
expectedParents: nil,
47+
},
48+
{
49+
path: ".",
50+
expectedParents: nil,
51+
},
52+
{
53+
path: "./",
54+
expectedParents: nil,
55+
},
56+
{
57+
path: "./blah",
58+
expectedParents: nil,
59+
},
60+
{
61+
path: filepath.Join("a", "great", "fake", "path", "blah"),
62+
expectedParents: []string{"a", filepath.Join("a", "great"), filepath.Join("a", "great", "fake"), filepath.Join("a", "great", "fake", "path")},
63+
},
64+
{
65+
path: "/foo/bar/setup.py",
66+
expectedParents: []string{`foo`, filepath.Join(`foo`, `bar`)},
67+
},
68+
}
69+
70+
if platform.IsWindows() {
71+
tests = append(tests, PathTest{
72+
path: "C:/foo/bar/setup.py",
73+
expectedParents: []string{"C:", filepath.Join(`C:`, `\foo`), filepath.Join(`C:`, `\foo`, `bar`)},
74+
})
75+
} else {
76+
tests = append(tests, PathTest{
77+
path: "C:/foo/bar/setup.py",
78+
expectedParents: []string{"C:", filepath.Join(`C:`, `foo`), filepath.Join(`C:`, `foo`, `bar`)},
79+
})
80+
}
81+
for _, tt := range tests {
82+
t.Run(tt.path, func(t *testing.T) {
83+
assert.ElementsMatch(t, tt.expectedParents, FilepathParents(tt.path))
84+
})
85+
}
86+
}
87+
3288
func TestFileTreeDepth(t *testing.T) {
3389
random := fmt.Sprintf("%v %v %v", faker.Name(), faker.Name(), faker.Name())
3490
complexRandom := fmt.Sprintf("%v&#~@£*-_()^+!%v %v", faker.Name(), faker.Name(), faker.Name())

0 commit comments

Comments
 (0)