pax_global_header00006660000000000000000000000064123012017510014502gustar00rootroot0000000000000052 comment=3e2ebaa304495558d3e2559c4796e3893faf61f3 golang-go-xdg-0~bzr20140219/000077500000000000000000000000001230120175100153745ustar00rootroot00000000000000golang-go-xdg-0~bzr20140219/LICENSE000066400000000000000000000024271230120175100164060ustar00rootroot00000000000000Copyright (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. golang-go-xdg-0~bzr20140219/README.md000066400000000000000000000024471230120175100166620ustar00rootroot00000000000000Go, 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. golang-go-xdg-0~bzr20140219/base_directory.go000066400000000000000000000053101230120175100207200ustar00rootroot00000000000000// (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 } golang-go-xdg-0~bzr20140219/base_directory_test.go000066400000000000000000000065241230120175100217670ustar00rootroot00000000000000// (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) } golang-go-xdg-0~bzr20140219/doc.go000066400000000000000000000003701230120175100164700ustar00rootroot00000000000000// (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