Skip to content

Commit 52b464a

Browse files
committed
Add the ability to change user on *nix systems
1 parent 769d7ec commit 52b464a

File tree

5 files changed

+55
-21
lines changed

5 files changed

+55
-21
lines changed

command.go

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,24 @@ type Command struct {
4747
//
4848
// Example:
4949
//
50-
// env := map[string]string{"ENV": "VALUE"}
51-
//
50+
// env := map[string]string{"ENV": "VALUE"}
5251
type EnvVars map[string]string
5352

5453
// NewCommand creates a new command
5554
// You can add option with variadic option argument
5655
// Default timeout is set to 30 minutes
5756
//
5857
// Example:
59-
// c := cmd.NewCommand("echo hello", function (c *Command) {
60-
// c.WorkingDir = "/tmp"
61-
// })
62-
// c.Execute()
6358
//
64-
// or you can use existing options functions
59+
// c := cmd.NewCommand("echo hello", function (c *Command) {
60+
// c.WorkingDir = "/tmp"
61+
// })
62+
// c.Execute()
6563
//
66-
// c := cmd.NewCommand("echo hello", cmd.WithStandardStreams)
67-
// c.Execute()
64+
// or you can use existing options functions
6865
//
66+
// c := cmd.NewCommand("echo hello", cmd.WithStandardStreams)
67+
// c.Execute()
6968
func NewCommand(cmd string, options ...func(*Command)) *Command {
7069
c := &Command{
7170
Command: cmd,
@@ -90,12 +89,11 @@ func NewCommand(cmd string, options ...func(*Command)) *Command {
9089
//
9190
// Example:
9291
//
93-
// c := cmd.NewCommand(
94-
// "echo hello",
95-
// cmd.WithCustomBaseCommand(exec.Command("/bin/bash", "-c")),
96-
// )
97-
// c.Execute()
98-
//
92+
// c := cmd.NewCommand(
93+
// "echo hello",
94+
// cmd.WithCustomBaseCommand(exec.Command("/bin/bash", "-c")),
95+
// )
96+
// c.Execute()
9997
func WithCustomBaseCommand(baseCommand *exec.Cmd) func(c *Command) {
10098
return func(c *Command) {
10199
baseCommand.Args = append(baseCommand.Args, c.Command)
@@ -108,9 +106,8 @@ func WithCustomBaseCommand(baseCommand *exec.Cmd) func(c *Command) {
108106
//
109107
// Example:
110108
//
111-
// c := cmd.NewCommand("echo hello", cmd.WithStandardStreams)
112-
// c.Execute()
113-
//
109+
// c := cmd.NewCommand("echo hello", cmd.WithStandardStreams)
110+
// c.Execute()
114111
func WithStandardStreams(c *Command) {
115112
c.StdoutWriter = io.MultiWriter(os.Stdout, &c.stdout, &c.combined)
116113
c.StderrWriter = io.MultiWriter(os.Stderr, &c.stderr, &c.combined)
@@ -135,8 +132,8 @@ func WithCustomStderr(writers ...io.Writer) func(c *Command) {
135132
// WithTimeout sets the timeout of the command
136133
//
137134
// Example:
138-
// cmd.NewCommand("sleep 10;", cmd.WithTimeout(500))
139135
//
136+
// cmd.NewCommand("sleep 10;", cmd.WithTimeout(500))
140137
func WithTimeout(t time.Duration) func(c *Command) {
141138
return func(c *Command) {
142139
c.Timeout = t
@@ -201,13 +198,13 @@ func (c *Command) Combined() string {
201198
return c.combined.String()
202199
}
203200

204-
//ExitCode returns the exit code of the command
201+
// ExitCode returns the exit code of the command
205202
func (c *Command) ExitCode() int {
206203
c.isExecuted("ExitCode")
207204
return c.exitCode
208205
}
209206

210-
//Executed returns if the command was already executed
207+
// Executed returns if the command was already executed
211208
func (c *Command) Executed() bool {
212209
return c.executed
213210
}

command_darwin.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@ package cmd
22

33
import (
44
"os/exec"
5+
"syscall"
56
)
67

78
func createBaseCommand(c *Command) *exec.Cmd {
89
cmd := exec.Command("/bin/sh", "-c", c.Command)
910
return cmd
1011
}
12+
13+
func WithUser(credential syscall.Credential) func(c *Command) {
14+
return func(c *Command) {
15+
c.baseCommand.SysProcAttr = &syscall.SysProcAttr{
16+
Credential: &credential,
17+
}
18+
}
19+
}

command_darwin_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"syscall"
45
"testing"
56
"time"
67

@@ -32,3 +33,13 @@ func TestCommand_WithValidTimeout(t *testing.T) {
3233

3334
assert.Nil(t, err)
3435
}
36+
37+
// I really don't see the point of mocking this
38+
// as the stdlib does so already. So testing here
39+
// seems redundant. This simple check if we're compliant
40+
// with an api changes
41+
func TestCommand_WithUser(t *testing.T) {
42+
cmd := NewCommand("echo hello", WithUser(syscall.Credential{}))
43+
err := cmd.Execute()
44+
assert.Error(t, err)
45+
}

command_linux.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@ package cmd
22

33
import (
44
"os/exec"
5+
"syscall"
56
)
67

78
func createBaseCommand(c *Command) *exec.Cmd {
89
cmd := exec.Command("/bin/sh", "-c", c.Command)
910
return cmd
1011
}
12+
13+
func WithUser(credential syscall.Credential) func(c *Command) {
14+
return func(c *Command) {
15+
c.baseCommand.SysProcAttr = &syscall.SysProcAttr{
16+
Credential: &credential,
17+
}
18+
}
19+
}

command_linux_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"os/exec"
99
"strings"
10+
"syscall"
1011
"testing"
1112
"time"
1213

@@ -171,3 +172,10 @@ func TestCommand_WithCustomBaseCommand(t *testing.T) {
171172
assert.NotEqual(t, "/bin/sh\n", cmd.Stdout())
172173
assert.Equal(t, "/bin/bash\n", cmd.Stdout())
173174
}
175+
176+
func TestCommand_WithUser(t *testing.T) {
177+
cred := syscall.Credential{}
178+
cmd := NewCommand("echo hello", WithUser(cred))
179+
err := cmd.Execute()
180+
assert.Error(t, err)
181+
}

0 commit comments

Comments
 (0)