diff --git a/go.mod b/go.mod
index 2e036e3..1094212 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@ require (
code.gitea.io/gitea-vet v0.2.0
code.gitea.io/sdk/gitea v0.13.0
github.com/AlecAivazis/survey/v2 v2.1.1
+ github.com/adrg/xdg v0.2.1
github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1
github.com/charmbracelet/glamour v0.2.0
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
diff --git a/go.sum b/go.sum
index 70b4b51..62a9b37 100644
--- a/go.sum
+++ b/go.sum
@@ -7,6 +7,8 @@ github.com/AlecAivazis/survey/v2 v2.1.1/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0T
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/adrg/xdg v0.2.1 h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=
+github.com/adrg/xdg v0.2.1/go.mod h1:ZuOshBmzV4Ta+s23hdfFZnBsdzmoR3US0d7ErpqSbTQ=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
diff --git a/modules/config/config.go b/modules/config/config.go
index e5a5cf6..34913af 100644
--- a/modules/config/config.go
+++ b/modules/config/config.go
@@ -9,13 +9,13 @@ import (
"fmt"
"io/ioutil"
"log"
- "os"
"path/filepath"
"strings"
"code.gitea.io/tea/modules/git"
"code.gitea.io/tea/modules/utils"
+ "github.com/adrg/xdg"
"gopkg.in/yaml.v2"
)
@@ -26,29 +26,34 @@ type LocalConfig struct {
var (
// Config contain if loaded local tea config
- Config LocalConfig
- yamlConfigPath string
+ Config LocalConfig
)
-// TODO: do not use init function to detect the tea configuration, use GetConfigPath()
-func init() {
- homeDir, err := utils.Home()
- if err != nil {
- log.Fatal("Retrieve home dir failed")
- }
-
- dir := filepath.Join(homeDir, ".tea")
- err = os.MkdirAll(dir, os.ModePerm)
- if err != nil {
- log.Fatal("Init tea config dir " + dir + " failed")
- }
-
- yamlConfigPath = filepath.Join(dir, "tea.yml")
-}
-
// GetConfigPath return path to tea config file
func GetConfigPath() string {
- return yamlConfigPath
+ configFilePath, err := xdg.ConfigFile("tea/config.yml")
+
+ var exists bool
+ if err != nil {
+ exists = false
+ } else {
+ exists, _ = utils.PathExists(configFilePath)
+ }
+
+ // fallback to old config if no new one exists
+ if !exists {
+ file := filepath.Join(xdg.Home, ".tea", "tea.yml")
+ exists, _ = utils.PathExists(file)
+ if exists {
+ return file
+ }
+ }
+
+ if err != nil {
+ log.Fatal("unable to get or create config file")
+ }
+
+ return configFilePath
}
// LoadConfig load config into global Config var
@@ -58,12 +63,12 @@ func LoadConfig() error {
if exist {
bs, err := ioutil.ReadFile(ymlPath)
if err != nil {
- return err
+ return fmt.Errorf("Failed to read config file: %s", ymlPath)
}
err = yaml.Unmarshal(bs, &Config)
if err != nil {
- return err
+ return fmt.Errorf("Failed to parse contents of config file: %s", ymlPath)
}
}
diff --git a/modules/config/login.go b/modules/config/login.go
index 9d37510..e4488a9 100644
--- a/modules/config/login.go
+++ b/modules/config/login.go
@@ -131,7 +131,7 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
err := LoadConfig()
if err != nil {
- log.Fatal("Unable to load config file " + yamlConfigPath)
+ log.Fatal(err)
}
for _, l := range Config.Logins {
@@ -253,7 +253,7 @@ func InitCommand(repoValue, loginValue, remoteValue string) (*Login, string, str
err := LoadConfig()
if err != nil {
- log.Fatal("load config file failed ", yamlConfigPath)
+ log.Fatal(err)
}
if login, err = GetDefaultLogin(); err != nil {
@@ -287,7 +287,7 @@ func InitCommand(repoValue, loginValue, remoteValue string) (*Login, string, str
func InitCommandLoginOnly(loginValue string) *Login {
err := LoadConfig()
if err != nil {
- log.Fatal("load config file failed ", yamlConfigPath)
+ log.Fatal(err)
}
var login *Login
diff --git a/modules/utils/home.go b/modules/utils/home.go
deleted file mode 100644
index 47361c9..0000000
--- a/modules/utils/home.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2018 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package utils
-
-import (
- "bytes"
- "errors"
- "os"
- "os/exec"
- "os/user"
- "runtime"
- "strconv"
- "strings"
-)
-
-// Home returns the home directory for the executing user.
-//
-// This uses an OS-specific method for discovering the home directory.
-// An error is returned if a home directory cannot be detected.
-func Home() (string, error) {
- user, err := user.Current()
- if nil == err {
- return user.HomeDir, nil
- }
-
- // cross compile support
- if "windows" == runtime.GOOS {
- return homeWindows()
- }
-
- // Unix-like system, so just assume Unix
- return homeUnix()
-}
-
-func homeUnix() (string, error) {
- // First prefer the HOME environmental variable
- if home := os.Getenv("HOME"); home != "" {
- return home, nil
- }
-
- // If that fails, try getent
- var stdout bytes.Buffer
- cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
- cmd.Stdout = &stdout
- if err := cmd.Run(); err != nil {
- // If the error is ErrNotFound, we ignore it. Otherwise, return it.
- if err != exec.ErrNotFound {
- return "", err
- }
- } else {
- if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
- // username:password:uid:gid:gecos:home:shell
- passwdParts := strings.SplitN(passwd, ":", 7)
- if len(passwdParts) > 5 {
- return passwdParts[5], nil
- }
- }
- }
-
- // If all else fails, try the shell
- stdout.Reset()
- cmd = exec.Command("sh", "-c", "cd && pwd")
- cmd.Stdout = &stdout
- if err := cmd.Run(); err != nil {
- return "", err
- }
-
- result := strings.TrimSpace(stdout.String())
- if result == "" {
- return "", errors.New("blank output when reading home directory")
- }
-
- return result, nil
-}
-
-func homeWindows() (string, error) {
- // First prefer the HOME environmental variable
- if home := os.Getenv("HOME"); home != "" {
- return home, nil
- }
-
- drive := os.Getenv("HOMEDRIVE")
- path := os.Getenv("HOMEPATH")
- home := drive + path
- if drive == "" || path == "" {
- home = os.Getenv("USERPROFILE")
- }
- if home == "" {
- return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
- }
-
- return home, nil
-}
diff --git a/vendor/github.com/adrg/xdg/.travis.yml b/vendor/github.com/adrg/xdg/.travis.yml
new file mode 100644
index 0000000..7b333cc
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/.travis.yml
@@ -0,0 +1,19 @@
+language: go
+go:
+ - 1.11.x
+ - 1.12.x
+ - 1.13.x
+os:
+ - linux
+ - osx
+ - windows
+env:
+ - GO111MODULE=on
+git:
+ autocrlf: false
+before_install:
+ - go get -t -v ./...
+ - go install github.com/golangci/golangci-lint/cmd/golangci-lint
+script:
+ - golangci-lint run --enable-all -D wsl -D gochecknoinits -D gochecknoglobals -D prealloc
+ - go test -v -race ./...
diff --git a/vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md b/vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..75349e5
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md
@@ -0,0 +1,77 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age,
+body size, disability, ethnicity, sex characteristics, gender identity and
+expression, level of experience, education, socio-economic status, nationality,
+personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behaviour that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behaviour by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behaviour and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behaviour.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviour that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behaviour may be
+reported by contacting the project team at adrg@epistack.com. All complaints
+will be reviewed and investigated and will result in a response that is deemed
+necessary and appropriate to the circumstances. The project team is obligated to
+maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/vendor/github.com/adrg/xdg/CONTRIBUTING.md b/vendor/github.com/adrg/xdg/CONTRIBUTING.md
new file mode 100644
index 0000000..006f146
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/CONTRIBUTING.md
@@ -0,0 +1,135 @@
+# Contributing to this project
+
+Contributions in the form of pull requests, issues or just general feedback,
+are always welcome. Please take a moment to review this document in order to
+make the contribution process easy and effective for everyone involved.
+
+Following these guidelines helps to communicate that you respect the time of
+the developers managing and developing this open source project. In return,
+they should reciprocate that respect in addressing your issue or assessing
+patches and features.
+
+## Using the issue tracker
+
+The issue tracker is the preferred channel for [bug reports](#bugs),
+[features requests](#features) and [submitting pull
+requests](#pull-requests), but please respect the following restrictions:
+
+* Please **do not** use the issue tracker for personal support requests (use
+ [Stack Overflow](http://stackoverflow.com) or IRC).
+* Please **do not** derail or troll issues. Keep the discussion on topic and
+ respect the opinions of others.
+
+
+## Bug reports
+
+A bug is a _demonstrable problem_ that is caused by the code in the repository.
+Good bug reports are extremely helpful - thank you!
+
+Guidelines for bug reports:
+
+1. **Use the GitHub issue search** — check if the issue has already been
+ reported.
+2. **Check if the issue has been fixed** — try to reproduce it using the
+ latest `master` or development branch in the repository.
+3. **Isolate the problem** — create a reduced test case.
+
+A good bug report shouldn't leave others needing to chase you up for more
+information. Please try to be as detailed as possible in your report. What is
+your environment? What steps will reproduce the issue? What browser(s) and OS
+experience the problem? What would you expect to be the outcome? All these
+details will help people to fix any potential bugs.
+
+Example:
+
+> Short and descriptive example bug report title
+>
+> A summary of the issue and the browser/OS environment in which it occurs. If
+> suitable, include the steps required to reproduce the bug.
+>
+> 1. This is the first step
+> 2. This is the second step
+> 3. Further steps, etc.
+>
+> `` - a link to the reduced test case
+>
+> Any other information you want to share that is relevant to the issue being
+> reported. This might include the lines of code that you have identified as
+> causing the bug, and potential solutions (and your opinions on their
+> merits).
+
+
+
+## Feature requests
+
+Feature requests are welcome. But take a moment to find out whether your idea
+fits with the scope and aims of the project. It's up to *you* to make a strong
+case to convince the project's developers of the merits of this feature. Please
+provide as much detail and context as possible.
+
+
+
+## Pull requests
+
+Good pull requests - patches, improvements, new features - are a fantastic
+help. They should remain focused in scope and avoid containing unrelated
+commits.
+
+**Please ask first** before embarking on any significant pull request (e.g.
+implementing features, refactoring code, porting to a different language),
+otherwise you risk spending a lot of time working on something that the
+project's developers might not want to merge into the project.
+
+Please adhere to the coding conventions used throughout a project (indentation,
+accurate comments, etc.) and any other requirements (such as test coverage).
+
+Follow this process if you'd like your work considered for inclusion in the
+project:
+
+1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
+ and configure the remotes:
+
+ ```bash
+ # Clone your fork of the repo into the current directory
+ git clone https://github.com//
+ # Navigate to the newly cloned directory
+ cd
+ # Assign the original repo to a remote called "upstream"
+ git remote add upstream https://github.com//
+ ```
+
+2. If you cloned a while ago, get the latest changes from upstream:
+
+ ```bash
+ git checkout
+ git pull upstream
+ ```
+
+3. Create a new topic branch (off the main project development branch) to
+ contain your feature, change, or fix:
+
+ ```bash
+ git checkout -b
+ ```
+
+4. Commit your changes in logical chunks and use descriptive commit messages.
+ Use [interactive rebase](https://help.github.com/articles/interactive-rebase)
+ to tidy up your commits before making them public.
+
+5. Locally merge (or rebase) the upstream development branch into your topic branch:
+
+ ```bash
+ git pull [--rebase] upstream
+ ```
+
+6. Push your topic branch up to your fork:
+
+ ```bash
+ git push origin
+ ```
+
+7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
+ with a clear title and description.
+
+**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
+license your work under the same license as that used by the project.
diff --git a/vendor/github.com/adrg/xdg/LICENSE b/vendor/github.com/adrg/xdg/LICENSE
new file mode 100644
index 0000000..7307e1b
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Adrian-George Bostan
+
+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/adrg/xdg/README.md b/vendor/github.com/adrg/xdg/README.md
new file mode 100644
index 0000000..a9ad34e
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/README.md
@@ -0,0 +1,187 @@
+xdg
+===
+[![Build Status](https://travis-ci.org/adrg/xdg.svg?branch=master)](https://travis-ci.org/adrg/xdg)
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/adrg/xdg)
+[![License: MIT](https://img.shields.io/badge/license-MIT-red.svg?style=flat-square)](https://opensource.org/licenses/MIT)
+[![Go Report Card](https://goreportcard.com/badge/github.com/adrg/xdg)](https://goreportcard.com/report/github.com/adrg/xdg)
+
+Provides an implementation of the [XDG Base Directory Specification](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html).
+The specification defines a set of standard paths for storing application files,
+including data and configuration files. For portability and flexibility reasons,
+applications should use the XDG defined locations instead of hardcoding paths.
+The package also includes the locations of well known user directories.
+The current implementation supports Windows, Mac OS and most flavors of Unix.
+
+Full documentation can be found at: https://godoc.org/github.com/adrg/xdg
+
+## Installation
+ go get github.com/adrg/xdg
+
+## Default locations
+
+The package defines sensible defaults for XDG variables which are empty or not
+present in the environment.
+
+#### XDG Base Directory
+
+| | Unix | Mac OS | Windows |
+| :--- | :--- | :----- | :--- |
+| XDG_DATA_HOME | `~/.local/share` | `~/Library/Application Support` | `%LOCALAPPDATA%` |
+| XDG_DATA_DIRS | `/usr/local/share`
`/usr/share` | `/Library/Application Support` | `%APPDATA%\Roaming`
`%PROGRAMDATA%` |
+| XDG_CONFIG_HOME | `~/.config` | `~/Library/Preferences` | `%LOCALAPPDATA%` |
+| XDG_CONFIG_DIRS | `/etc/xdg` | `/Library/Preferences` | `%PROGRAMDATA%` |
+| XDG_CACHE_HOME | `~/.cache` | `~/Library/Caches` | `%LOCALAPPDATA%\cache` |
+| XDG_RUNTIME_DIR | `/run/user/UID` | `~/Library/Application Support` | `%LOCALAPPDATA%` |
+
+#### XDG user directories
+
+| | Unix | Mac OS | Windows |
+| :--- | :--- | :----- | :--- |
+| XDG_DESKTOP_DIR | `~/Desktop` | `~/Desktop` | `%USERPROFILE%/Desktop` |
+| XDG_DOWNLOAD_DIR | `~/Downloads` | `~/Downloads` | `%USERPROFILE%/Downloads` |
+| XDG_DOCUMENTS_DIR | `~/Documents` | `~/Documents` | `%USERPROFILE%/Documents` |
+| XDG_MUSIC_DIR | `~/Music` | `~/Music` | `%USERPROFILE%/Music` |
+| XDG_PICTURES_DIR | `~/Pictures` | `~/Pictures` | `%USERPROFILE%/Pictures` |
+| XDG_VIDEOS_DIR | `~/Videos` | `~/Movies` | `%USERPROFILE%/Videos` |
+| XDG_TEMPLATES_DIR | `~/Templates` | `~/Templates` | `%USERPROFILE%/Templates` |
+| XDG_PUBLICSHARE_DIR | `~/Public` | `~/Public` | `%PUBLIC%` |
+
+#### Non-standard directories
+
+Application directories
+
+```
+Unix:
+- $XDG_DATA_HOME/applications
+- ~/.local/share/applications
+- /usr/local/share/applications
+- /usr/share/applications
+- $XDG_DATA_DIRS/applications
+
+Mac OS:
+- /Applications
+
+Windows:
+- %APPDATA%\Roaming\Microsoft\Windows\Start Menu\Programs
+```
+
+Font Directories
+
+```
+Unix:
+- $XDG_DATA_HOME/fonts
+- ~/.fonts
+- ~/.local/share/fonts
+- /usr/local/share/fonts
+- /usr/share/fonts
+- $XDG_DATA_DIRS/fonts
+
+Mac OS:
+- ~/Library/Fonts
+- /Library/Fonts
+- /System/Library/Fonts
+- /Network/Library/Fonts
+
+Windows:
+- %windir%\Fonts
+- %LOCALAPPDATA%\Microsoft\Windows\Fonts
+```
+
+## Usage
+
+#### XDG Base Directory
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/adrg/xdg"
+)
+
+func main() {
+ // XDG Base Directory paths.
+ log.Println("Home config directory:", xdg.DataHome)
+ log.Println("Data directories:", xdg.DataDirs)
+ log.Println("Home config directory:", xdg.ConfigHome)
+ log.Println("Config directories:", xdg.ConfigDirs)
+ log.Println("Cache directory:", xdg.CacheHome)
+ log.Println("Runtime directory:", xdg.RuntimeDir)
+
+ // Non-standard directories.
+ log.Println("Application directories:", xdg.ApplicationDirs)
+ log.Println("Font directories:", xdg.FontDirs)
+
+ // Obtain a suitable location for application config files.
+ // ConfigFile takes one parameter which must contain the name of the file,
+ // but it can also contain a set of parent directories. If the directories
+ // don't exists, they will be created relative to the base config directory.
+ configFilePath, err := xdg.ConfigFile("appname/config.yaml")
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Save the config file at:", configFilePath)
+
+ // For other types of application files use:
+ // xdg.DataFile()
+ // xdg.CacheFile()
+ // xdg.RuntimeFile()
+
+ // Finding application config files.
+ // SearchConfigFile takes one parameter which must contain the name of
+ // the file, but it can also contain a set of parent directories relative
+ // to the config search paths (xdg.ConfigHome and xdg.ConfigDirs).
+ configFilePath, err = xdg.SearchConfigFile("appname/config.yaml")
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Config file was found at:", configFilePath)
+
+ // For other types of application files use:
+ // xdg.SearchDataFile()
+ // xdg.SearchCacheFile()
+ // xdg.SearchRuntimeFile()
+}
+```
+
+#### XDG user directories
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/adrg/xdg"
+)
+
+func main() {
+ // XDG user directories.
+ log.Println("Desktop directory:", xdg.UserDirs.Desktop)
+ log.Println("Download directory:", xdg.UserDirs.Download)
+ log.Println("Documents directory:", xdg.UserDirs.Documents)
+ log.Println("Music directory:", xdg.UserDirs.Music)
+ log.Println("Pictures directory:", xdg.UserDirs.Pictures)
+ log.Println("Videos directory:", xdg.UserDirs.Videos)
+ log.Println("Templates directory:", xdg.UserDirs.Templates)
+ log.Println("Public directory:", xdg.UserDirs.PublicShare)
+}
+```
+
+## References
+For more information see the
+[XDG Base Directory Specification](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and
+[XDG user directories](https://wiki.archlinux.org/index.php/XDG_user_directories).
+
+## Contributing
+
+Contributions in the form of pull requests, issues or just general feedback,
+are always welcome.
+See [CONTRIBUTING.MD](https://github.com/adrg/xdg/blob/master/CONTRIBUTING.md).
+
+## License
+Copyright (c) 2014 Adrian-George Bostan.
+
+This project is licensed under the [MIT license](https://opensource.org/licenses/MIT).
+See [LICENSE](https://github.com/adrg/xdg/blob/master/LICENSE) for more details.
diff --git a/vendor/github.com/adrg/xdg/base_dirs.go b/vendor/github.com/adrg/xdg/base_dirs.go
new file mode 100644
index 0000000..0b2054c
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/base_dirs.go
@@ -0,0 +1,78 @@
+package xdg
+
+import "os"
+
+// XDG Base Directory environment variables.
+var (
+ envDataHome = "XDG_DATA_HOME"
+ envDataDirs = "XDG_DATA_DIRS"
+ envConfigHome = "XDG_CONFIG_HOME"
+ envConfigDirs = "XDG_CONFIG_DIRS"
+ envCacheHome = "XDG_CACHE_HOME"
+ envRuntimeDir = "XDG_RUNTIME_DIR"
+)
+
+type baseDirectories struct {
+ dataHome string
+ data []string
+ configHome string
+ config []string
+ cacheHome string
+ runtime string
+
+ // Non-standard directories.
+ fonts []string
+ applications []string
+}
+
+func (bd baseDirectories) dataFile(relPath string) (string, error) {
+ return createPath(relPath, append([]string{bd.dataHome}, bd.data...))
+}
+
+func (bd baseDirectories) configFile(relPath string) (string, error) {
+ return createPath(relPath, append([]string{bd.configHome}, bd.config...))
+}
+
+func (bd baseDirectories) cacheFile(relPath string) (string, error) {
+ return createPath(relPath, []string{bd.cacheHome})
+}
+
+func (bd baseDirectories) runtimeFile(relPath string) (string, error) {
+ fi, err := os.Lstat(bd.runtime)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return createPath(relPath, []string{bd.runtime})
+ }
+ return "", err
+ }
+
+ if fi.IsDir() {
+ // The runtime directory must be owned by the user.
+ if err = os.Chown(bd.runtime, os.Getuid(), os.Getgid()); err != nil {
+ return "", err
+ }
+ } else {
+ // For security reasons, the runtime directory cannot be a symlink.
+ if err = os.Remove(bd.runtime); err != nil {
+ return "", err
+ }
+ }
+
+ return createPath(relPath, []string{bd.runtime})
+}
+
+func (bd baseDirectories) searchDataFile(relPath string) (string, error) {
+ return searchFile(relPath, append([]string{bd.dataHome}, bd.data...))
+}
+
+func (bd baseDirectories) searchConfigFile(relPath string) (string, error) {
+ return searchFile(relPath, append([]string{bd.configHome}, bd.config...))
+}
+
+func (bd baseDirectories) searchCacheFile(relPath string) (string, error) {
+ return searchFile(relPath, []string{bd.cacheHome})
+}
+
+func (bd baseDirectories) searchRuntimeFile(relPath string) (string, error) {
+ return searchFile(relPath, []string{bd.runtime})
+}
diff --git a/vendor/github.com/adrg/xdg/go.mod b/vendor/github.com/adrg/xdg/go.mod
new file mode 100644
index 0000000..87b1ff6
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/go.mod
@@ -0,0 +1 @@
+module github.com/adrg/xdg
diff --git a/vendor/github.com/adrg/xdg/paths_darwin.go b/vendor/github.com/adrg/xdg/paths_darwin.go
new file mode 100644
index 0000000..d74447b
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/paths_darwin.go
@@ -0,0 +1,37 @@
+package xdg
+
+import (
+ "path/filepath"
+)
+
+func initBaseDirs(home string) {
+ // Initialize base directories.
+ baseDirs.dataHome = xdgPath(envDataHome, filepath.Join(home, "Library", "Application Support"))
+ baseDirs.data = xdgPaths(envDataDirs, "/Library/Application Support")
+ baseDirs.configHome = xdgPath(envConfigHome, filepath.Join(home, "Library", "Preferences"))
+ baseDirs.config = xdgPaths(envConfigDirs, "/Library/Preferences")
+ baseDirs.cacheHome = xdgPath(envCacheHome, filepath.Join(home, "Library", "Caches"))
+ baseDirs.runtime = xdgPath(envRuntimeDir, filepath.Join(home, "Library", "Application Support"))
+
+ // Initialize non-standard directories.
+ baseDirs.applications = []string{
+ "/Applications",
+ }
+ baseDirs.fonts = []string{
+ filepath.Join(home, "Library/Fonts"),
+ "/Library/Fonts",
+ "/System/Library/Fonts",
+ "/Network/Library/Fonts",
+ }
+}
+
+func initUserDirs(home string) {
+ UserDirs.Desktop = xdgPath(envDesktopDir, filepath.Join(home, "Desktop"))
+ UserDirs.Download = xdgPath(envDownloadDir, filepath.Join(home, "Downloads"))
+ UserDirs.Documents = xdgPath(envDocumentsDir, filepath.Join(home, "Documents"))
+ UserDirs.Music = xdgPath(envMusicDir, filepath.Join(home, "Music"))
+ UserDirs.Pictures = xdgPath(envPicturesDir, filepath.Join(home, "Pictures"))
+ UserDirs.Videos = xdgPath(envVideosDir, filepath.Join(home, "Movies"))
+ UserDirs.Templates = xdgPath(envTemplatesDir, filepath.Join(home, "Templates"))
+ UserDirs.PublicShare = xdgPath(envPublicShareDir, filepath.Join(home, "Public"))
+}
diff --git a/vendor/github.com/adrg/xdg/paths_unix.go b/vendor/github.com/adrg/xdg/paths_unix.go
new file mode 100644
index 0000000..b48a2f9
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/paths_unix.go
@@ -0,0 +1,54 @@
+// +build aix dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package xdg
+
+import (
+ "os"
+ "path/filepath"
+ "strconv"
+)
+
+func initBaseDirs(home string) {
+ // Initialize base directories.
+ baseDirs.dataHome = xdgPath(envDataHome, filepath.Join(home, ".local", "share"))
+ baseDirs.data = xdgPaths(envDataDirs, "/usr/local/share", "/usr/share")
+ baseDirs.configHome = xdgPath(envConfigHome, filepath.Join(home, ".config"))
+ baseDirs.config = xdgPaths(envConfigDirs, "/etc/xdg")
+ baseDirs.cacheHome = xdgPath(envCacheHome, filepath.Join(home, ".cache"))
+ baseDirs.runtime = xdgPath(envRuntimeDir, filepath.Join("/run/user", strconv.Itoa(os.Getuid())))
+
+ // Initialize non-standard directories.
+ appDirs := []string{
+ filepath.Join(baseDirs.dataHome, "applications"),
+ filepath.Join(home, ".local/share/applications"),
+ "/usr/local/share/applications",
+ "/usr/share/applications",
+ }
+
+ fontDirs := []string{
+ filepath.Join(baseDirs.dataHome, "fonts"),
+ filepath.Join(home, ".fonts"),
+ filepath.Join(home, ".local/share/fonts"),
+ "/usr/local/share/fonts",
+ "/usr/share/fonts",
+ }
+
+ for _, dir := range baseDirs.data {
+ appDirs = append(appDirs, filepath.Join(dir, "applications"))
+ fontDirs = append(fontDirs, filepath.Join(dir, "fonts"))
+ }
+
+ baseDirs.applications = uniquePaths(appDirs)
+ baseDirs.fonts = uniquePaths(fontDirs)
+}
+
+func initUserDirs(home string) {
+ UserDirs.Desktop = xdgPath(envDesktopDir, filepath.Join(home, "Desktop"))
+ UserDirs.Download = xdgPath(envDownloadDir, filepath.Join(home, "Downloads"))
+ UserDirs.Documents = xdgPath(envDocumentsDir, filepath.Join(home, "Documents"))
+ UserDirs.Music = xdgPath(envMusicDir, filepath.Join(home, "Music"))
+ UserDirs.Pictures = xdgPath(envPicturesDir, filepath.Join(home, "Pictures"))
+ UserDirs.Videos = xdgPath(envVideosDir, filepath.Join(home, "Videos"))
+ UserDirs.Templates = xdgPath(envTemplatesDir, filepath.Join(home, "Templates"))
+ UserDirs.PublicShare = xdgPath(envPublicShareDir, filepath.Join(home, "Public"))
+}
diff --git a/vendor/github.com/adrg/xdg/paths_windows.go b/vendor/github.com/adrg/xdg/paths_windows.go
new file mode 100644
index 0000000..24194f0
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/paths_windows.go
@@ -0,0 +1,69 @@
+package xdg
+
+import (
+ "os"
+ "path/filepath"
+)
+
+func initBaseDirs(home string) {
+ appDataDir := os.Getenv("APPDATA")
+ if appDataDir == "" {
+ appDataDir = filepath.Join(home, "AppData")
+ }
+ roamingAppDataDir := filepath.Join(appDataDir, "Roaming")
+
+ localAppDataDir := os.Getenv("LOCALAPPDATA")
+ if localAppDataDir == "" {
+ localAppDataDir = filepath.Join(appDataDir, "Local")
+ }
+
+ programDataDir := os.Getenv("PROGRAMDATA")
+ if programDataDir == "" {
+ if systemDrive := os.Getenv("SystemDrive"); systemDrive != "" {
+ programDataDir = filepath.Join(systemDrive, "ProgramData")
+ } else {
+ programDataDir = home
+ }
+ }
+
+ winDir := os.Getenv("windir")
+ if winDir == "" {
+ winDir = os.Getenv("SystemRoot")
+ if winDir == "" {
+ winDir = home
+ }
+ }
+
+ // Initialize base directories.
+ baseDirs.dataHome = xdgPath(envDataHome, localAppDataDir)
+ baseDirs.data = xdgPaths(envDataDirs, roamingAppDataDir, programDataDir)
+ baseDirs.configHome = xdgPath(envConfigHome, localAppDataDir)
+ baseDirs.config = xdgPaths(envConfigDirs, programDataDir)
+ baseDirs.cacheHome = xdgPath(envCacheHome, filepath.Join(localAppDataDir, "cache"))
+ baseDirs.runtime = xdgPath(envRuntimeDir, localAppDataDir)
+
+ // Initialize non-standard directories.
+ baseDirs.applications = []string{
+ filepath.Join(roamingAppDataDir, "Microsoft", "Windows", "Start Menu", "Programs"),
+ }
+ baseDirs.fonts = []string{
+ filepath.Join(winDir, "Fonts"),
+ filepath.Join(localAppDataDir, "Microsoft", "Windows", "Fonts"),
+ }
+}
+
+func initUserDirs(home string) {
+ publicDir := os.Getenv("PUBLIC")
+ if publicDir == "" {
+ publicDir = filepath.Join(home, "Public")
+ }
+
+ UserDirs.Desktop = xdgPath(envDesktopDir, filepath.Join(home, "Desktop"))
+ UserDirs.Download = xdgPath(envDownloadDir, filepath.Join(home, "Downloads"))
+ UserDirs.Documents = xdgPath(envDocumentsDir, filepath.Join(home, "Documents"))
+ UserDirs.Music = xdgPath(envMusicDir, filepath.Join(home, "Music"))
+ UserDirs.Pictures = xdgPath(envPicturesDir, filepath.Join(home, "Pictures"))
+ UserDirs.Videos = xdgPath(envVideosDir, filepath.Join(home, "Videos"))
+ UserDirs.Templates = xdgPath(envTemplatesDir, filepath.Join(home, "Templates"))
+ UserDirs.PublicShare = xdgPath(envPublicShareDir, publicDir)
+}
diff --git a/vendor/github.com/adrg/xdg/user_dirs.go b/vendor/github.com/adrg/xdg/user_dirs.go
new file mode 100644
index 0000000..dbfd268
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/user_dirs.go
@@ -0,0 +1,40 @@
+package xdg
+
+// XDG user directories environment variables.
+var (
+ envDesktopDir = "XDG_DESKTOP_DIR"
+ envDownloadDir = "XDG_DOWNLOAD_DIR"
+ envDocumentsDir = "XDG_DOCUMENTS_DIR"
+ envMusicDir = "XDG_MUSIC_DIR"
+ envPicturesDir = "XDG_PICTURES_DIR"
+ envVideosDir = "XDG_VIDEOS_DIR"
+ envTemplatesDir = "XDG_TEMPLATES_DIR"
+ envPublicShareDir = "XDG_PUBLICSHARE_DIR"
+)
+
+// UserDirectories defines the locations of well known user directories.
+type UserDirectories struct {
+ // Desktop defines the location of the user's desktop directory.
+ Desktop string
+
+ // Download defines a suitable location for user downloaded files.
+ Download string
+
+ // Documents defines a suitable location for user document files.
+ Documents string
+
+ // Music defines a suitable location for user audio files.
+ Music string
+
+ // Pictures defines a suitable location for user image files.
+ Pictures string
+
+ // VideosDir defines a suitable location for user video files.
+ Videos string
+
+ // Templates defines a suitable location for user template files.
+ Templates string
+
+ // PublicShare defines a suitable location for user shared files.
+ PublicShare string
+}
diff --git a/vendor/github.com/adrg/xdg/utils.go b/vendor/github.com/adrg/xdg/utils.go
new file mode 100644
index 0000000..8d5b196
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/utils.go
@@ -0,0 +1,126 @@
+package xdg
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+func homeDir() string {
+ homeEnv := "HOME"
+ switch runtime.GOOS {
+ case "windows":
+ homeEnv = "USERPROFILE"
+ case "plan9":
+ homeEnv = "home"
+ }
+
+ if home := os.Getenv(homeEnv); home != "" {
+ return home
+ }
+
+ switch runtime.GOOS {
+ case "nacl":
+ return "/"
+ case "darwin":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ return "/"
+ }
+ }
+
+ return ""
+}
+
+func exists(path string) bool {
+ _, err := os.Stat(path)
+ return err == nil || os.IsExist(err)
+}
+
+func expandPath(path, homeDir string) string {
+ if path == "" || homeDir == "" {
+ return path
+ }
+ if path[0] == '~' {
+ return filepath.Join(homeDir, path[1:])
+ }
+ if strings.HasPrefix(path, "$HOME") {
+ return filepath.Join(homeDir, path[5:])
+ }
+
+ return path
+}
+
+func createPath(name string, paths []string) (string, error) {
+ var searchedPaths []string
+ for _, p := range paths {
+ path := filepath.Join(p, name)
+ dir := filepath.Dir(path)
+
+ if exists(dir) {
+ return path, nil
+ }
+ if err := os.MkdirAll(dir, os.ModeDir|0700); err == nil {
+ return path, nil
+ }
+
+ searchedPaths = append(searchedPaths, dir)
+ }
+
+ return "", fmt.Errorf("could not create any of the following paths: %s",
+ strings.Join(searchedPaths, ", "))
+}
+
+func searchFile(name string, paths []string) (string, error) {
+ var searchedPaths []string
+ for _, p := range paths {
+ path := filepath.Join(p, name)
+ if exists(path) {
+ return path, nil
+ }
+
+ searchedPaths = append(searchedPaths, filepath.Dir(path))
+ }
+
+ return "", fmt.Errorf("could not locate `%s` in any of the following paths: %s",
+ filepath.Base(name), strings.Join(searchedPaths, ", "))
+}
+
+func xdgPath(name, defaultPath string) string {
+ dir := expandPath(os.Getenv(name), Home)
+ if dir != "" && filepath.IsAbs(dir) {
+ return dir
+ }
+
+ return defaultPath
+}
+
+func xdgPaths(name string, defaultPaths ...string) []string {
+ dirs := uniquePaths(filepath.SplitList(os.Getenv(name)))
+ if len(dirs) != 0 {
+ return dirs
+ }
+
+ return uniquePaths(defaultPaths)
+}
+
+func uniquePaths(paths []string) []string {
+ var uniq []string
+ registry := map[string]struct{}{}
+
+ for _, p := range paths {
+ dir := expandPath(p, Home)
+ if dir == "" || !filepath.IsAbs(dir) {
+ continue
+ }
+ if _, ok := registry[dir]; ok {
+ continue
+ }
+
+ registry[dir] = struct{}{}
+ uniq = append(uniq, dir)
+ }
+
+ return uniq
+}
diff --git a/vendor/github.com/adrg/xdg/xdg.go b/vendor/github.com/adrg/xdg/xdg.go
new file mode 100644
index 0000000..826c0f8
--- /dev/null
+++ b/vendor/github.com/adrg/xdg/xdg.go
@@ -0,0 +1,180 @@
+/*
+Package xdg provides an implementation of the XDG Base Directory
+Specification. The specification defines a set of standard paths for storing
+application files including data and configuration files. For portability and
+flexibility reasons, applications should use the XDG defined locations instead
+of hardcoding paths. The package also includes the locations of well known user
+directories. The current implementation supports Windows, Mac OS and most
+flavors of Unix.
+
+ For more information regarding the XDG Base Directory Specification see:
+ https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+ For more information regarding the XDG user directories see:
+ https://wiki.archlinux.org/index.php/XDG_user_directories
+*/
+package xdg
+
+var (
+ // Home contains the path of the user's home directory.
+ Home string
+
+ // DataHome defines the base directory relative to which user-specific
+ // data files should be stored. This directory is defined by the
+ // environment variable $XDG_DATA_HOME. If this variable is not set,
+ // a default equal to $HOME/.local/share should be used.
+ DataHome string
+
+ // DataDirs defines the preference-ordered set of base directories to
+ // search for data files in addition to the DataHome base directory.
+ // This set of directories is defined by the environment variable
+ // $XDG_DATA_DIRS. If this variable is not set, the default directories
+ // to be used are /usr/local/share and /usr/share, in that order. The
+ // DataHome directory is considered more important than any of the
+ // directories defined by DataDirs. Therefore, user data files should be
+ // written relative to the DataHome directory, if possible.
+ DataDirs []string
+
+ // ConfigHome defines the base directory relative to which user-specific
+ // configuration files should be written. This directory is defined by
+ // the environment variable $XDG_CONFIG_HOME. If this variable is not
+ // not set, a default equal to $HOME/.config should be used.
+ ConfigHome string
+
+ // ConfigDirs defines the preference-ordered set of base directories to
+ // search for configuration files in addition to the ConfigHome base
+ // directory. This set of directories is defined by the environment
+ // variable $XDG_CONFIG_DIRS. If this variable is not set, a default
+ // equal to /etc/xdg should be used. The ConfigHome directory is
+ // considered more important than any of the directories defined by
+ // ConfigDirs. Therefore, user config files should be written
+ // relative to the ConfigHome directory, if possible.
+ ConfigDirs []string
+
+ // CacheHome defines the base directory relative to which user-specific
+ // non-essential (cached) data should be written. This directory is
+ // defined by the environment variable $XDG_CACHE_HOME. If this variable
+ // is not set, a default equal to $HOME/.cache should be used.
+ CacheHome string
+
+ // RuntimeDir defines the base directory relative to which user-specific
+ // non-essential runtime files and other file objects (such as sockets,
+ // named pipes, etc.) should be stored. This directory is defined by the
+ // environment variable $XDG_RUNTIME_DIR. If this variable is not set,
+ // applications should fall back to a replacement directory with similar
+ // capabilities. Applications should use this directory for communication
+ // and synchronization purposes and should not place larger files in it,
+ // since it might reside in runtime memory and cannot necessarily be
+ // swapped out to disk.
+ RuntimeDir string
+
+ // UserDirs defines the locations of well known user directories.
+ UserDirs UserDirectories
+
+ // FontDirs defines the common locations where font files are stored.
+ FontDirs []string
+
+ // ApplicationDirs defines the common locations of applications.
+ ApplicationDirs []string
+
+ // baseDirs defines the locations of base directories.
+ baseDirs baseDirectories
+)
+
+// Reload refreshes base and user directories by reading the environment.
+// Defaults are applied for XDG variables which are empty or not present
+// in the environment.
+func Reload() {
+ // Initialize home directory.
+ Home = homeDir()
+
+ // Initialize base directories.
+ initBaseDirs(Home)
+ DataHome = baseDirs.dataHome
+ DataDirs = baseDirs.data
+ ConfigHome = baseDirs.configHome
+ ConfigDirs = baseDirs.config
+ CacheHome = baseDirs.cacheHome
+ RuntimeDir = baseDirs.runtime
+ FontDirs = baseDirs.fonts
+ ApplicationDirs = baseDirs.applications
+
+ // Initialize user directories.
+ initUserDirs(Home)
+}
+
+// DataFile returns a suitable location for the specified data file.
+// The relPath parameter must contain the name of the data file, and
+// optionally, a set of parent directories (e.g. appname/app.data).
+// If the specified directories do not exist, they will be created relative
+// to the base data directory. On failure, an error containing the
+// attempted paths is returned.
+func DataFile(relPath string) (string, error) {
+ return baseDirs.dataFile(relPath)
+}
+
+// ConfigFile returns a suitable location for the specified config file.
+// The relPath parameter must contain the name of the config file, and
+// optionally, a set of parent directories (e.g. appname/app.yaml).
+// If the specified directories do not exist, they will be created relative
+// to the base config directory. On failure, an error containing the
+// attempted paths is returned.
+func ConfigFile(relPath string) (string, error) {
+ return baseDirs.configFile(relPath)
+}
+
+// CacheFile returns a suitable location for the specified cache file.
+// The relPath parameter must contain the name of the cache file, and
+// optionally, a set of parent directories (e.g. appname/app.cache).
+// If the specified directories do not exist, they will be created relative
+// to the base cache directory. On failure, an error containing the
+// attempted paths is returned.
+func CacheFile(relPath string) (string, error) {
+ return baseDirs.cacheFile(relPath)
+}
+
+// RuntimeFile returns a suitable location for the specified runtime file.
+// The relPath parameter must contain the name of the runtime file, and
+// optionally, a set of parent directories (e.g. appname/app.pid).
+// If the specified directories do not exist, they will be created relative
+// to the base runtime directory. On failure, an error containing the
+// attempted paths is returned.
+func RuntimeFile(relPath string) (string, error) {
+ return baseDirs.runtimeFile(relPath)
+}
+
+// SearchDataFile searches for specified file in the data search paths.
+// The relPath parameter must contain the name of the data file, and
+// optionally, a set of parent directories (e.g. appname/app.data). If the
+// file cannot be found, an error specifying the searched paths is returned.
+func SearchDataFile(relPath string) (string, error) {
+ return baseDirs.searchDataFile(relPath)
+}
+
+// SearchConfigFile searches for the specified file in config search paths.
+// The relPath parameter must contain the name of the config file, and
+// optionally, a set of parent directories (e.g. appname/app.yaml). If the
+// file cannot be found, an error specifying the searched paths is returned.
+func SearchConfigFile(relPath string) (string, error) {
+ return baseDirs.searchConfigFile(relPath)
+}
+
+// SearchCacheFile searches for the specified file in the cache search path.
+// The relPath parameter must contain the name of the cache file, and
+// optionally, a set of parent directories (e.g. appname/app.cache). If the
+// file cannot be found, an error specifying the searched path is returned.
+func SearchCacheFile(relPath string) (string, error) {
+ return baseDirs.searchCacheFile(relPath)
+}
+
+// SearchRuntimeFile searches for the specified file in the runtime search path.
+// The relPath parameter must contain the name of the runtime file, and
+// optionally, a set of parent directories (e.g. appname/app.pid). If the
+// file cannot be found, an error specifying the searched path is returned.
+func SearchRuntimeFile(relPath string) (string, error) {
+ return baseDirs.searchRuntimeFile(relPath)
+}
+
+func init() {
+ Reload()
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 584189c..3465970 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -7,6 +7,8 @@ code.gitea.io/sdk/gitea
github.com/AlecAivazis/survey/v2
github.com/AlecAivazis/survey/v2/core
github.com/AlecAivazis/survey/v2/terminal
+# github.com/adrg/xdg v0.2.1
+github.com/adrg/xdg
# github.com/alecthomas/chroma v0.7.3
github.com/alecthomas/chroma
github.com/alecthomas/chroma/formatters