File: base_directory.go

package info (click to toggle)
golang-go-xdg 0~bzr20140219-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, sid
  • size: 92 kB
  • sloc: makefile: 3
file content (103 lines) | stat: -rw-r--r-- 2,760 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// (c) 2014 John R. Lenton. See LICENSE.

package xdg

import (
	"os"
	"os/user"
	"path/filepath"
)

// An XDGDir holds configuration for and can be used to access the
// XDG-specified base directories relative to which user-specific files of a
// given type should be stored.
//
// Typically you wouldn't use XDGDir directly, but one of the
// predefined ones which implement the spec: Data, Config and Cache.
type XDGDir struct {
	homeEnv  string
	homeDefault string
	dirsEnv  string
	dirsDefault string
}

var (
	Data   *XDGDir // for data files.
	Config *XDGDir // for configuration files.
	Cache  *XDGDir // for non-essential data files.
)

func init() {
	// do this here to make the docs nicer
	Data = &XDGDir{"XDG_DATA_HOME", ".local/share", "XDG_DATA_DIRS", "/usr/local/share:/usr/share"}
	Config = &XDGDir{"XDG_CONFIG_HOME", ".config", "XDG_CONFIG_DIRS", "/etc/xdg"}
	Cache = &XDGDir{"XDG_CACHE_HOME", ".cache", "", ""}
}

// Home gets the path to the given user-specific XDG directory, as specified
// (or not) by the user's environment.
func (x *XDGDir) Home() string {
	dir := os.Getenv(x.homeEnv)
	if dir != "" {
		return dir
	}
	home := os.Getenv("HOME")
	if home == "" {
		user, err := user.Current()
		if err != nil {
			panic("unable to determine $HOME")
		}
		home = user.HomeDir
	}
	return filepath.Join(home, x.homeDefault)
}

// Dirs returns the preference-ordered set of base directories to search for
// files of the given type, starting with the user-specific one, as specified
// (or not) by the user's environment.
func (x *XDGDir) Dirs() []string {
	dirs := []string{x.Home()}
	if x.dirsEnv != "" {
		xtra := os.Getenv(x.dirsEnv)
		if xtra == "" {
			xtra = x.dirsDefault
		}
		for _, path := range filepath.SplitList(xtra) {
			if path != "" {
				dirs = append(dirs, path)
			}
		}
	}
	return dirs
}

// Find attempts to find the path suffix in all of the known XDG directories.
// If not found, an error is returned.
func (x *XDGDir) Find(suffix string) (absPath string, err error) {
	var firstError error = nil
	for _, path := range x.Dirs() {
		name := filepath.Join(path, suffix)
		_, err = os.Stat(name)
		if err == nil {
			return name, nil
		} else if firstError == nil {
			firstError = err
		}
	}
	return "", firstError
}

// Ensure takes the path suffix given, and ensures that a matching file exists
// in the home XDG directory. If it doesn't exist it is created. If it can't
// be created, or exists but is unreadable, an error is returned.
func (x *XDGDir) Ensure(suffix string) (absPath string, err error) {
	absPath = filepath.Join(x.Home(), suffix)
	err = os.MkdirAll(filepath.Dir(absPath), 0700)
	if err == nil {
		f, err := os.OpenFile(absPath, os.O_CREATE, 0600)
		if err == nil {
			f.Close()
		}
	}
	return
}