Skip to content

Commit bd1e26a

Browse files
committed
Application core.
1 parent 58268b1 commit bd1e26a

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

path_helper.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"path"
6+
"path/filepath"
7+
"strings"
8+
)
9+
10+
// PathHelper represents the application path-helper. Takes a configuration as input, and uses local
11+
// attributes to keep list of files and directories to compose PATH.
12+
type PathHelper struct {
13+
config *Config // parsed command-line flags
14+
files []string // slice of files in path.d
15+
directories []string // directories that will compose PATH
16+
}
17+
18+
// logger for path-helper instance, skip printing when verbose is off.
19+
func (p *PathHelper) logger(format string, v ...interface{}) {
20+
if p.config.Verbose {
21+
fmt.Printf(fmt.Sprintf("# %s\n", format), v...)
22+
}
23+
}
24+
25+
// append a direcotry in global list, making sure it skips duplicates when setting is enabled.
26+
func (p *PathHelper) append(directory string) {
27+
if p.config.SkipDuplicates {
28+
for _, d := range p.directories {
29+
if d == directory {
30+
p.logger("[WARN] Skipping entry '%s', is already defined.", directory)
31+
return
32+
}
33+
}
34+
}
35+
p.directories = append(p.directories, directory)
36+
}
37+
38+
// globPathFiles load list of files in base directory. Returns errors when base directory does not
39+
// exist or when having issues to execute globing.
40+
func (p *PathHelper) globPathFiles() error {
41+
baseDir := p.config.BaseDir
42+
p.logger("Inspecting paths directory: '%s'", baseDir)
43+
if !dirExists(baseDir) {
44+
return fmt.Errorf("can't find base directory at '%s'", baseDir)
45+
}
46+
47+
var err error
48+
pattern := path.Join(baseDir, "*")
49+
p.files, err = filepath.Glob(pattern)
50+
return err
51+
}
52+
53+
// gatherPathDirs based in path files, read and inspect direcotories listed in those. Can return
54+
// errors related to reading files.
55+
func (p *PathHelper) gatherPathDirs() error {
56+
for _, file := range p.files {
57+
p.logger("File '%s'", file)
58+
directories, err := readLines(file)
59+
if err != nil {
60+
return fmt.Errorf("can't read file '%s': '%v'", file, err)
61+
}
62+
63+
for _, directory := range directories {
64+
p.logger("\t- '%s'", directory)
65+
if p.config.SkipNotFound && !dirExists(directory) {
66+
p.logger("[WARN] Directory '%s' (%s) is not found! Skipping.", directory, file)
67+
continue
68+
}
69+
p.append(directory)
70+
}
71+
}
72+
return nil
73+
}
74+
75+
// pathDirsColonJoined return slice of direcotires joined by colon.
76+
func (p *PathHelper) pathDirsColonJoined() string {
77+
return strings.Join(p.directories, ":")
78+
}
79+
80+
// RenderExpression print out the shell expression exporting PATH. Will forward errors from methods
81+
// listing and reading path files, and inspecting direcotories present found in those files.
82+
func (p *PathHelper) RenderExpression() (string, error) {
83+
if err := p.globPathFiles(); err != nil {
84+
return "", err
85+
}
86+
if err := p.gatherPathDirs(); err != nil {
87+
return "", err
88+
}
89+
90+
return fmt.Sprintf("export PATH=\"%s\"", p.pathDirsColonJoined()), nil
91+
}
92+
93+
// NewPathHelper instantiate a PathHelper type.
94+
func NewPathHelper(config *Config) *PathHelper {
95+
return &PathHelper{
96+
config: config,
97+
files: []string{},
98+
directories: []string{},
99+
}
100+
}

path_helper_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestPathHelper(t *testing.T) {
11+
config := &Config{Verbose: true, BaseDir: "./test/paths.d"}
12+
expectedJoinedPaths := "/a/a/a:/b/b/b:/c/c/c:/d/d/d"
13+
14+
t.Run("without-duplicates", func(t *testing.T) {
15+
t.Run("inspecting-directories-and-files", func(t *testing.T) {
16+
inspectPathFilesAndDirectories(t, config, 1, expectedJoinedPaths)
17+
})
18+
19+
t.Run("RenderExpression", func(t *testing.T) {
20+
inspectRenderedExpression(t, config, expectedJoinedPaths)
21+
})
22+
})
23+
24+
t.Run("with-duplicates", func(t *testing.T) {
25+
config.SkipDuplicates = true
26+
27+
t.Run("inspecting-directories-and-files", func(t *testing.T) {
28+
inspectPathFilesAndDirectories(t, config, 1, expectedJoinedPaths)
29+
})
30+
31+
t.Run("RenderExpression", func(t *testing.T) {
32+
inspectRenderedExpression(t, config, expectedJoinedPaths)
33+
})
34+
})
35+
36+
t.Run("with-skip-not-found", func(t *testing.T) {
37+
config.SkipDuplicates = true
38+
config.SkipNotFound = true
39+
40+
t.Run("inspecting-directories-and-files", func(t *testing.T) {
41+
inspectPathFilesAndDirectories(t, config, 0, "")
42+
})
43+
44+
t.Run("RenderExpression", func(t *testing.T) {
45+
inspectRenderedExpression(t, config, "")
46+
})
47+
})
48+
}
49+
50+
func inspectPathFilesAndDirectories(
51+
t *testing.T,
52+
config *Config,
53+
expectedLen int,
54+
expectedJoinedPaths string,
55+
) {
56+
p := NewPathHelper(config)
57+
err := p.globPathFiles()
58+
t.Logf("Error: '%#v", err)
59+
assert.NoError(t, err)
60+
t.Logf("Files: '%#v'", p.files)
61+
assert.True(t, len(p.files) >= expectedLen)
62+
63+
err = p.gatherPathDirs()
64+
t.Logf("Error: '%#v", err)
65+
assert.NoError(t, err)
66+
t.Logf("Directories: '%#v'", p.directories)
67+
assert.True(t, len(p.directories) >= expectedLen)
68+
69+
assert.Equal(t, expectedJoinedPaths, p.pathDirsColonJoined())
70+
}
71+
72+
func inspectRenderedExpression(t *testing.T, config *Config, expectedJoinedPaths string) {
73+
p := NewPathHelper(config)
74+
s, err := p.RenderExpression()
75+
assert.NoError(t, err)
76+
t.Logf("Expression: '%s'", s)
77+
assert.NotEmpty(t, s)
78+
assert.Equal(t, fmt.Sprintf("export PATH=\"%s\"", expectedJoinedPaths), s)
79+
}

0 commit comments

Comments
 (0)