configdir

package
v0.6.8-ci.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2023 License: BSD-3-Clause, MIT Imports: 3 Imported by: 0

README

ConfigDir for Go

This library provides a cross platform means of detecting the system's configuration directories so that your Go app can store config files in a standard location. For Linux and other Unixes (BSD, etc.) this means using the Freedesktop.org XDG Base Directory Specification (0.8), and for Windows and macOS it uses their standard directories.

This is a simple no-nonsense module that just gives you the path names to do with as you please. You can either get the bare root config path, or get a path with any number of names suffixed onto it for vendor- or application-specific namespacing.

For the impatient, the directories this library can return tend to be like the following:

System-wide Configuration
Windows %PROGRAMDATA% or C:\ProgramData
Linux $XDG_CONFIG_DIRS or /etc/xdg
macOS /Library/Application Support
User-level Configuration
Windows %APPDATA% or C:\Users\%USER%\AppData\Roaming
Linux $XDG_CONFIG_HOME or $HOME/.config
macOS $HOME/Library/Application Support
User-level Cache Folder
Windows %LOCALAPPDATA% or C:\Users\%USER%\AppData\Local
Linux $XDG_CACHE_HOME or $HOME/.cache
macOS $HOME/Library/Caches

Quick Start

// A common use case is to get a private config folder for your app to
// place its settings files into, that are specific to the local user.
configPath := configdir.LocalConfig("my-app")
err := configdir.MakePath(configPath) // Ensure it exists.
if err != nil {
    panic(err)
}

// Deal with a JSON configuration file in that folder.
configFile := filepath.Join(configPath, "settings.json")
type AppSettings struct {
    Username string `json:"username"`
    Password string `json:"password"`
}
var settings AppSettings

// Does the file not exist?
if _, err = os.Stat(configFile); os.IsNotExist(err) {
    // Create the new config file.
    settings = AppSettings{"MyUser", "MyPassword"}
    fh, err := os.Create(configFile)
    if err != nil {
        panic(err)
    }
    defer fh.Close()

    encoder := json.NewEncoder(fh)
    encoder.Encode(&settings)
} else {
    // Load the existing file.
    fh, err := os.Open(configFile)
    if err != nil {
        panic(err)
    }
    defer fh.Close()

    decoder := json.NewDecoder(fh)
    decoder.Decode(&settings)
}

Documentation

Package documentation is available at https://godoc.org/github.com/kirsle/configdir

Author

Noah Petherbridge, @kirsle

License

MIT

Documentation

Overview

Package configdir provides a cross platform means of detecting the system's configuration directories.

This makes it easy to program your Go app to store its configuration files in a standard location relevant to the host operating system. For Linux and some other Unixes (like BSD) this means following the Freedesktop.org XDG Base Directory Specification 0.8, and for Windows and macOS it uses their standard directories.

This is a simple no-nonsense module that just gives you the paths, with optional components tacked on the end for vendor- or app-specific namespacing. It also provides a convenience function to call `os.MkdirAll()` on the paths to ensure they exist and are ready for you to read and write files in.

Standard Global Configuration Paths

  • Linux: $XDG_CONFIG_DIRS or "/etc/xdg"
  • Windows: %PROGRAMDATA% or "C:\\ProgramData"
  • macOS: /Library/Application Support

Standard User-Specific Configuration Paths

  • Linux: $XDG_CONFIG_HOME or "$HOME/.config"
  • Windows: %APPDATA% or "C:\\Users\\%USER%\\AppData\\Roaming"
  • macOS: $HOME/Library/Application Support

Standard User-Specific Cache Paths

  • Linux: $XDG_CACHE_HOME or "$HOME/.cache"
  • Windows: %LOCALAPPDATA% or "C:\\Users\\%USER%\\AppData\\Local"
  • macOS: $HOME/Library/Caches
Example

Quick start example for a common use case of this module.

package main

import (
	"encoding/json"
	"os"
	"path/filepath"

	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// A common use case is to get a private config folder for your app to
	// place its settings files into, that are specific to the local user.
	configPath := configdir.LocalConfig("my-app")
	err := configdir.MakePath(configPath) // Ensure it exists.
	if err != nil {
		panic(err)
	}

	// Deal with a JSON configuration file in that folder.
	configFile := filepath.Join(configPath, "settings.json")
	type AppSettings struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	var settings AppSettings

	// Does the file not exist?
	if _, err = os.Stat(configFile); os.IsNotExist(err) {
		// Create the new config file.
		settings = AppSettings{"MyUser", "MyPassword"}
		fh, err := os.Create(configFile)
		if err != nil {
			panic(err)
		}
		defer fh.Close()

		encoder := json.NewEncoder(fh)
		encoder.Encode(&settings)
	} else {
		// Load the existing file.
		fh, err := os.Open(configFile)
		if err != nil {
			panic(err)
		}
		defer fh.Close()

		decoder := json.NewDecoder(fh)
		decoder.Decode(&settings)
	}
}
Output:

Index

Examples

Constants

View Source
const VERSION = "0.1.0"

VERSION is the semantic version number of the configdir library.

Variables

View Source
var DefaultFileMode = os.FileMode(0755)

DefaultFileMode controls the default permissions on any paths created by using MakePath.

Functions

func LocalCache

func LocalCache(folder ...string) string

LocalCache returns the local user cache folder, with optional path components added to the end for vendor/application-specific settings.

Example

Example for getting a user-specific cache folder.

package main

import (
	"fmt"

	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// Get the default root of the local cache folder.
	//
	// On Linux or BSD this might be "$HOME/.cache", or on Windows this might
	// be "C:\\Users\\$USER\\AppData\\Local"
	path := configdir.LocalCache()
	fmt.Printf("Local user cache path: %s\n", path)

	// Or you can get a local cache path with a vendor suffix, like
	// "$HOME/.cache/acme" on Linux.
	vendor := configdir.LocalCache("acme")
	fmt.Printf("Vendor-specific local cache path: %s\n", vendor)

	// Or you can use multiple path suffixes to group caches in a
	// `vendor/application` namespace. You can use as many path
	// components as you like.
	app := configdir.LocalCache("acme", "sprockets")
	fmt.Printf("Vendor/app specific local cache path: %s\n", app)
}
Output:

func LocalConfig

func LocalConfig(folder ...string) string

LocalConfig returns the local user configuration path, with optional path components added to the end for vendor/application-specific settings.

Example

Example for getting a user-specific configuration path.

package main

import (
	"fmt"

	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// Get the default root of the local configuration path.
	//
	// On Linux or BSD this might be "$HOME/.config", or on Windows this might
	// be "C:\\Users\\$USER\\AppData\\Roaming"
	path := configdir.LocalConfig()
	fmt.Printf("Local user config path: %s\n", path)

	// Or you can get a local config path with a vendor suffix, like
	// "$HOME/.config/acme" on Linux.
	vendor := configdir.LocalConfig("acme")
	fmt.Printf("Vendor-specific local config path: %s\n", vendor)

	// Or you can use multiple path suffixes to group configs in a
	// `vendor/application` namespace. You can use as many path
	// components as you like.
	app := configdir.LocalConfig("acme", "sprockets")
	fmt.Printf("Vendor/app specific local config path: %s\n", app)
}
Output:

func MakePath

func MakePath(paths ...string) error

MakePath ensures that the full path you wanted, including vendor or application-specific components, exists. You can give this the output of any of the config path functions (SystemConfig, LocalConfig or LocalCache).

In the event that the path function gives multiple answers, e.g. for SystemConfig, MakePath() will only attempt to create the sub-folders on the *first* path found. If this isn't what you want, you may want to just use the os.MkdirAll() functionality directly.

Example

Example for automatically creating config directories.

package main

import (
	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// The MakePath() function can accept the output of any of the folder
	// getting functions and ensure that their path exists.

	// Create a local user configuration folder under an app prefix.
	// On Linux this may result in `$HOME/.config/my-cool-app` existing as
	// a directory, depending on the value of `$XDG_CONFIG_HOME`.
	err := configdir.MakePath(configdir.LocalConfig("my-cool-app"))
	if err != nil {
		panic(err)
	}

	// Create a cache folder under a namespace.
	err = configdir.MakePath(configdir.LocalCache("acme", "sprockets", "client"))
	if err != nil {
		panic(err)
	}

	// In the case of global system configuration, which may return more than
	// one path (especially on Linux/BSD that uses the XDG Base Directory Spec),
	// it will attempt to create the directories only under the *first* path.
	//
	// For example, if $XDG_CONFIG_DIRS="/etc/xdg:/opt/config" this will try
	// to create the config dir only in "/etc/xdg/acme/sprockets" and not try
	// to create any folders under "/opt/config".
	err = configdir.MakePath(configdir.SystemConfig("acme", "sprockets")...)
	if err != nil {
		panic(err)
	}
}
Output:

func Refresh

func Refresh()

Refresh will rediscover the config paths, checking current environment variables again.

This function is automatically called when the program initializes. If you change the environment variables at run-time, though, you may call the Refresh() function to reevaluate the config paths.

Example

Example for recalculating what the directories should be.

package main

import (
	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// On your program's initialization, this module decides which paths to
	// use for global, local and cache folders, based on environment variables
	// and falling back on defaults.
	//
	// In case the environment variables change throughout the life of your
	// program, for example if you re-assigned $XDG_CONFIG_HOME, you can call
	// the Refresh() function to re-calculate the paths to reflect the new
	// environment.
	configdir.Refresh()
}
Output:

func SystemConfig

func SystemConfig(folder ...string) []string

SystemConfig returns the system-wide configuration paths, with optional path components added to the end for vendor/application-specific settings.

Example

Example for getting a global system configuration path.

package main

import (
	"fmt"

	"github.com/hofstadter-io/hof/lib/yagu/configdir"
)

func main() {
	// Get all of the global system configuration paths.
	//
	// On Linux or BSD this might be []string{"/etc/xdg"} or the split
	// version of $XDG_CONFIG_DIRS.
	//
	// On macOS or Windows this will likely return a slice with only one entry
	// that points to the global config path; see the README.md for details.
	paths := configdir.SystemConfig()
	fmt.Printf("Global system config paths: %v\n", paths)

	// Or you can get a version of the path suffixed with a vendor folder.
	vendor := configdir.SystemConfig("acme")
	fmt.Printf("Vendor-specific config paths: %v\n", vendor)

	// Or you can use multiple path suffixes to group configs in a
	// `vendor/application` namespace. You can use as many path
	// components as you like.
	app := configdir.SystemConfig("acme", "sprockets")
	fmt.Printf("Vendor/app specific config paths: %v\n", app)
}
Output:

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL