forked from konflux-ci/build-definitions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshell.go
136 lines (114 loc) · 3.25 KB
/
shell.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package main
import (
"regexp"
"slices"
"sort"
"strings"
"mvdan.cc/sh/v3/fileutil"
"mvdan.cc/sh/v3/syntax"
)
var (
parser = syntax.NewParser(syntax.KeepComments(true))
printer = syntax.NewPrinter(syntax.Indent(2))
)
func removeEnvUse(f *syntax.File, name string) []*syntax.Stmt {
modified := make([]*syntax.Stmt, 0, len(f.Stmts))
syntax.Walk(f, func(node syntax.Node) bool {
if p, ok := node.(*syntax.ParamExp); ok {
// parameter expansion, e.g. ${name}
if p.Param.Value == name {
// remove every line starting from the line where the ${name} was used
start := p.Param.Pos().Line()
var end uint = 0
for _, s := range f.Stmts {
line := s.Pos().Line()
if line == start {
if ifstmt, ok := s.Cmd.(*syntax.IfClause); ok {
// if the if statement is at the start line, remove
// the lines till the corresponding `fi` statement
end = ifstmt.FiPos.Line()
}
if assign, ok := s.Cmd.(*syntax.CallExpr); ok {
// remove the whole assignment
end = assign.End().Line()
}
}
if line < start || (line > end || end == 0) {
// add only the lines that are not in the start-end segment
modified = append(modified, s)
}
}
}
}
return true
})
if len(modified) == 0 {
// if the environment variable is not found, the modified slice will be empty
return f.Stmts
}
return modified
}
func removeUnusedFunctions(f *syntax.File) []*syntax.Stmt {
used := make([]string, 0, 10) // includes used functions and other calls (echo, printf...)
syntax.Walk(f, func(node syntax.Node) bool {
if c, ok := node.(*syntax.CallExpr); ok && len(c.Args) > 0 {
// first argument of a call statement is the name
used = append(used, c.Args[0].Lit())
}
return true
})
sort.Strings(used)
forRemoval := make([]struct{ start, end uint }, 0, 10)
syntax.Walk(f, func(node syntax.Node) bool {
if fn, ok := node.(*syntax.FuncDecl); ok {
if _, found := slices.BinarySearch(used, fn.Name.Value); !found {
// we found a function declared and unused
forRemoval = append(forRemoval, struct{ start, end uint }{fn.Pos().Line(), fn.End().Line()})
}
}
return true
})
modified := make([]*syntax.Stmt, 0, len(f.Stmts))
for _, s := range f.Stmts {
line := s.Position.Line()
remove := false
for _, r := range forRemoval {
if remove = line >= r.start && line <= r.end; remove {
// found lines comprising a unused function declaration
break
}
}
if !remove {
modified = append(modified, s)
}
}
return modified
}
func replaceLiterals(f *syntax.File, rx map[*regexp.Regexp]string) []*syntax.Stmt {
syntax.Walk(f, func(n syntax.Node) bool {
if l, ok := n.(*syntax.Lit); ok {
l.Value = applyRegexReplacements(l.Value, rx)
}
if s, ok := n.(*syntax.Stmt); ok {
for i := range s.Comments {
s.Comments[i].Text = applyRegexReplacements(s.Comments[i].Text, rx)
}
}
return true
})
return f.Stmts
}
func isShell(script string) bool {
if script == "" {
return false
}
// fileutil.Shebang returns "" if the shebang is not shell
if shebang := fileutil.Shebang([]byte(script)); shebang != "" {
return true
}
// folk don't add shebangs so missing one defaults to shell
if !strings.HasPrefix(script, "#!") {
return true
}
return false
}