@@ -20,12 +20,18 @@ type Command struct {
20
20
name string
21
21
args []string
22
22
envs []string
23
+ ctx context.Context
23
24
}
24
25
25
26
// CommandOptions contains options for running a command.
27
+ // If timeout is zero, DefaultTimeout will be used.
28
+ // If timeout is less than zero, no timeout will be set.
29
+ // If context is nil, context.Background() will be used.
26
30
type CommandOptions struct {
27
- Args []string
28
- Envs []string
31
+ Args []string
32
+ Envs []string
33
+ Timeout time.Duration
34
+ Context context.Context
29
35
}
30
36
31
37
// String returns the string representation of the command.
@@ -38,9 +44,16 @@ func (c *Command) String() string {
38
44
39
45
// NewCommand creates and returns a new Command with given arguments for "git".
40
46
func NewCommand (args ... string ) * Command {
47
+ return NewCommandWithContext (context .Background (), args ... )
48
+ }
49
+
50
+ // NewCommandWithContext creates and returns a new Command with given arguments
51
+ // and context for "git".
52
+ func NewCommandWithContext (ctx context.Context , args ... string ) * Command {
41
53
return & Command {
42
54
name : "git" ,
43
55
args : args ,
56
+ ctx : ctx ,
44
57
}
45
58
}
46
59
@@ -56,9 +69,17 @@ func (c *Command) AddEnvs(envs ...string) *Command {
56
69
return c
57
70
}
58
71
72
+ // WithContext sets the context for the command.
73
+ func (c * Command ) WithContext (ctx context.Context ) * Command {
74
+ c .ctx = ctx
75
+ return c
76
+ }
77
+
59
78
// AddOptions adds options to the command.
79
+ // Note: only the last option will take effect if there are duplicated options.
60
80
func (c * Command ) AddOptions (opts ... CommandOptions ) * Command {
61
81
for _ , opt := range opts {
82
+ c = c .WithContext (opt .Context )
62
83
c .AddArgs (opt .Args ... )
63
84
c .AddEnvs (opt .Envs ... )
64
85
}
@@ -124,7 +145,9 @@ func (c *Command) RunInDirWithOptions(dir string, opts ...RunInDirOptions) (err
124
145
if len (opts ) > 0 {
125
146
opt = opts [0 ]
126
147
}
127
- if opt .Timeout < time .Nanosecond {
148
+ if opt .Timeout < 0 {
149
+ opt .Timeout = - 1
150
+ } else if opt .Timeout == 0 {
128
151
opt .Timeout = DefaultTimeout
129
152
}
130
153
@@ -147,13 +170,21 @@ func (c *Command) RunInDirWithOptions(dir string, opts ...RunInDirOptions) (err
147
170
}
148
171
}()
149
172
150
- ctx , cancel := context .WithTimeout (context .Background (), opt .Timeout )
151
- defer func () {
152
- cancel ()
153
- if err == context .DeadlineExceeded {
154
- err = ErrExecTimeout
155
- }
156
- }()
173
+ ctx := context .Background ()
174
+ if c .ctx != nil {
175
+ ctx = c .ctx
176
+ }
177
+
178
+ if opt .Timeout > 0 {
179
+ var cancel context.CancelFunc
180
+ ctx , cancel = context .WithTimeout (ctx , opt .Timeout )
181
+ defer func () {
182
+ cancel ()
183
+ if err == context .DeadlineExceeded {
184
+ err = ErrExecTimeout
185
+ }
186
+ }()
187
+ }
157
188
158
189
cmd := exec .CommandContext (ctx , c .name , c .args ... )
159
190
if len (c .envs ) > 0 {
0 commit comments