Vendor go-xdg
A few other changes
This commit is contained in:
		
							
								
								
									
										88
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								config.go
									
									
									
									
									
								
							| @@ -2,30 +2,24 @@ | ||||
| package userConfig | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"launchpad.net/go-xdg" | ||||
| 	"gogs.bullercodeworks.com/brian/user-config/ext/go-xdg" | ||||
| ) | ||||
|  | ||||
| // Config is a stuct for managing the config | ||||
| type Config struct { | ||||
| 	name          string | ||||
| 	generalConfig *ConfigFile | ||||
| 	// ConfigFiles are files that have key/value pairs | ||||
| 	ConfigFiles []ConfigFile | ||||
| 	// RawFiles are other files (dbs, etc.) | ||||
| 	RawFiles map[string]string | ||||
| 	generalConfig *GeneralConfig | ||||
| } | ||||
|  | ||||
| // NewConfig generates a Config struct | ||||
| func NewConfig(name string) (*Config, error) { | ||||
| 	c := &Config{name: name} | ||||
| 	if err := c.Load(); err != nil { | ||||
| 		return nil, err | ||||
| 		return c, err | ||||
| 	} | ||||
| 	return c, nil | ||||
| } | ||||
| @@ -40,15 +34,14 @@ func (c *Config) Get(k string) string { | ||||
| 	return c.generalConfig.Get(k) | ||||
| } | ||||
|  | ||||
| // GetConfigPath just returns the config path | ||||
| func (c *Config) GetConfigPath() string { | ||||
| 	return c.generalConfig.Path | ||||
| } | ||||
|  | ||||
| // Load loads config files into the config | ||||
| func (c *Config) Load() error { | ||||
| 	var err error | ||||
| 	// Clear the data, we're reloading | ||||
| 	c.ConfigFiles = c.ConfigFiles[:0] | ||||
| 	c.RawFiles = make(map[string]string) | ||||
| 	var conf generalConfig | ||||
| 	c.data = conf | ||||
|  | ||||
| 	if strings.TrimSpace(c.name) == "" { | ||||
| 		return errors.New("Invalid Config Name: " + c.name) | ||||
| 	} | ||||
| @@ -61,10 +54,10 @@ func (c *Config) Load() error { | ||||
| 			return err | ||||
| 		} | ||||
| 		// We always have a <name>.conf file | ||||
| 		cfgPath = cfgPath + "/" + c.name + ".conf" | ||||
| 		//cfgPath = cfgPath + "/" + c.name + ".conf" | ||||
| 	} | ||||
| 	// Load general config | ||||
| 	if c.generalConfig, err = NewConfigFile(c.name, cfgPath, c.data); err != nil { | ||||
| 	if c.generalConfig, err = NewGeneralConfig(c.name, cfgPath); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @@ -73,38 +66,41 @@ func (c *Config) Load() error { | ||||
|  | ||||
| // Save writes the config to file(s) | ||||
| func (c *Config) Save() error { | ||||
| 	var err error | ||||
| 	c.generalConfig.Save() | ||||
|  | ||||
| 	var cfgPath string | ||||
| 	var configLines []string | ||||
| 	//configLines = append(configLines, "server="+client.ServerAddr) | ||||
| 	//configLines = append(configLines, "key="+client.ServerKey) | ||||
| 	cfgPath = os.Getenv("HOME") | ||||
| 	if cfgPath != "" { | ||||
| 		cfgPath = cfgPath + "/.config" | ||||
| 		if err := c.verifyOrCreateDirectory(cfgPath); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		cfgPath = cfgPath + "/" + c.name | ||||
| 	if c.generalConfig == nil { | ||||
| 		return errors.New("Bad setup.") | ||||
| 	} | ||||
| 	if cfgPath != "" { | ||||
| 		file, err := os.Create(cfgPath) | ||||
| 		if err != nil { | ||||
| 			// Couldn't load config even though one was specified | ||||
| 			return err | ||||
| 	return c.generalConfig.Save() | ||||
| 	/* | ||||
| 		var cfgPath string | ||||
| 		var configLines []string | ||||
| 		//configLines = append(configLines, "server="+client.ServerAddr) | ||||
| 		//configLines = append(configLines, "key="+client.ServerKey) | ||||
| 		cfgPath = os.Getenv("HOME") | ||||
| 		if cfgPath != "" { | ||||
| 			cfgPath = cfgPath + "/.config" | ||||
| 			if err := c.verifyOrCreateDirectory(cfgPath); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			cfgPath = cfgPath + "/" + c.name | ||||
| 		} | ||||
| 		defer file.Close() | ||||
| 		if cfgPath != "" { | ||||
| 			file, err := os.Create(cfgPath) | ||||
| 			if err != nil { | ||||
| 				// Couldn't load config even though one was specified | ||||
| 				return err | ||||
| 			} | ||||
| 			defer file.Close() | ||||
|  | ||||
| 		w := bufio.NewWriter(file) | ||||
| 		for _, line := range configLines { | ||||
| 			fmt.Fprintln(w, line) | ||||
| 			w := bufio.NewWriter(file) | ||||
| 			for _, line := range configLines { | ||||
| 				fmt.Fprintln(w, line) | ||||
| 			} | ||||
| 			if err = w.Flush(); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if err = w.Flush(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| 		return nil | ||||
| 	*/ | ||||
| } | ||||
|  | ||||
| // verifyOrCreateDirectory is a helper function for building an | ||||
| @@ -129,4 +125,4 @@ func (c *Config) verifyOrCreateDirectory(path string) error { | ||||
| 	} | ||||
| 	// We were able to open the path and it was a directory | ||||
| 	return nil | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										108
									
								
								config_file.go
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								config_file.go
									
									
									
									
									
								
							| @@ -2,111 +2,81 @@ | ||||
| package userConfig | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/BurntSushi/toml" | ||||
| ) | ||||
|  | ||||
| type generalConfig struct { | ||||
| // GeneralConfig is the basic config structure | ||||
| // All configs make with package userConfig will have this file | ||||
| type GeneralConfig struct { | ||||
| 	Name        string            `toml:"-"` | ||||
| 	Path        string            `toml:"-"` | ||||
| 	ConfigFiles []string          `toml:"additional_config"` | ||||
| 	RawFiles    []string          `toml:"raw_files"` | ||||
| 	Values      map[string]string `toml:"general"` | ||||
| } | ||||
|  | ||||
| // ConfigFile is a file that has key/value pairs in the config | ||||
| type ConfigFile struct { | ||||
| 	Name string | ||||
| 	Path string | ||||
| 	data interface{} | ||||
| } | ||||
| // NewGeneralConfig generates a General Config struct | ||||
| func NewGeneralConfig(name, path string) (*GeneralConfig, error) { | ||||
| 	gf := &GeneralConfig{Name: name, Path: path} | ||||
| 	gf.ConfigFiles = []string{} | ||||
| 	gf.RawFiles = []string{} | ||||
| 	gf.Values = make(map[string]string) | ||||
|  | ||||
| // NewConfigFile generates a Config struct | ||||
| func NewConfigFile(name, path string, dt interface{}) (*ConfigFile, error) { | ||||
| 	cf := &ConfigFile{Name: name, Path: path, data: dt} | ||||
| 	if err := cf.Load(); err != nil { | ||||
| 		return nil, err | ||||
| 	if err := gf.Load(); err != nil { | ||||
| 		return gf, err | ||||
| 	} | ||||
| 	return cf, nil | ||||
| } | ||||
|  | ||||
| // Set sets a key/value pair in cf, if unable to save, revert to old value | ||||
| // (and return the error) | ||||
| func (cf *ConfigFile) Set(k, v string) error { | ||||
| 	oldVal := cf.values[k] | ||||
| 	cf.values[k] = v | ||||
| 	if err := cf.Save(); err != nil { | ||||
| 		cf.values[k] = oldVal | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Get gets a key/value pair from cf | ||||
| func (cf *ConfigFile) Get(k string) string { | ||||
| 	return cf.values[k] | ||||
| 	return gf, nil | ||||
| } | ||||
|  | ||||
| // Load loads config files into the config | ||||
| func (cf *ConfigFile) Load() error { | ||||
| 	if strings.TrimSpace(cf.Name) == "" && strings.TrimSpace(cf.Path) { | ||||
| 		return errors.New("Invalid ConfigFile Name: " + cf.Path + "/" + cf.Name) | ||||
| func (gf *GeneralConfig) Load() error { | ||||
| 	if strings.TrimSpace(gf.Name) == "" || strings.TrimSpace(gf.Path) == "" { | ||||
| 		return errors.New("Invalid ConfigFile Name: " + gf.Path + "/" + gf.Name) | ||||
| 	} | ||||
|  | ||||
| 	// Config files end with .conf | ||||
| 	cfgPath := cf.Path + "/" + cf.Name + ".conf" | ||||
| 	cfgPath := gf.Path + "/" + gf.Name + ".conf" | ||||
| 	tomlData, err := ioutil.ReadFile(cfgPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := toml.Decode(tomlData, &cf.data); err != nil { | ||||
| 	if _, err := toml.Decode(string(tomlData), &gf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Save writes the config to file(s) | ||||
| func (cf *ConfigFile) Save() error { | ||||
| 	if strings.TrimSpace(cf.Name) == "" && strings.TrimSpace(cf.Path) { | ||||
| 		return errors.New("Invalid ConfigFile Name: " + cf.Path + "/" + cf.Name + ".conf") | ||||
| 	} | ||||
|  | ||||
| 	filePath := cf.path + "/" + cf.Name + ".conf" | ||||
| 	var err error | ||||
| func (gf *GeneralConfig) Save() error { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	enc := toml.NewEncoder(buf).Encode(data) | ||||
| 	err = ioutil.WriteFile(filePath, buf, 0644) | ||||
| 	if err != nil { | ||||
| 	cfgPath := gf.Path + "/" + gf.Name + ".conf" | ||||
| 	fmt.Println("Writing Config File: " + cfgPath) | ||||
| 	if err := toml.NewEncoder(buf).Encode(gf); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	fmt.Println("Writing Config File: " + buf.String()) | ||||
| 	return ioutil.WriteFile(cfgPath, buf.Bytes(), 0644) | ||||
| } | ||||
|  | ||||
| 	cfgPath = os.Getenv("HOME") | ||||
| 	if cfgPath != "" { | ||||
| 		cfgPath = cfgPath + "/.config" | ||||
| 		if err := c.verifyOrCreateDirectory(cfgPath); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		cfgPath = cfgPath + "/" + c.name | ||||
| 	} | ||||
| 	if cfgPath != "" { | ||||
| 		file, err := os.Create(cfgPath) | ||||
| 		if err != nil { | ||||
| 			// Couldn't load config even though one was specified | ||||
| 			return err | ||||
| 		} | ||||
| 		defer file.Close() | ||||
|  | ||||
| 		w := bufio.NewWriter(file) | ||||
| 		for _, line := range configLines { | ||||
| 			fmt.Fprintln(w, line) | ||||
| 		} | ||||
| 		if err = w.Flush(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| // Set sets a key/value pair in gf, if unable to save, revert to old value | ||||
| // (and return the error) | ||||
| func (gf *GeneralConfig) Set(k, v string) error { | ||||
| 	oldVal := gf.Values[k] | ||||
| 	gf.Values[k] = v | ||||
| 	if err := gf.Save(); err != nil { | ||||
| 		gf.Values[k] = oldVal | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Get gets a key/value pair from gf | ||||
| func (gf *GeneralConfig) Get(k string) string { | ||||
| 	return gf.Values[k] | ||||
| } | ||||
							
								
								
									
										3
									
								
								ext/go-xdg/.bzr/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								ext/go-xdg/.bzr/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| This is a Bazaar control directory. | ||||
| Do not change any files in this directory. | ||||
| See http://bazaar.canonical.com/ for more information about Bazaar. | ||||
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/branch-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/branch-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Bazaar-NG meta directory, format 1 | ||||
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/branch/branch.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/branch/branch.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| parent_location = http://bazaar.launchpad.net/~chipaca/go-xdg/trunk/ | ||||
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/branch/format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/branch/format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Bazaar Branch Format 7 (needs bzr 1.6) | ||||
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/branch/last-revision
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/branch/last-revision
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 10 john.lenton@canonical.com-20140208094800-gubd5md7cro3mtxa | ||||
							
								
								
									
										0
									
								
								ext/go-xdg/.bzr/branch/tags
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ext/go-xdg/.bzr/branch/tags
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/checkout/conflicts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/checkout/conflicts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| BZR conflict list format 1 | ||||
							
								
								
									
										
											BIN
										
									
								
								ext/go-xdg/.bzr/checkout/dirstate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								ext/go-xdg/.bzr/checkout/dirstate
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/checkout/format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/checkout/format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Bazaar Working Tree Format 6 (bzr 1.14) | ||||
							
								
								
									
										0
									
								
								ext/go-xdg/.bzr/checkout/views
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ext/go-xdg/.bzr/checkout/views
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								ext/go-xdg/.bzr/repository/format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ext/go-xdg/.bzr/repository/format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Bazaar repository format 2a (needs bzr 1.16 or later) | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -0,0 +1,8 @@ | ||||
| B+Tree Graph Index 2 | ||||
| node_ref_lists=0 | ||||
| key_elements=1 | ||||
| len=10 | ||||
| row_lengths=1 | ||||
| x<EFBFBD><EFBFBD><EFBFBD>;<3B><>0<06><>{ | ||||
| .<2E><>e<EFBFBD>E<EFBFBD>3{c<>Gbp 8N<><4E><EFBFBD>tШ<74><D0A8><EFBFBD>/<2F><><EFBFBD><EFBFBD> | ||||
| ޔ?<3F>Xw<58><77><EFBFBD>1v<76>t<EFBFBD>k<EFBFBD>	W[<5B>(p | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								ext/go-xdg/.bzr/repository/pack-names
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								ext/go-xdg/.bzr/repository/pack-names
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										23
									
								
								ext/go-xdg/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								ext/go-xdg/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| Copyright (c) 2014, John R. Lenton. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										39
									
								
								ext/go-xdg/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								ext/go-xdg/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| Go, XDG, go! | ||||
| =========== | ||||
|  | ||||
| This is `go-xdg`, a little library to help you use the `XDG` | ||||
| [base directory spec](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html). | ||||
|  | ||||
| (There are other `XDG` specs, that might get included in time. Patches welcome.) | ||||
|  | ||||
| Sample usage | ||||
| ------------ | ||||
|  | ||||
| Let's say you are writing an app called “frobz”. It has a config file | ||||
| and a sqlite database. You'd do something like this: | ||||
|  | ||||
|     configFileName, err := xdg.Config.Find("frobz/config.txt") | ||||
|     if err == nil { | ||||
|         // a config file exists! load it... | ||||
|     } | ||||
|     dbFileName, err := xdg.Data.Ensure("frobz/frobz.db") | ||||
|     // now the file and all its directories exist; it's up to you to | ||||
|     // determine if it's empty, etc. | ||||
|  | ||||
|  | ||||
| Resources | ||||
| --------- | ||||
|  | ||||
| Both `Find` and `Ensure` take a `resource` to construct the path they return. | ||||
|  | ||||
| A resource is usually an application name (or a well-known shared resource | ||||
| pool name, such as `icons`), followed by a filename. However nothing in the | ||||
| standard nor in this library limits you to that; you may store e.g. your | ||||
| application's configuration in just `$XDG_CONFIG_HOME/application.conf` (in | ||||
| which case the "resource" here would be just `application.conf`), or in a | ||||
| sub-directory of an application-specific directory. | ||||
|  | ||||
| License, etc. | ||||
| ------------ | ||||
|  | ||||
| BSD simplified, © John R. Lenton, blah blah. | ||||
							
								
								
									
										103
									
								
								ext/go-xdg/base_directory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								ext/go-xdg/base_directory.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,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 | ||||
| } | ||||
							
								
								
									
										151
									
								
								ext/go-xdg/base_directory_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								ext/go-xdg/base_directory_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| // (c) 2014 John R. Lenton. See LICENSE. | ||||
|  | ||||
| package xdg | ||||
|  | ||||
| import ( | ||||
| 	. "launchpad.net/gocheck" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestXDGd(t *testing.T) { TestingT(t) } | ||||
|  | ||||
| type xdgdSuite struct { | ||||
| 	home string | ||||
| 	env1 string | ||||
| 	val1 string | ||||
| 	env2 string | ||||
| 	val2 string | ||||
| 	dir  *XDGDir | ||||
| } | ||||
|  | ||||
| var _ = Suite(&xdgdSuite{}) | ||||
|  | ||||
| func (s *xdgdSuite) SetUpTest(c *C) { | ||||
| 	s.home = os.Getenv("HOME") | ||||
| 	s.env1 = "go_xdg_one" | ||||
| 	s.env2 = "go_xdg_two" | ||||
| 	s.val1 = "something" | ||||
| 	s.val2 = "one:two:three" | ||||
| 	s.dir = &XDGDir{s.env1, s.val1, s.env2, s.val2} | ||||
| } | ||||
|  | ||||
| func (s *xdgdSuite) TestHomePrefersEnviron(c *C) { | ||||
| 	err := os.Setenv(s.env1, "algo") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	defer os.Setenv(s.env1, "") | ||||
| 	h := s.dir.Home() | ||||
| 	c.Check(h, Equals, "algo") | ||||
| } | ||||
|  | ||||
| func (s *xdgdSuite) TestHomeUsesDefault(c *C) { | ||||
| 	h := s.dir.Home() | ||||
| 	c.Check(h, Matches, s.home+".*"+s.val1) | ||||
| } | ||||
|  | ||||
| func (s *xdgdSuite) TestDirsPrefersEnviron(c *C) { | ||||
| 	err := os.Setenv(s.env1, "cero") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	defer os.Setenv(s.env1, "") | ||||
| 	err = os.Setenv(s.env2, "uno:dos") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	defer os.Setenv(s.env2, "") | ||||
| 	hs := s.dir.Dirs() | ||||
| 	c.Check(hs, DeepEquals, []string{"cero", "uno", "dos"}) | ||||
| } | ||||
|  | ||||
| func (s *xdgdSuite) TestDirsSkipsEmpty(c *C) { | ||||
| 	err := os.Setenv(s.env2, "::") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	defer os.Setenv(s.env2, "") | ||||
| 	hs := s.dir.Dirs() | ||||
| 	c.Check(hs, HasLen, 1) | ||||
| } | ||||
|  | ||||
| func (s *xdgdSuite) TestDirsUsesDefault(c *C) { | ||||
| 	hs := s.dir.Dirs() | ||||
| 	c.Assert(hs, HasLen, 4) | ||||
| 	c.Check(hs[1:], DeepEquals, strings.Split(s.val2, ":")) | ||||
| 	c.Check(hs[0], Matches, s.home+".*"+s.val1) | ||||
| } | ||||
|  | ||||
| // now repeat all the tests, but without the HOME environ. | ||||
| type xdgdNoHomeSuite struct { | ||||
| 	xdgdSuite | ||||
| } | ||||
|  | ||||
| var _ = Suite(&xdgdNoHomeSuite{}) | ||||
|  | ||||
| func (s *xdgdNoHomeSuite) SetUpTest(c *C) { | ||||
| 	s.xdgdSuite.SetUpTest(c) | ||||
| 	os.Setenv("HOME", "") | ||||
| } | ||||
|  | ||||
| func (s *xdgdNoHomeSuite) TearDownTest(c *C) { | ||||
| 	os.Setenv("HOME", s.home) | ||||
| } | ||||
|  | ||||
| // and for these tests, an entirely fake HOME | ||||
| type xdgdFHSuite struct { | ||||
| 	xdgdSuite | ||||
| 	real_home string | ||||
| } | ||||
|  | ||||
| var _ = Suite(&xdgdFHSuite{}) | ||||
|  | ||||
| func (s *xdgdFHSuite) SetUpTest(c *C) { | ||||
| 	s.real_home = os.Getenv("HOME") | ||||
| 	home := c.MkDir() | ||||
| 	os.Setenv("HOME", home) | ||||
| 	s.xdgdSuite.SetUpTest(c) | ||||
| 	s.val2 = c.MkDir() + ":" + c.MkDir() + ":" + c.MkDir() | ||||
| 	s.dir = &XDGDir{s.env1, s.val1, s.env2, s.val2} | ||||
| } | ||||
|  | ||||
| func (s *xdgdFHSuite) TearDownTest(c *C) { | ||||
| 	os.Setenv("HOME", s.real_home) | ||||
| } | ||||
|  | ||||
| func (s *xdgdFHSuite) TestFind(c *C) { | ||||
| 	vs := strings.Split(s.val2, ":") | ||||
| 	res1 := "stuff" | ||||
| 	exp1 := filepath.Join(s.home, s.val1, res1) | ||||
| 	res2 := "things/that" | ||||
| 	exp2 := filepath.Join(vs[1], res2) | ||||
| 	res3 := "more" | ||||
| 	exp3 := filepath.Join(vs[2], res3) | ||||
| 	for _, d := range []string{exp1, exp2, exp3} { | ||||
| 		err := os.MkdirAll(d, 0700) | ||||
| 		c.Assert(err, IsNil, Commentf(d)) | ||||
| 	} | ||||
| 	for _, it := range []struct { | ||||
| 		res string | ||||
| 		exp string | ||||
| 	}{{res1, exp1}, {res2, exp2}, {res3, exp3}} { | ||||
| 		rv, err := s.dir.Find(it.res) | ||||
| 		c.Assert(err, IsNil) | ||||
| 		c.Check(rv, Equals, it.exp) | ||||
| 	} | ||||
| 	_, err := s.dir.Find("missing") | ||||
| 	c.Check(err, NotNil) | ||||
| } | ||||
|  | ||||
| func (s *xdgdFHSuite) TestEnsureFirst(c *C) { | ||||
| 	// creates it if missing | ||||
| 	rv1, err := s.dir.Ensure("missing/file") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	_, err = os.Stat(rv1) | ||||
| 	c.Check(err, IsNil) | ||||
| 	c.Check(rv1, Matches, s.home+".*"+"missing/file") | ||||
| 	// just gets it if existing | ||||
| 	rv2, err := s.dir.Ensure("missing/file") | ||||
| 	c.Assert(err, IsNil) | ||||
| 	c.Check(rv2, Equals, rv1) | ||||
| } | ||||
|  | ||||
| func (s *xdgdFHSuite) TestEnsureFirstFailures(c *C) { | ||||
| 	_, err := s.dir.Ensure(strings.Repeat("*", 1<<9) + "/" + strings.Repeat("*", 1<<9)) | ||||
| 	c.Assert(err, NotNil) | ||||
| } | ||||
							
								
								
									
										7
									
								
								ext/go-xdg/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ext/go-xdg/doc.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| // (c) 2014 John R. Lenton. See LICENSE. | ||||
|  | ||||
| // xdg implements helpers for you to use the XDG spec in your apps. | ||||
| // | ||||
| // For now, that's just the base directory spec, | ||||
| // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||||
| package xdg | ||||
		Reference in New Issue
	
	Block a user