// HasSymlink reports whether the current system can use os.Symlink.
func HasSymlink() bool {
- return hasSymlink()
+ ok, _ := hasSymlink()
+ return ok
}
// MustHaveSymlink reports whether the current system can use os.Symlink.
// If not, MustHaveSymlink calls t.Skip with an explanation.
func MustHaveSymlink(t *testing.T) {
- if !HasSymlink() {
- t.Skipf("skipping test: cannot make symlinks on %s/%s", runtime.GOOS, runtime.GOARCH)
+ ok, reason := hasSymlink()
+ if !ok {
+ t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
}
}
"runtime"
)
-func hasSymlink() bool {
+func hasSymlink() (ok bool, reason string) {
switch runtime.GOOS {
case "android", "nacl", "plan9":
- return false
+ return false, ""
}
- return true
+ return true, ""
}
)
var symlinkOnce sync.Once
-var winHasSymlink = true
+var winSymlinkErr error
func initWinHasSymlink() {
tmpdir, err := ioutil.TempDir("", "symtest")
err = err.(*os.LinkError).Err
switch err {
case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
- winHasSymlink = false
+ winSymlinkErr = err
}
}
os.Remove("target")
}
-func hasSymlink() bool {
+func hasSymlink() (ok bool, reason string) {
symlinkOnce.Do(initWinHasSymlink)
- return winHasSymlink
+ switch winSymlinkErr {
+ case nil:
+ return true, ""
+ case syscall.EWINDOWS:
+ return false, ": symlinks are not supported on your version of Windows"
+ case syscall.ERROR_PRIVILEGE_NOT_HELD:
+ return false, ": you don't have enough privileges to create symlinks"
+ }
+
+ return false, ""
}