Skip to content
This repository has been archived by the owner on Dec 8, 2020. It is now read-only.

Commit

Permalink
Update: adding a utility package for managing working directories
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleterry committed Aug 8, 2019
1 parent 4429727 commit 50a74c4
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 23 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ This package provides utilties for creating and managing working directories.
It defaults to the XDG suite of directory standards from [freedesktop.org](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/).

Help can be found by running `go doc -all github.com/puppetlabs/horsehead/workdir`.

The functionality in this package should work on Linux, MacOS and the BSDs.

### TODO

- add a mechanism for root interactions
- add Windows support
48 changes: 35 additions & 13 deletions workdir/workdir.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package workdir

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

const defaultMode = 0755

type cleanup func() error
type CleanupFunc func() error

// WorkDir is a response type that contains the Path to a directory created by this package.
type WorkDir struct {
// Path is the absolute path to the directory requested.
Path string
// Cleanup is a function that will cleanup any directory and files under
// Path.
Cleanup cleanup
Cleanup CleanupFunc
}

type dirType int
Expand Down Expand Up @@ -63,21 +64,13 @@ var dirTypeEnv = map[dirType]dirTypeEnvDefault{
},
}

// New returns a new WorkDir or an error. If p is not empty, then it will attempt
// to create the directory contained with in it. If p is empty, then it will use dirType
// and namespace to determine what directory should be created and passed back to the caller.
// New returns a new WorkDir or an error. An error is returned if p is empty.
// A standard cleanup function is made available so the caller can decide if they want to
// remove the directory created after they are done. Options allow additional control over
// the directory attributes.
func New(p string, dirType dirType, namespace []string, opts Options) (*WorkDir, error) {
func New(p string, opts Options) (*WorkDir, error) {
if p == "" {
def := dirTypeEnv[dirType]

p = filepath.Join(def.defaultLoc, filepath.Join(namespace...))

if os.Getenv(def.envName) != "" {
p = filepath.Join(os.Getenv(def.envName), filepath.Join(namespace...))
}
return nil, errors.New("path cannot be empty")
}

mode := os.FileMode(defaultMode)
Expand All @@ -98,3 +91,32 @@ func New(p string, dirType dirType, namespace []string, opts Options) (*WorkDir,

return wd, nil
}

// Namespace holds the directory parts that will be joined together to form
// a namespaced path segment in the final workdir.
type Namespace struct {
parts []string
}

// New returns a new WorkDir under the context of dt (directory type) and allows for setting
// a namespace. Below is an example of its use:
// wd, _ := NewNamespace([]string{"foo", "bar"}).New(DirTypeConfig, Options{})
// fmt.Println(wd.Path)
//
// Out: /home/kyle/.config/foo/bar
func (n *Namespace) New(dt dirType, opts Options) (*WorkDir, error) {
def := dirTypeEnv[dt]

p := filepath.Join(def.defaultLoc, filepath.Join(n.parts...))

if os.Getenv(def.envName) != "" {
p = filepath.Join(os.Getenv(def.envName), filepath.Join(n.parts...))
}

return New(p, opts)
}

// NewNamespace returns a new Namespace with the provided parts slice set
func NewNamespace(parts []string) *Namespace {
return &Namespace{parts: parts}
}
44 changes: 34 additions & 10 deletions workdir/workdir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,21 @@ import (
"github.com/stretchr/testify/require"
)

func TestNew(t *testing.T) {
func TestNewNamespace(t *testing.T) {
t.Parallel()

testID := uuid.New().String()

var cases = []struct {
description string
setup func()
provided string
dirType dirType
namespace []string
expected string
shouldError bool
}{
{
description: "make sure we can create config dirs",
description: "can create config dirs with XDG var set",
setup: func() {
require.NoError(t, os.Setenv("XDG_CONFIG_HOME", "/tmp/"))
},
Expand All @@ -33,7 +32,7 @@ func TestNew(t *testing.T) {
expected: filepath.Join("/tmp", testID, "horsehead", "config-dir-test"),
},
{
description: "make sure we can create cache dirs",
description: "can create cache dirs with XDG var set",
setup: func() {
require.NoError(t, os.Setenv("XDG_CACHE_HOME", "/tmp/"))
},
Expand All @@ -42,7 +41,7 @@ func TestNew(t *testing.T) {
expected: filepath.Join("/tmp", testID, "horsehead", "cache-dir-test"),
},
{
description: "make sure we can create data dirs",
description: "can create data dirs with XDG var set",
setup: func() {
require.NoError(t, os.Setenv("XDG_DATA_HOME", "/tmp/"))
},
Expand All @@ -51,9 +50,31 @@ func TestNew(t *testing.T) {
expected: filepath.Join("/tmp", testID, "horsehead", "data-dir-test"),
},
{
description: "make sure we can create provided dirs",
provided: filepath.Join("/tmp", testID, "horsehead", "provided-dir-test"),
expected: filepath.Join("/tmp", testID, "horsehead", "provided-dir-test"),
description: "can create config dirs",
setup: func() {
require.NoError(t, os.Setenv("XDG_CONFIG_HOME", ""))
},
dirType: DirTypeConfig,
namespace: []string{testID, "horsehead", "config-dir-test"},
expected: filepath.Join(os.Getenv("HOME"), ".config", testID, "horsehead", "config-dir-test"),
},
{
description: "can create cache dirs",
setup: func() {
require.NoError(t, os.Setenv("XDG_CACHE_HOME", ""))
},
dirType: DirTypeCache,
namespace: []string{testID, "horsehead", "cache-dir-test"},
expected: filepath.Join(os.Getenv("HOME"), ".cache", testID, "horsehead", "cache-dir-test"),
},
{
description: "can create data dirs",
setup: func() {
require.NoError(t, os.Setenv("XDG_DATA_HOME", ""))
},
dirType: DirTypeData,
namespace: []string{testID, "horsehead", "data-dir-test"},
expected: filepath.Join(os.Getenv("HOME"), ".local", "share", testID, "horsehead", "data-dir-test"),
},
}

Expand All @@ -63,7 +84,7 @@ func TestNew(t *testing.T) {
c.setup()
}

wd, err := New(c.provided, c.dirType, c.namespace, Options{})
wd, err := NewNamespace(c.namespace).New(c.dirType, Options{})
if c.shouldError {
require.Error(t, err)

Expand All @@ -74,9 +95,12 @@ func TestNew(t *testing.T) {
require.Equal(t, c.expected, wd.Path)

_, err = os.Stat(c.expected)
require.NoError(t, err)
require.NoError(t, err, "directory should exist")

require.NoError(t, wd.Cleanup())

_, err = os.Stat(c.expected)
require.Error(t, err, "expected directory to be gone")
})
}
}

0 comments on commit 50a74c4

Please sign in to comment.