@@ -20,12 +20,18 @@ type Command struct {
2020 name string
2121 args []string
2222 envs []string
23+ ctx context.Context
2324}
2425
2526// 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.
2630type CommandOptions struct {
27- Args []string
28- Envs []string
31+ Args []string
32+ Envs []string
33+ Timeout time.Duration
34+ Context context.Context
2935}
3036
3137// String returns the string representation of the command.
@@ -38,9 +44,16 @@ func (c *Command) String() string {
3844
3945// NewCommand creates and returns a new Command with given arguments for "git".
4046func 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 {
4153 return & Command {
4254 name : "git" ,
4355 args : args ,
56+ ctx : ctx ,
4457 }
4558}
4659
@@ -56,9 +69,17 @@ func (c *Command) AddEnvs(envs ...string) *Command {
5669 return c
5770}
5871
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+
5978// AddOptions adds options to the command.
79+ // Note: only the last option will take effect if there are duplicated options.
6080func (c * Command ) AddOptions (opts ... CommandOptions ) * Command {
6181 for _ , opt := range opts {
82+ c = c .WithContext (opt .Context )
6283 c .AddArgs (opt .Args ... )
6384 c .AddEnvs (opt .Envs ... )
6485 }
@@ -124,7 +145,9 @@ func (c *Command) RunInDirWithOptions(dir string, opts ...RunInDirOptions) (err
124145 if len (opts ) > 0 {
125146 opt = opts [0 ]
126147 }
127- if opt .Timeout < time .Nanosecond {
148+ if opt .Timeout < 0 {
149+ opt .Timeout = - 1
150+ } else if opt .Timeout == 0 {
128151 opt .Timeout = DefaultTimeout
129152 }
130153
@@ -147,13 +170,21 @@ func (c *Command) RunInDirWithOptions(dir string, opts ...RunInDirOptions) (err
147170 }
148171 }()
149172
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+ }
157188
158189 cmd := exec .CommandContext (ctx , c .name , c .args ... )
159190 if len (c .envs ) > 0 {
0 commit comments