Skip to content

Commit 134a6e7

Browse files
committed
walking the source commands
1 parent 13e8deb commit 134a6e7

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

common/script_parser.go

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import (
77
)
88

99
func ForEachVariableAssignment(key, input string, fn func(string)) {
10-
// parse
11-
r := strings.NewReader(input)
12-
f, err := syntax.NewParser().Parse(r, "")
10+
f, err := parseScript(input)
1311
if err != nil {
1412
return
1513
}
@@ -25,3 +23,42 @@ func ForEachVariableAssignment(key, input string, fn func(string)) {
2523
return true
2624
})
2725
}
26+
27+
var isSourceCommand = map[string]bool{
28+
".": true,
29+
"source": true,
30+
// eval?
31+
}
32+
33+
func ForEachSourcedScript(input string, fn func(string)) {
34+
f, err := parseScript(input)
35+
if err != nil {
36+
return
37+
}
38+
39+
syntax.Walk(f, func(node syntax.Node) bool {
40+
switch x := node.(type) {
41+
case *syntax.CallExpr:
42+
if len(x.Args) == 2 {
43+
cmd := input[x.Args[0].Pos().Offset():x.Args[0].End().Offset()]
44+
cmd = strings.TrimLeft(cmd, "\\")
45+
46+
arg := input[x.Args[1].Pos().Offset():x.Args[1].End().Offset()]
47+
arg = strings.Trim(arg, "\"'`")
48+
49+
if !isSourceCommand[cmd] {
50+
return true
51+
}
52+
53+
fn(arg)
54+
}
55+
}
56+
return true
57+
})
58+
}
59+
60+
func parseScript(input string) (*syntax.File, error) {
61+
r := strings.NewReader(input)
62+
f, err := syntax.NewParser().Parse(r, "")
63+
return f, err
64+
}

common/script_parser_test.go

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ import (
88

99
func Test_parsing_scrip_assignments(t *testing.T) {
1010
input := `
11-
if [[ true ]]; then
12-
export PATH="/path1:$PATH"
13-
else
14-
export PATH="${PATH}:/path2"
15-
fi
16-
PATH=$PATH:/path3
17-
path=$path:/path4
18-
TEST=$PATH:/path5
19-
`
11+
if [[ true ]]; then
12+
export PATH="/path1:$PATH"
13+
else
14+
export PATH="${PATH}:/path2"
15+
fi
16+
PATH=$PATH:/path3
17+
path=$path:/path4
18+
TEST=$PATH:/path5
19+
`
20+
2021
var seenValues string
2122
ForEachVariableAssignment("PATH", input, func(s string) {
2223
seenValues += s
@@ -27,3 +28,24 @@ TEST=$PATH:/path5
2728
assert.NotContains(t, seenValues, "/path4")
2829
assert.NotContains(t, seenValues, "/path5")
2930
}
31+
32+
func Test_recursively_walking_sourced_scripts(t *testing.T) {
33+
input := `
34+
[ -s "/test1.sh" ] && \. "/test1.sh"
35+
[ -f /test2 ] && source /test2
36+
if [ "${BASH-no}" != "no" ]; then
37+
[ -r ~/.test3 ] && . '~/.test3'
38+
fi
39+
./test4
40+
`
41+
42+
seenScripts := []string{}
43+
ForEachSourcedScript(input, func(s string) {
44+
seenScripts = append(seenScripts, s)
45+
})
46+
47+
assert.Contains(t, seenScripts, "/test1.sh")
48+
assert.Contains(t, seenScripts, "/test2")
49+
assert.Contains(t, seenScripts, "~/.test3")
50+
assert.NotContains(t, seenScripts, "./test4")
51+
}

0 commit comments

Comments
 (0)