From c945ef129a40366013d7c34f04c8b2fddb71db26 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 2 Apr 2020 17:55:25 -0700 Subject: [PATCH] vendor: go get github.com/apparentlymart/go-userdirs This library implements the user-specific directory layout specifications for various platforms (XDG on Unix, "Known Folders" on Windows, etc). We'll use this in a subsequent commit to add additional system-specific search directories for provider plugins, and perhaps later on also CLI configuration directories. --- go.mod | 1 + go.sum | 5 +- .../apparentlymart/go-userdirs/LICENSE | 21 +++ .../go-userdirs/internal/unix/homedir.go | 97 ++++++++++ .../go-userdirs/macosbase/doc.go | 8 + .../go-userdirs/macosbase/home.go | 9 + .../go-userdirs/macosbase/macosbase.go | 26 +++ .../go-userdirs/userdirs/app.go | 32 ++++ .../go-userdirs/userdirs/app_darwin.go | 29 +++ .../go-userdirs/userdirs/app_stub.go | 20 ++ .../go-userdirs/userdirs/app_unix.go | 42 +++++ .../go-userdirs/userdirs/app_windows.go | 41 ++++ .../go-userdirs/userdirs/dirs.go | 178 ++++++++++++++++++ .../go-userdirs/userdirs/doc.go | 39 ++++ .../go-userdirs/windowsbase/doc.go | 6 + .../go-userdirs/windowsbase/impl.go | 40 ++++ .../go-userdirs/windowsbase/stub.go | 11 ++ .../go-userdirs/windowsbase/windowsbase.go | 35 ++++ .../apparentlymart/go-userdirs/xdgbase/doc.go | 8 + .../go-userdirs/xdgbase/home.go | 9 + .../apparentlymart/go-userdirs/xdgbase/xdg.go | 105 +++++++++++ vendor/modules.txt | 7 + 22 files changed, 767 insertions(+), 2 deletions(-) create mode 100644 vendor/github.com/apparentlymart/go-userdirs/LICENSE create mode 100644 vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/macosbase/doc.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/macosbase/home.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/app.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/app_stub.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/app_unix.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/dirs.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/userdirs/doc.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/windowsbase/doc.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/windowsbase/impl.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/windowsbase/stub.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/xdgbase/doc.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/xdgbase/home.go create mode 100644 vendor/github.com/apparentlymart/go-userdirs/xdgbase/xdg.go diff --git a/go.mod b/go.mod index 33d592cc1..b1e607062 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible github.com/apparentlymart/go-cidr v1.0.1 github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 + github.com/apparentlymart/go-userdirs v0.0.0-20190512014041-4a23807e62b9 github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect diff --git a/go.sum b/go.sum index a7143c087..79f052c8b 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,8 @@ github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFU github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-userdirs v0.0.0-20190512014041-4a23807e62b9 h1:GRMI604e1ILyP9b5DTNAZFHx+Vu693kxb9ZBrIA2JQg= +github.com/apparentlymart/go-userdirs v0.0.0-20190512014041-4a23807e62b9/go.mod h1:7kfpUbyCdGJ9fDRCp3fopPQi5+cKNHgTE4ZuNrO71Cw= github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171 h1:19Seu/H5gq3Ugtx+CGenwF89SDG3S1REX5i6PJj3RK4= github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171/go.mod h1:JXY95WvQrPJQtudvNARshgWajS7jNNlM90altXIPNyI= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= @@ -431,8 +433,6 @@ github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.3.0 h1:ig1G6+rJHX6jZDRjw4LUD3J8q7SBAagcmbM7bQ8ijmI= -github.com/zclconf/go-cty v1.3.0/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k= github.com/zclconf/go-cty v1.3.1 h1:QIOZl+CKKdkv4l2w3lG23nNzXgLoxsWLSEdg1MlX4p0= github.com/zclconf/go-cty v1.3.1/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k= github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= @@ -506,6 +506,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= diff --git a/vendor/github.com/apparentlymart/go-userdirs/LICENSE b/vendor/github.com/apparentlymart/go-userdirs/LICENSE new file mode 100644 index 000000000..70a64efb7 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Martin Atkins + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go b/vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go new file mode 100644 index 000000000..01920a4f4 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go @@ -0,0 +1,97 @@ +package unix + +import ( + "bytes" + "os" + "os/exec" + "os/user" + "path/filepath" + "runtime" + "strconv" + "strings" +) + +// Home returns the home directory for the current process, with the following +// preference order: +// +// - The value of the HOME environment variable, if it is set and contains +// an absolute path. +// - The home directory indicated in the return value of the "Current" +// function in the os/user standard library package, which has +// platform-specific behavior, if it contains an absolute path. +// - If neither of the above yields an absolute path, the string "/". +// +// In practice, POSIX requires the HOME environment variable to be set, so on +// any reasonable system it is that which will be selected. The other +// permutations are fallback behavior for less reasonable systems. +// +// XDG does not permit applications to write directly into the home directory. +// Instead, the paths returned by other functions in this package are +// potentially derived from the home path, if their explicit environment +// variables are not set. +func Home() string { + if homeDir := os.Getenv("HOME"); homeDir != "" { + if filepath.IsAbs(homeDir) { + return homeDir + } + } + + user, err := user.Current() + if err == nil { + if homeDir := user.HomeDir; homeDir != "" { + if filepath.IsAbs(homeDir) { + return homeDir + } + } + } + + if maybe := desperateFallback(); maybe != "" { + return maybe + } + + // Fallback behavior mimics a common choice in other software. + return "/" +} + +func desperateFallback() string { + // This function implements some rather-nasty fallback behavior via some + // platform-specific shell commands. This should always be a last resort, + // but particulary when we are working not in CGo mode this path can help + // us on platforms where the pure Go user.Current() stub's behavior isn't + // appropriate for some more unusual Unix platforms, like Mac OS X. + // + // The existence and behavior of these commands is not an OS API contract, + // so we run them in a best-effort way and just move on and try something + // else if they fail. + + switch runtime.GOOS { + case "darwin": + var stdout bytes.Buffer + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + if result := strings.TrimSpace(stdout.String()); filepath.IsAbs(result) { + return result + } + } + return "" + case "linux": + var stdout bytes.Buffer + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + if result := passwdParts[5]; filepath.IsAbs(result) { + return result + } + } + } + } + return "" + default: + return "" + } +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/macosbase/doc.go b/vendor/github.com/apparentlymart/go-userdirs/macosbase/doc.go new file mode 100644 index 000000000..7176fe867 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/macosbase/doc.go @@ -0,0 +1,8 @@ +// Package macosbase contains helper functions that construct base paths +// conforming to the Mac OS user-specific file layout guidelines as +// documented in https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6 . +// +// This package only does path construction, and doesn't depend on any Mac OS +// system APIs, so in principle it can run on other platforms but the results +// it produces in that case are undefined and unlikely to be useful. +package macosbase diff --git a/vendor/github.com/apparentlymart/go-userdirs/macosbase/home.go b/vendor/github.com/apparentlymart/go-userdirs/macosbase/home.go new file mode 100644 index 000000000..f3fa3ec9d --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/macosbase/home.go @@ -0,0 +1,9 @@ +package macosbase + +import ( + "github.com/apparentlymart/go-userdirs/internal/unix" +) + +func home() string { + return unix.Home() +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go b/vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go new file mode 100644 index 000000000..9dae96285 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go @@ -0,0 +1,26 @@ +package macosbase + +import ( + "path/filepath" +) + +// ApplicationSupportDir returns the path to the current user's +// "Application Support" library directory. +func ApplicationSupportDir() string { + return filepath.Join(home(), "Library", "Application Support") +} + +// CachesDir returns the path to the current user's "Caches" library directory. +func CachesDir() string { + return filepath.Join(home(), "Library", "Caches") +} + +// FrameworksDir returns the path to the current user's "Frameworks" library directory. +func FrameworksDir() string { + return filepath.Join(home(), "Library", "Frameworks") +} + +// PreferencesDir returns the path to the current user's "Preferences" library directory. +func PreferencesDir() string { + return filepath.Join(home(), "Library", "Preferences") +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/app.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app.go new file mode 100644 index 000000000..0d4edc059 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app.go @@ -0,0 +1,32 @@ +package userdirs + +// ForApp returns a set of user-specific directories for a particular +// application. +// +// The three arguments are used in different ways depending on the current +// host operating system, because each OS has different conventions. +// +// - On Windows, the vendor and string are used to construct a two-level +// heirarchy, vendor/name, under each namespaced directory prefix. +// The bundleID is ignored. +// - On Linux and other similar Unix systems, the name is converted to +// lowercase and any spaces changed to dashes and used as a subdirectory +// name. The vendor and bundleID are ignored. +// - On Mac OS X, the bundleID is used and the name and vendor are ignored. +// +// For best results, the name and vendor arguments should contain +// space-separated words using title case, like "Image Editor" and "Contoso", +// and the bundleID should be a reverse-DNS-style string, like +// "com.example.appname". +func ForApp(name string, vendor string, bundleID string) Dirs { + // Delegate to OS-specific implementation + return forApp(name, vendor, bundleID) +} + +// SupportedOS returns true if the current operating system is supported by +// this package. If this function returns false, any call to ForApp will +// panic. +func SupportedOS() bool { + // Delegate to OS-specific implementation + return supportedOS() +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go new file mode 100644 index 000000000..2cd7aae98 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go @@ -0,0 +1,29 @@ +// +build darwin + +package userdirs + +import ( + "path/filepath" + + "github.com/apparentlymart/go-userdirs/macosbase" +) + +func supportedOS() bool { + return true +} + +func forApp(name string, vendor string, bundleID string) Dirs { + appSupportDir := filepath.Join(macosbase.ApplicationSupportDir(), bundleID) + cachesDir := filepath.Join(macosbase.CachesDir(), bundleID) + globalAppSupportDir := filepath.Join("/", "Library", "Application Support", bundleID) + + return Dirs{ + // NOTE: We don't use "Preferences" here because it is specified as + // containing propertly list files managed by an OS framework API only, + // so it would not be appropriate to read/write arbitrary config + // files in there. + ConfigDirs: []string{appSupportDir}, + DataDirs: []string{appSupportDir, globalAppSupportDir}, + CacheDir: cachesDir, + } +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_stub.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_stub.go new file mode 100644 index 000000000..3a725b18e --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_stub.go @@ -0,0 +1,20 @@ +// +build !linux,!windows,!darwin,!aix,!dragonfly,!freebsd,!netbsd,!solaris + +// The above build constraint must contain the negation of all of the build +// constraints found in the other app_*.go files, to catch any other OS +// we haven't accounted for. + +package userdirs + +import ( + "fmt" + "runtime" +) + +func supportedOS() bool { + return false +} + +func forApp(name string, vendor string, bundleID string) Dirs { + panic(fmt.Sprintf("cannot determine user directories on OS %q", runtime.GOOS)) +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_unix.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_unix.go new file mode 100644 index 000000000..3842f9440 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_unix.go @@ -0,0 +1,42 @@ +// +build linux aix dragonfly freebsd netbsd solaris + +package userdirs + +import ( + "path/filepath" + "strings" + + "github.com/apparentlymart/go-userdirs/xdgbase" +) + +func supportedOS() bool { + return true +} + +func forApp(name string, vendor string, bundleID string) Dirs { + // We use XDG conventions on Linux and other Unixes without their own special rules + + subDir := appDirName(name) + + ret := xdgDirs() + for i, dir := range ret.ConfigDirs { + ret.ConfigDirs[i] = filepath.Join(dir, subDir) + } + for i, dir := range ret.DataDirs { + ret.DataDirs[i] = filepath.Join(dir, subDir) + } + ret.CacheDir = filepath.Join(ret.CacheDir, subDir) + return ret +} + +func xdgDirs() Dirs { + return Dirs{ + ConfigDirs: xdgbase.ConfigDirs(), + DataDirs: xdgbase.DataDirs(), + CacheDir: xdgbase.CacheHome(), + } +} + +func appDirName(appName string) string { + return strings.ToLower(strings.ReplaceAll(appName, " ", "-")) +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go new file mode 100644 index 000000000..3bf9ef021 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go @@ -0,0 +1,41 @@ +// +build windows + +package userdirs + +import ( + "path/filepath" + + "github.com/apparentlymart/go-userdirs/windowsbase" +) + +func supportedOS() bool { + return true +} + +func forApp(name string, vendor string, bundleID string) Dirs { + subDir := filepath.Join(vendor, name) + localBase, err := windowsbase.LocalAppDataDir() + if err != nil { + localBase = "" + } + roamingBase, err := windowsbase.RoamingAppDataDir() + if err != nil { + roamingBase = "" + } + if localBase == "" { + // Should never happen in practice, because this is always set on Windows + localBase = "c:\\" + } + if roamingBase == "" { + roamingBase = localBase // store everything locally, then + } + + roamingDir := filepath.Join(roamingBase, subDir) + localDir := filepath.Join(localBase, subDir) + + return Dirs{ + ConfigDirs: []string{roamingDir}, + DataDirs: []string{roamingDir}, + CacheDir: localDir, + } +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/dirs.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/dirs.go new file mode 100644 index 000000000..db5c33c92 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/dirs.go @@ -0,0 +1,178 @@ +package userdirs + +import ( + "os" + "path/filepath" +) + +// Dirs represents a set of directory paths with different purposes. +type Dirs struct { + // ConfigDirs is a list, in preference order, of directory paths to search + // for configuration files. + // + // The list must always contain at least one element, and its first element + // is the directory where any new configuration files should be written. + // + // On some systems, ConfigDirs and DataDirs may overlap, so applications + // which scan the contents of the configuration directories should impose + // some additional filtering to distinguish configuration files from data + // files. + // + // Files placed in ConfigDirs should ideally be things that it would be + // reasonable to share among multiple systems (possibly on different + // platforms, possibly to check into a version control system, etc. + ConfigDirs []string + + // DataDirs is a list, in preference order, of directory paths to search for + // data files. + // + // The list must always contain at least one element, and its first element + // is the directory where any new data files should be written. + // + // On some systems, ConfigDirs and DataDirs may overlap, so applications + // which scan the contents of the data directories should impose some + // additional filtering to distinguish data files from configuration files. + DataDirs []string + + // CacheDir is the path of a single directory that can be used for temporary + // cache data. + // + // The cache is suitable only for data that the calling application could + // recreate if lost. Any file or directory under this prefix may be deleted + // at any time by other software. + // + // This directory may, on some systems, match one of the directories + // returned in ConfigDirs and/or DataDirs. For this reason applications + // must ensure that they do not misinterpret config and data files as + // cache files, and in particular should not naively purge a cache by + // emptying this directory. + CacheDir string +} + +// ConfigHome returns the path for the directory where any new configuration +// files should be written. +func (d Dirs) ConfigHome() string { + return d.ConfigDirs[0] +} + +// DataHome returns the path for the directory where any new configuration +// files should be written. +func (d Dirs) DataHome() string { + return d.DataDirs[0] +} + +// NewConfigPath joins the given path segments to the ConfigHome to produce a +// path where a new configuration file might be written. +func (d Dirs) NewConfigPath(parts ...string) string { + return filepath.Join(d.ConfigHome(), filepath.Join(parts...)) +} + +// NewDataPath joins the given path segments to the DataHome to produce a +// path where a new data file might be written. +func (d Dirs) NewDataPath(parts ...string) string { + return filepath.Join(d.DataHome(), filepath.Join(parts...)) +} + +// CachePath joins the given path segments to the CacheHome to produce a +// path for a cache file or directory. +func (d Dirs) CachePath(parts ...string) string { + return filepath.Join(d.CacheDir, filepath.Join(parts...)) +} + +// ConfigSearchPaths joins the given path segments to each of the directories +// in in ConfigDirs to produce a more specific set of paths to be searched +// in preference order. +func (d Dirs) ConfigSearchPaths(parts ...string) []string { + return searchPaths(d.ConfigDirs, parts...) +} + +// DataSearchPaths joins the given path segments to each of the directories +// in in ConfigDirs to produce a more specific set of paths to be searched +// in preference order. +func (d Dirs) DataSearchPaths(parts ...string) []string { + return searchPaths(d.DataDirs, parts...) +} + +// FindConfigFiles scans over all of the paths in ConfigDirs and tests whether +// a file of the given name is present in each, returning a slice of full +// paths that matched. +func (d Dirs) FindConfigFiles(parts ...string) []string { + return findFiles(d.ConfigDirs, parts...) +} + +// FindDataFiles scans over all of the paths in ConfigDirs and tests whether +// a file of the given name is present in each, returning a slice of full +// paths that matched. +func (d Dirs) FindDataFiles(parts ...string) []string { + return findFiles(d.DataDirs, parts...) +} + +// GlobConfigFiles joins the given parts to create a glob pattern and then +// applies it relative to each of the paths in ConfigDirs, returning all +// of the matches in a single slice. +// +// The order of the result preserves the directory preference order and +// sorts multiple files within the same directory lexicographically. +// +// Remember that on some platforms the config dirs and data dirs overlap, +// so to be robust you should use distinct naming patterns for configuration +// and data files to avoid accidentally matching data files with this method. +func (d Dirs) GlobConfigFiles(parts ...string) []string { + return globFiles(d.ConfigDirs, parts...) +} + +// GlobDataFiles joins the given parts to create a glob pattern and then +// applies it relative to each of the paths in DataDirs, returning all +// of the matches in a single slice. +// +// The order of the result preserves the directory preference order and +// sorts multiple files within the same directory lexicographically. +// +// Remember that on some platforms the config dirs and data dirs overlap, +// so to be robust you should use distinct naming patterns for configuration +// and data files to avoid accidentally matching configuration files with this +// method. +func (d Dirs) GlobDataFiles(parts ...string) []string { + return globFiles(d.DataDirs, parts...) +} + +func searchPaths(bases []string, parts ...string) []string { + extra := filepath.Join(parts...) + ret := make([]string, len(bases)) + for i, base := range bases { + ret[i] = filepath.Join(base, extra) + } + return ret +} + +func findFiles(bases []string, parts ...string) []string { + extra := filepath.Join(parts...) + ret := make([]string, 0, len(bases)) + for _, base := range bases { + candidate := filepath.Join(base, extra) + if info, err := os.Stat(candidate); err == nil && !info.IsDir() { + ret = append(ret, candidate) + } + } + if len(ret) == 0 { + return nil + } + return ret +} + +func globFiles(bases []string, parts ...string) []string { + extra := filepath.Join(parts...) + var ret []string + for _, base := range bases { + pattern := filepath.Join(base, extra) + found, err := filepath.Glob(pattern) + if err != nil { + continue + } + ret = append(ret, found...) + } + if len(ret) == 0 { + return nil + } + return ret +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/userdirs/doc.go b/vendor/github.com/apparentlymart/go-userdirs/userdirs/doc.go new file mode 100644 index 000000000..941220d7d --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/userdirs/doc.go @@ -0,0 +1,39 @@ +// Package userdirs is a utility for building user-specific filesystem paths +// for applications to store configuration information, caches, etc. +// +// It aims to conform to the conventions of the operating system where it is +// running, allowing applications using this package to follow the relevant +// conventions automatically. +// +// Because the behavior of this library must be tailored for each operating +// system it supports, it supports only a subset of Go's own supported +// operating system targets. Others are intentionally not supported (rather than +// mapped on to some default OS) to avoid the situation where adding a new +// supported OS would change the behavior of existing applications built for +// that OS. +// +// Currently this package supports Mac OS X ("darwin"), Linux and Windows +// first-class. It also maps AIX, Dragonfly, FreeBSD, NetBSD, and Solaris, +// following the same rules as for Linux. +// +// On Mac OS X, we follow the Standard Directories guidelines from +// https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6 . +// +// On Linux and other Unix-like systems, we follow the XDG Base Directory +// specification version 0.8, from https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.8.html . +// +// On Windows, we use the Known Folder API and follow relevant platform conventions +// https://docs.microsoft.com/en-us/windows/desktop/shell/knownfolderid . +// +// On all other systems, the directory-construction functions will panic. Use +// the SupportedOS function to determine whether this function's packages are +// available on the current operating system target, to avoid those panics. +// However, in practice it probably doesn't make much sense to use this package +// when building for an unsupported operating system anyway. +// +// Additional operating systems may be supported in future releases. Once an +// operating system is supported, the constructed paths are frozen to ensure +// that applications can find their same files on future versions. Therefore +// the bar for adding support for a new operating system is there being a +// committed standard published by the operating system vendor. +package userdirs diff --git a/vendor/github.com/apparentlymart/go-userdirs/windowsbase/doc.go b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/doc.go new file mode 100644 index 000000000..e7f2aa921 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/doc.go @@ -0,0 +1,6 @@ +// Package windowsbase contains helper functionality for accessing the +// "Known Folders" shell API functions on Windows systems. +// +// This package calls into Windows system DLLs, so it cannot be used on any +// other platform. +package windowsbase diff --git a/vendor/github.com/apparentlymart/go-userdirs/windowsbase/impl.go b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/impl.go new file mode 100644 index 000000000..13e5b4c88 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/impl.go @@ -0,0 +1,40 @@ +// +build windows + +package windowsbase + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + shell32 = windows.NewLazyDLL("Shell32.dll") + ole32 = windows.NewLazyDLL("Ole32.dll") + procSHGetKnownFolderPath = shell32.NewProc("SHGetKnownFolderPath") + procCoTaskMemFree = ole32.NewProc("CoTaskMemFree") +) + +func knownFolderDir(fid *FolderID) (string, error) { + var path uintptr + err := shGetKnownFolderPath(fid, 0, 0, &path) + if err != nil { + return "", err + } + defer coTaskMemFree(path) + dir := syscall.UTF16ToString((*[1 << 16]uint16)(unsafe.Pointer(path))[:]) + return dir, nil +} + +func shGetKnownFolderPath(fid *FolderID, dwFlags uint32, hToken syscall.Handle, pszPath *uintptr) (retval error) { + r0, _, _ := procSHGetKnownFolderPath.Call(uintptr(unsafe.Pointer(fid)), uintptr(dwFlags), uintptr(hToken), uintptr(unsafe.Pointer(pszPath)), 0, 0) + if r0 != 0 { + return syscall.Errno(r0) + } + return nil +} + +func coTaskMemFree(pv uintptr) { + procCoTaskMemFree.Call(uintptr(pv), 0, 0) +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/windowsbase/stub.go b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/stub.go new file mode 100644 index 000000000..21df8a36d --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/stub.go @@ -0,0 +1,11 @@ +// +build !windows + +package windowsbase + +import ( + "errors" +) + +func knownFolderDir(id *FolderID) (string, error) { + return "", errors.New("cannot use Windows known folders on a non-Windows platform") +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go new file mode 100644 index 000000000..d19f3d353 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go @@ -0,0 +1,35 @@ +package windowsbase + +// FolderID is a representation of a known folder id UUID +type FolderID struct { + a uint32 + b uint16 + c uint16 + d [8]byte +} + +var ( + // RoamingAppDataID is the FolderID for the roaming application data folder + RoamingAppDataID = &FolderID{0x3EB685DB, 0x65F9, 0x4CF6, [...]byte{0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D}} + + // LocalAppDataID is the FolderID for the local application data folder + LocalAppDataID = &FolderID{0xF1B32785, 0x6FBA, 0x4FCF, [...]byte{0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91}} +) + +// KnownFolderDir returns the absolute path for the given known folder id, or +// returns an error if that is not possible. +func KnownFolderDir(id *FolderID) (string, error) { + return knownFolderDir(id) +} + +// RoamingAppDataDir returns the absolute path for the current user's roaming +// application data directory. +func RoamingAppDataDir() (string, error) { + return KnownFolderDir(RoamingAppDataID) +} + +// LocalAppDataDir returns the absolute path for the current user's local +// application data directory. +func LocalAppDataDir() (string, error) { + return KnownFolderDir(LocalAppDataID) +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/xdgbase/doc.go b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/doc.go new file mode 100644 index 000000000..11c561640 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/doc.go @@ -0,0 +1,8 @@ +// Package xdgbase is an implementation of the XDG Basedir Specification +// version 0.8, as published at https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.8.html . +// +// This package has no checks for the host operating system, so it can in +// principle function on any operating system but in practice XDG conventions +// are followed only on some Unix-like systems, so using this library elsewhere +// would not be very useful and will produce undefined results. +package xdgbase diff --git a/vendor/github.com/apparentlymart/go-userdirs/xdgbase/home.go b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/home.go new file mode 100644 index 000000000..45cbda878 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/home.go @@ -0,0 +1,9 @@ +package xdgbase + +import ( + "github.com/apparentlymart/go-userdirs/internal/unix" +) + +func home() string { + return unix.Home() +} diff --git a/vendor/github.com/apparentlymart/go-userdirs/xdgbase/xdg.go b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/xdg.go new file mode 100644 index 000000000..b6dcc7821 --- /dev/null +++ b/vendor/github.com/apparentlymart/go-userdirs/xdgbase/xdg.go @@ -0,0 +1,105 @@ +package xdgbase + +import ( + "os" + "path/filepath" +) + +// DataHome returns the value of XDG_DATA_HOME, or the specification-defined +// fallback value of $HOME/.local/share. +func DataHome() string { + return envSingle("XDG_DATA_HOME", func() string { + return filepath.Join(home(), ".local", "share") + }) +} + +// OtherDataDirs returns the values from XDG_DATA_DIRS, or the specification-defined +// fallback values "/usr/local/share/" and "/usr/share/". +func OtherDataDirs() []string { + return envMulti("XDG_DATA_DIRS", func() []string { + return []string{"/usr/local/share/", "/usr/share/"} + }) +} + +// DataDirs returns the combination of DataHome and OtherDataDirs, giving the +// full set of data directories to search, in preference order. +func DataDirs() []string { + ret := make([]string, 0, 3) // default OtherDataDirs has two elements + ret = append(ret, DataHome()) + ret = append(ret, OtherDataDirs()...) + return ret[:len(ret):len(ret)] +} + +// ConfigHome returns the value of XDG_CONFIG_HOME, or the specification-defined +// fallback value of $HOME/.config. +func ConfigHome() string { + return envSingle("XDG_CONFIG_HOME", func() string { + return filepath.Join(home(), ".config") + }) +} + +// OtherConfigDirs returns the values from XDG_CONFIG_DIRS, or the +// specification-defined fallback value "/etc/xdg". +func OtherConfigDirs() []string { + return envMulti("XDG_CONFIG_DIRS", func() []string { + return []string{"/etc/xdg"} + }) +} + +// ConfigDirs returns the combination of ConfigHome and OtherConfigDirs, giving the +// full set of config directories to search, in preference order. +func ConfigDirs() []string { + ret := make([]string, 0, 2) // default OtherConfigDirs has one element + ret = append(ret, ConfigHome()) + ret = append(ret, OtherConfigDirs()...) + return ret[:len(ret):len(ret)] +} + +// CacheHome returns the value of XDG_CACHE_HOME, or the specification-defined +// fallback value of $HOME/.cache. +func CacheHome() string { + return envSingle("XDG_CACHE_HOME", func() string { + return filepath.Join(home(), ".cache") + }) +} + +// MaybeRuntimeDir returns the value of XDG_RUNTIME_DIR, or an empty string if +// it is not set. +// +// Calling applications MUST check that the return value is non-empty before +// using it, because there is no reasonable default behavior when no runtime +// directory is defined. +func MaybeRuntimeDir() string { + return envSingle("XDG_RUNTIME_DIR", func() string { + return "" + }) +} + +func envSingle(name string, fallback func() string) string { + if p := os.Getenv(name); p != "" { + if filepath.IsAbs(p) { + return p + } + } + + return fallback() +} + +func envMulti(name string, fallback func() []string) []string { + if p := os.Getenv(name); p != "" { + parts := filepath.SplitList(p) + // Make sure all of the paths are absolute + for i := len(parts) - 1; i >= 0; i-- { + if !filepath.IsAbs(parts[i]) { + // We'll shift everything after this point in the list + // down so that this element is no longer present. + copy(parts[i:], parts[i+1:]) + parts = parts[:len(parts)-1] + } + } + parts = parts[:len(parts):len(parts)] // hide any extra capacity from the caller + return parts + } + + return fallback() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 294b0e830..045e4b922 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -97,6 +97,13 @@ github.com/apparentlymart/go-cidr/cidr github.com/apparentlymart/go-dump/dump # github.com/apparentlymart/go-textseg v1.0.0 github.com/apparentlymart/go-textseg/textseg +# github.com/apparentlymart/go-userdirs v0.0.0-20190512014041-4a23807e62b9 +## explicit +github.com/apparentlymart/go-userdirs/internal/unix +github.com/apparentlymart/go-userdirs/macosbase +github.com/apparentlymart/go-userdirs/userdirs +github.com/apparentlymart/go-userdirs/windowsbase +github.com/apparentlymart/go-userdirs/xdgbase # github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171 ## explicit github.com/apparentlymart/go-versions/versions