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.
This commit is contained in:
parent
fcb8c53454
commit
c945ef129a
1
go.mod
1
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
|
||||
|
|
5
go.sum
5
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=
|
||||
|
|
|
@ -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.
|
97
vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go
generated
vendored
Normal file
97
vendor/github.com/apparentlymart/go-userdirs/internal/unix/homedir.go
generated
vendored
Normal file
|
@ -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 ""
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
|||
package macosbase
|
||||
|
||||
import (
|
||||
"github.com/apparentlymart/go-userdirs/internal/unix"
|
||||
)
|
||||
|
||||
func home() string {
|
||||
return unix.Home()
|
||||
}
|
26
vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go
generated
vendored
Normal file
26
vendor/github.com/apparentlymart/go-userdirs/macosbase/macosbase.go
generated
vendored
Normal file
|
@ -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")
|
||||
}
|
|
@ -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()
|
||||
}
|
29
vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go
generated
vendored
Normal file
29
vendor/github.com/apparentlymart/go-userdirs/userdirs/app_darwin.go
generated
vendored
Normal file
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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, " ", "-"))
|
||||
}
|
41
vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go
generated
vendored
Normal file
41
vendor/github.com/apparentlymart/go-userdirs/userdirs/app_windows.go
generated
vendored
Normal file
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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")
|
||||
}
|
35
vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go
generated
vendored
Normal file
35
vendor/github.com/apparentlymart/go-userdirs/windowsbase/windowsbase.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
|||
package xdgbase
|
||||
|
||||
import (
|
||||
"github.com/apparentlymart/go-userdirs/internal/unix"
|
||||
)
|
||||
|
||||
func home() string {
|
||||
return unix.Home()
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue