os: add UserCacheDir

Adds a function that returns an OS-dependent location
for user-specific cache data.

Fixes golang/go#22536

Change-Id: Ifff015452494571ad357fa2d945d66a5992c751d
Reviewed-on: https://go-review.googlesource.com/78835
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/os/file.go b/src/os/file.go
index c667421..aecf9f5 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -41,6 +41,7 @@
 	"internal/poll"
 	"internal/testlog"
 	"io"
+	"runtime"
 	"syscall"
 	"time"
 )
@@ -315,6 +316,54 @@
 	return tempDir()
 }
 
+// UserCacheDir returns the default root directory to use for user-specific
+// cached data. Users should create their own application-specific subdirectory
+// within this one and use that.
+//
+// On Unix systems, it returns $XDG_CACHE_HOME as specified by
+// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html if
+// non-empty, else $HOME/.cache.
+// On Darwin, it returns $HOME/Library/Caches.
+// On Windows, it returns %LocalAppData%.
+// On Plan 9, it returns $home/lib/cache.
+//
+// If the location cannot be determined (for example, $HOME is not defined),
+// then it will return an empty string.
+func UserCacheDir() string {
+	var dir string
+
+	switch runtime.GOOS {
+	case "windows":
+		dir = Getenv("LocalAppData")
+
+	case "darwin":
+		dir = Getenv("HOME")
+		if dir == "" {
+			return ""
+		}
+		dir += "/Library/Caches"
+
+	case "plan9":
+		dir = Getenv("home")
+		if dir == "" {
+			return ""
+		}
+		dir += "/lib/cache"
+
+	default: // Unix
+		dir = Getenv("XDG_CACHE_HOME")
+		if dir == "" {
+			dir = Getenv("HOME")
+			if dir == "" {
+				return ""
+			}
+			dir += "/.cache"
+		}
+	}
+
+	return dir
+}
+
 // Chmod changes the mode of the named file to mode.
 // If the file is a symbolic link, it changes the mode of the link's target.
 // If there is an error, it will be of type *PathError.