Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Commit 6b75d6b

Browse files
authored
Merge pull request #704 from mikijov/issue675-old
Fixes #675. Changes to HasFilepathPrefix to handle Windows better.
2 parents c36bccf + 5a7783f commit 6b75d6b

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed

internal/fs/fs.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,28 @@ import (
2929
// will return true. The implementation is *not* OS-specific, so a FAT32
3030
// filesystem mounted on Linux will be handled correctly.
3131
func HasFilepathPrefix(path, prefix string) bool {
32-
if filepath.VolumeName(path) != filepath.VolumeName(prefix) {
32+
// this function is more convoluted then ideal due to need for special
33+
// handling of volume name/drive letter on Windows. vnPath and vnPrefix
34+
// are first compared, and then used to initialize initial values of p and
35+
// d which will be appended to for incremental checks using
36+
// isCaseSensitiveFilesystem and then equality.
37+
38+
// no need to check isCaseSensitiveFilesystem because VolumeName return
39+
// empty string on all non-Windows machines
40+
vnPath := strings.ToLower(filepath.VolumeName(path))
41+
vnPrefix := strings.ToLower(filepath.VolumeName(prefix))
42+
if vnPath != vnPrefix {
3343
return false
3444
}
3545

46+
// because filepath.Join("c:","dir") returns "c:dir", we have to manually add path separator to drive letters
47+
if strings.HasSuffix(vnPath, ":") {
48+
vnPath += string(os.PathSeparator)
49+
}
50+
if strings.HasSuffix(vnPrefix, ":") {
51+
vnPrefix += string(os.PathSeparator)
52+
}
53+
3654
var dn string
3755

3856
if isDir, err := IsDir(path); err != nil {
@@ -46,14 +64,17 @@ func HasFilepathPrefix(path, prefix string) bool {
4664
dn = strings.TrimSuffix(dn, string(os.PathSeparator))
4765
prefix = strings.TrimSuffix(prefix, string(os.PathSeparator))
4866

67+
// [1:] in the lines below eliminates empty string on *nix and volume name on Windows
4968
dirs := strings.Split(dn, string(os.PathSeparator))[1:]
5069
prefixes := strings.Split(prefix, string(os.PathSeparator))[1:]
5170

5271
if len(prefixes) > len(dirs) {
5372
return false
5473
}
5574

56-
var d, p string
75+
// d,p are initialized with "" on *nix and volume name on Windows
76+
d := vnPath
77+
p := vnPrefix
5778

5879
for i := range prefixes {
5980
// need to test each component of the path for

internal/fs/fs_test.go

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,61 @@ import (
99
"os"
1010
"path/filepath"
1111
"runtime"
12+
"strings"
1213
"testing"
1314

1415
"github.com/golang/dep/internal/test"
1516
)
1617

18+
// This function tests HadFilepathPrefix. It should test it on both case
19+
// sensitive and insensitive situations. However, the only reliable way to test
20+
// case-insensitive behaviour is if using case-insensitive filesystem. This
21+
// cannot be guaranteed in an automated test. Therefore, the behaviour of the
22+
// tests is not to test case sensitivity on *nix and to assume that Windows is
23+
// case-insensitive. Please see link below for some background.
24+
//
25+
// https://superuser.com/questions/266110/how-do-you-make-windows-7-fully-case-sensitive-with-respect-to-the-filesystem
26+
//
27+
// NOTE: NTFS can be made case-sensitive. However many Windows programs,
28+
// including Windows Explorer do not handle gracefully multiple files that
29+
// differ only in capitalization. It is possible that this can cause these tests
30+
// to fail on some setups.
1731
func TestHasFilepathPrefix(t *testing.T) {
1832
dir, err := ioutil.TempDir("", "dep")
1933
if err != nil {
2034
t.Fatal(err)
2135
}
2236
defer os.RemoveAll(dir)
2337

38+
// dir2 is the same as dir but with different capitalization on Windows to
39+
// test case insensitivity
40+
var dir2 string
41+
if runtime.GOOS == "windows" {
42+
dir = strings.ToLower(dir)
43+
dir2 = strings.ToUpper(dir)
44+
} else {
45+
dir2 = dir
46+
}
47+
2448
cases := []struct {
2549
path string
2650
prefix string
2751
want bool
2852
}{
29-
{filepath.Join(dir, "a", "b"), filepath.Join(dir), true},
30-
{filepath.Join(dir, "a", "b"), filepath.Join(dir, "a"), true},
31-
{filepath.Join(dir, "a", "b"), filepath.Join(dir, "a", "b"), true},
32-
{filepath.Join(dir, "a", "b"), filepath.Join(dir, "c"), false},
33-
{filepath.Join(dir, "a", "b"), filepath.Join(dir, "a", "d", "b"), false},
34-
{filepath.Join(dir, "a", "b"), filepath.Join(dir, "a", "b2"), false},
35-
{filepath.Join(dir), filepath.Join(dir, "a", "b"), false},
36-
{filepath.Join(dir, "ab"), filepath.Join(dir, "a", "b"), false},
37-
{filepath.Join(dir, "ab"), filepath.Join(dir, "a"), false},
38-
{filepath.Join(dir, "123"), filepath.Join(dir, "123"), true},
39-
{filepath.Join(dir, "123"), filepath.Join(dir, "1"), false},
40-
{filepath.Join(dir, "⌘"), filepath.Join(dir, "⌘"), true},
41-
{filepath.Join(dir, "a"), filepath.Join(dir, "⌘"), false},
42-
{filepath.Join(dir, "⌘"), filepath.Join(dir, "a"), false},
53+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2), true},
54+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2, "a"), true},
55+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2, "a", "b"), true},
56+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2, "c"), false},
57+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2, "a", "d", "b"), false},
58+
{filepath.Join(dir, "a", "b"), filepath.Join(dir2, "a", "b2"), false},
59+
{filepath.Join(dir), filepath.Join(dir2, "a", "b"), false},
60+
{filepath.Join(dir, "ab"), filepath.Join(dir2, "a", "b"), false},
61+
{filepath.Join(dir, "ab"), filepath.Join(dir2, "a"), false},
62+
{filepath.Join(dir, "123"), filepath.Join(dir2, "123"), true},
63+
{filepath.Join(dir, "123"), filepath.Join(dir2, "1"), false},
64+
{filepath.Join(dir, "⌘"), filepath.Join(dir2, "⌘"), true},
65+
{filepath.Join(dir, "a"), filepath.Join(dir2, "⌘"), false},
66+
{filepath.Join(dir, "⌘"), filepath.Join(dir2, "a"), false},
4367
}
4468

4569
for _, c := range cases {
@@ -57,13 +81,36 @@ func TestHasFilepathPrefix(t *testing.T) {
5781
}
5882
}
5983

84+
// This function tests HadFilepathPrefix. It should test it on both case
85+
// sensitive and insensitive situations. However, the only reliable way to test
86+
// case-insensitive behaviour is if using case-insensitive filesystem. This
87+
// cannot be guaranteed in an automated test. Therefore, the behaviour of the
88+
// tests is not to test case sensitivity on *nix and to assume that Windows is
89+
// case-insensitive. Please see link below for some background.
90+
//
91+
// https://superuser.com/questions/266110/how-do-you-make-windows-7-fully-case-sensitive-with-respect-to-the-filesystem
92+
//
93+
// NOTE: NTFS can be made case-sensitive. However many Windows programs,
94+
// including Windows Explorer do not handle gracefully multiple files that
95+
// differ only in capitalization. It is possible that this can cause these tests
96+
// to fail on some setups.
6097
func TestHasFilepathPrefix_Files(t *testing.T) {
6198
dir, err := ioutil.TempDir("", "dep")
6299
if err != nil {
63100
t.Fatal(err)
64101
}
65102
defer os.RemoveAll(dir)
66103

104+
// dir2 is the same as dir but with different capitalization on Windows to
105+
// test case insensitivity
106+
var dir2 string
107+
if runtime.GOOS == "windows" {
108+
dir = strings.ToLower(dir)
109+
dir2 = strings.ToUpper(dir)
110+
} else {
111+
dir2 = dir
112+
}
113+
67114
existingFile := filepath.Join(dir, "exists")
68115
if _, err := os.Create(existingFile); err != nil {
69116
t.Fatal(err)
@@ -76,8 +123,8 @@ func TestHasFilepathPrefix_Files(t *testing.T) {
76123
prefix string
77124
want bool
78125
}{
79-
{existingFile, filepath.Join(dir), false},
80-
{nonExistingFile, filepath.Join(dir), true},
126+
{existingFile, filepath.Join(dir2), false},
127+
{nonExistingFile, filepath.Join(dir2), true},
81128
}
82129

83130
for _, c := range cases {

0 commit comments

Comments
 (0)