Skip to content

Commit

Permalink
allow script to have shebang
Browse files Browse the repository at this point in the history
  • Loading branch information
umputun committed Jun 5, 2023
1 parent 5d19692 commit b03b28f
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,18 @@ echo "All done! $FOO $BAR"

By using this approach, Spot enables users to write and execute more complex scripts, providing greater flexibility and power in managing remote hosts or local environments.

User can also set any custom shebang for the script by adding `#!` at the beginning of the script. For example:

```yaml
commands:
- name: multi_line_script
script: |
#!/bin/bash
touch /tmp/file1
echo "Hello World" > /tmp/file2
```

### Passing variables from one script command to another

Spot allows to pass variables from one command to another. This feature is especially useful when a command, often a script, sets a variable, and the subsequent command requires this variable. For instance, if one command creates a file and the file name is needed in another command. To pass these variables, user must use the conventional shell's export directive in the initial script command. Subsequently, all variables exported in this initial command will be accessible in the following commands.
Expand Down
31 changes: 29 additions & 2 deletions pkg/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ func (cmd *Cmd) scriptCommand(inp string) string {
func (cmd *Cmd) scriptFile(inp string) (r io.Reader) {
var buf bytes.Buffer

buf.WriteString("#!/bin/sh\n") // add hashbang
buf.WriteString("set -e\n") // add 'set -e' to make the script exit on error
if !cmd.hasShebang(inp) {
buf.WriteString("#!/bin/sh\n") // add default shebang if not present
buf.WriteString("set -e\n") // add 'set -e' to make the script exit on error
}

envs := cmd.genEnv()
envs = append(envs, cmd.getSecrets()...)
Expand All @@ -186,10 +188,21 @@ func (cmd *Cmd) scriptFile(inp string) (r io.Reader) {
if len(c) < 2 {
continue
}

if strings.HasPrefix(c, "#!") {
// if the line in the script is a shebang write it right away and add 'set -e' to make the script exit on error
buf.WriteString(c)
buf.WriteString("\n")
buf.WriteString("set -e\n")
continue
}

if strings.HasPrefix(c, "#") {
// skip comments
continue
}
if i := strings.Index(c, "#"); i > 0 {
// remove comments from the line
c = strings.TrimSpace(c[:i])
}
buf.WriteString(c)
Expand Down Expand Up @@ -222,6 +235,20 @@ func (cmd *Cmd) scriptFile(inp string) (r io.Reader) {
return &buf
}

func (cmd *Cmd) hasShebang(inp string) bool {
elems := strings.Split(inp, "\n")
for _, el := range elems {
c := strings.TrimSpace(el)
if len(c) < 2 {
continue
}
if strings.HasPrefix(c, "#!") {
return true
}
}
return false
}

// genEnv returns a sorted list of environment variables from the Environment map (part of the command)
func (cmd *Cmd) genEnv() []string {
envs := make([]string, 0, len(cmd.Environment))
Expand Down
28 changes: 28 additions & 0 deletions pkg/config/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,13 @@ func TestCmd_getScriptFile(t *testing.T) {
},
expected: "#!/bin/sh\nset -e\necho 'Hello, World!'\n",
},
{
name: "with custom shebang",
cmd: &Cmd{
Script: "#!/bin/bash\necho 'Hello, World!'",
},
expected: "#!/bin/bash\nset -e\necho 'Hello, World!'\n",
},
{
name: "with one environment variable",
cmd: &Cmd{
Expand Down Expand Up @@ -576,3 +583,24 @@ echo 'Goodbye, World!'
})
}
}

func TestHasShebang(t *testing.T) {
testCases := []struct {
name string
inp string
exp bool
}{
{"empty string", "", false},
{"no newline", "test data", false},
{"newline, no shebang", "test\ndata", false},
{"newline, shebang not at start", "test\n# data", false},
{"newline, shebang at start", "#!test\ndata", true},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cmd := &Cmd{} // Assuming Cmd is your type with hasShebang method
require.Equal(t, tc.exp, cmd.hasShebang(tc.inp))
})
}
}

0 comments on commit b03b28f

Please sign in to comment.