Skip to content

Commit e4eee1b

Browse files
authored
devbox: add AppendScript method to ConfigShellCmds (#149)
This method takes a script as a string and appends it to the slice of shell commands in the config. From the docs: AppendScript appends each line of a script to s.Cmds. It also applies the following formatting rules: - Trim leading newlines from the script. - Trim trailing whitespace from the script. - If the first line of the script begins with one or more tabs ('\t'), then unindent each line by that same number of tabs. - Remove trailing whitespace from each line. Note that unindenting only happens when a line starts with at least as many tabs as the first line. If it starts with fewer tabs, then it is not unindented at all. See `config_test.go` for an example.
1 parent e8d5078 commit e4eee1b

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

config.go

+28
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/json"
88
"fmt"
99
"strings"
10+
"unicode"
1011

1112
"github.com/pkg/errors"
1213
"go.jetpack.io/devbox/cuecfg"
@@ -93,6 +94,33 @@ type ConfigShellCmds struct {
9394
Cmds []string
9495
}
9596

97+
// AppendScript appends each line of a script to s.Cmds. It also applies the
98+
// following formatting rules:
99+
//
100+
// - Trim leading newlines from the script.
101+
// - Trim trailing whitespace from the script.
102+
// - If the first line of the script begins with one or more tabs ('\t'), then
103+
// unindent each line by that same number of tabs.
104+
// - Remove trailing whitespace from each line.
105+
//
106+
// Note that unindenting only happens when a line starts with at least as many
107+
// tabs as the first line. If it starts with fewer tabs, then it is not
108+
// unindented at all.
109+
func (s *ConfigShellCmds) AppendScript(script string) {
110+
script = strings.TrimLeft(script, "\r\n ")
111+
script = strings.TrimRightFunc(script, unicode.IsSpace)
112+
if len(script) == 0 {
113+
return
114+
}
115+
prefixLen := strings.IndexFunc(script, func(r rune) bool { return r != '\t' })
116+
prefix := strings.Repeat("\t", prefixLen)
117+
for _, line := range strings.Split(script, "\n") {
118+
line = strings.TrimRightFunc(line, unicode.IsSpace)
119+
line = strings.TrimPrefix(line, prefix)
120+
s.Cmds = append(s.Cmds, line)
121+
}
122+
}
123+
96124
// MarshalJSON marshals shell commands according to s.MarshalAs. It marshals
97125
// commands to a string by joining s.Cmds with newlines.
98126
func (s ConfigShellCmds) MarshalJSON() ([]byte, error) {

config_test.go

+104
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package devbox
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"testing"
67

78
"github.com/google/go-cmp/cmp"
@@ -145,3 +146,106 @@ func TestConfigShellCmdsString(t *testing.T) {
145146
})
146147
}
147148
}
149+
150+
func ExampleConfigShellCmds_AppendScript() {
151+
shCmds := ConfigShellCmds{}
152+
shCmds.AppendScript(`
153+
# This script will be unindented by the number of leading tabs
154+
# on the first line.
155+
if true; then
156+
echo "this is always printed"
157+
fi`,
158+
)
159+
b, _ := json.MarshalIndent(&shCmds, "", " ")
160+
fmt.Println(string(b))
161+
162+
// Output:
163+
// [
164+
// "# This script will be unindented by the number of leading tabs",
165+
// "# on the first line.",
166+
// "if true; then",
167+
// "\techo \"this is always printed\"",
168+
// "fi"
169+
// ]
170+
}
171+
172+
func TestAppendScript(t *testing.T) {
173+
tests := []struct {
174+
name string
175+
script string
176+
wantCmds []string
177+
}{
178+
{
179+
name: "Empty",
180+
script: "",
181+
wantCmds: nil,
182+
},
183+
{
184+
name: "OnlySpaces",
185+
script: " ",
186+
wantCmds: nil,
187+
},
188+
{
189+
name: "Only newlines",
190+
script: "\r\n",
191+
wantCmds: nil,
192+
},
193+
{
194+
name: "Simple",
195+
script: "echo test",
196+
wantCmds: []string{"echo test"},
197+
},
198+
{
199+
name: "LeadingNewline",
200+
script: "\necho test",
201+
wantCmds: []string{"echo test"},
202+
},
203+
{
204+
name: "LeadingNewlineAndSpace",
205+
script: "\n echo test",
206+
wantCmds: []string{"echo test"},
207+
},
208+
{
209+
name: "TrailingWhitespace",
210+
script: "echo test \n",
211+
wantCmds: []string{"echo test"},
212+
},
213+
{
214+
name: "SecondLineIndent",
215+
script: "if true; then\n\techo test\nfi",
216+
wantCmds: []string{
217+
"if true; then",
218+
"\techo test",
219+
"fi",
220+
},
221+
},
222+
{
223+
name: "Unindent",
224+
script: "\n\tif true; then\n\t\techo test\n\tfi",
225+
wantCmds: []string{
226+
"if true; then",
227+
"\techo test",
228+
"fi",
229+
},
230+
},
231+
{
232+
name: "UnindentTooFewTabs",
233+
script: "\t\tif true; then\n\techo test\n\t\tfi",
234+
wantCmds: []string{
235+
"if true; then",
236+
"\techo test",
237+
"fi",
238+
},
239+
},
240+
}
241+
for _, test := range tests {
242+
t.Run(test.name, func(t *testing.T) {
243+
shCmds := ConfigShellCmds{}
244+
shCmds.AppendScript(test.script)
245+
gotCmds := shCmds.Cmds
246+
if diff := cmp.Diff(test.wantCmds, gotCmds); diff != "" {
247+
t.Errorf("Got incorrect commands slice (-want +got):\n%s", diff)
248+
}
249+
})
250+
}
251+
}

0 commit comments

Comments
 (0)