2 # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
4 # This module is part of GitPython and is released under
5 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
14 from cola
import errors
18 return string
.replace('_', '-')
20 # Enables debugging of GitPython's git commands
21 GIT_PYTHON_TRACE
= os
.environ
.get("GIT_PYTHON_TRACE", False)
23 execute_kwargs
= ('cwd',
31 if sys
.platform
== 'win32':
32 extra
= {'shell': True}
36 The Git class manages communication with the Git binary
39 self
._git
_cwd
= None #: The working directory used by execute()
41 def set_cwd(self
, path
):
42 """Sets the current directory."""
45 def __getattr__(self
, name
):
47 raise AttributeError(name
)
48 return lambda *args
, **kwargs
: self
._call
_process
(name
, *args
, **kwargs
)
54 with_exceptions
=False,
55 with_raw_output
=False,
59 Execute a command and returns its output
62 The command argument list to execute
65 Readable filehandle passed to subprocess.Popen.
68 The working directory when running commands.
72 Whether to return a (status, unicode(output)) tuple.
75 Whether to include stderr in the output stream
78 Whether to raise an exception when git returns a non-zero status.
81 Whether to avoid stripping off trailing whitespace.
84 unicode(stdout) # Default
85 unicode(stdout+stderr) # with_stderr=True
86 tuple(int(status), unicode(output)) # with_status=True
90 if GIT_PYTHON_TRACE
and not GIT_PYTHON_TRACE
== 'full':
91 print ' '.join(command
)
93 # Allow the user to have the command executed in their working dir.
98 stderr
= subprocess
.STDOUT
102 if sys
.platform
== 'win32':
103 command
= map(replace_carot
, command
)
108 proc
= subprocess
.Popen(command
,
112 stdout
=subprocess
.PIPE
,
116 # Some systems interrupt system calls and throw OSError
117 if e
.errno
== errno
.EINTR
:
121 # Wait for the process to return
122 output
= core
.read_nointr(proc
.stdout
)
124 status
= core
.wait_nointr(proc
)
126 if with_exceptions
and status
!= 0:
127 raise errors
.GitCommandError(command
, status
, output
)
129 if not with_raw_output
:
130 output
= output
.rstrip()
132 if GIT_PYTHON_TRACE
== 'full':
134 print "%s -> %d: '%s'" % (command
, status
, output
)
136 print "%s -> %d" % (command
, status
)
138 # Allow access to the command's status code
140 return (status
, output
)
144 def transform_kwargs(self
, **kwargs
):
146 Transforms Python style kwargs into git command line options.
149 for k
, v
in kwargs
.items():
152 args
.append("-%s" % k
)
153 elif type(v
) is not bool:
154 args
.append("-%s%s" % (k
, v
))
157 args
.append("--%s" % dashify(k
))
158 elif type(v
) is not bool:
159 args
.append("--%s=%s" % (dashify(k
), v
))
162 def _call_process(self
, method
, *args
, **kwargs
):
164 Run the given git command with the specified arguments and return
165 the result as a String
171 is the list of arguments
174 is a dict of keyword arguments.
175 This function accepts the same optional keyword arguments
179 git.rev_list('master', max_count=10, header=True)
185 # Handle optional arguments prior to calling transform_kwargs
186 # otherwise they'll end up in args, which is bad.
187 _kwargs
= dict(cwd
=self
._git
_cwd
)
188 for kwarg
in execute_kwargs
:
190 _kwargs
[kwarg
] = kwargs
.pop(kwarg
)
192 # Prepare the argument list
193 opt_args
= self
.transform_kwargs(**kwargs
)
194 ext_args
= map(core
.encode
, args
)
195 args
= opt_args
+ ext_args
197 call
= ['git', dashify(method
)]
200 return self
.execute(call
, **_kwargs
)
203 def replace_carot(cmd_arg
):
205 Guard against the windows command shell.
207 In the Windows shell, a carat character (^) may be used for
208 line continuation. To guard against this, escape the carat
209 by using two of them.
211 http://technet.microsoft.com/en-us/library/cc723564.aspx
214 return cmd_arg
.replace('^', '^^')
217 def shell_quote(*strings
):
219 Quote strings so that they can be suitably martialled
220 off to the shell. This method supports POSIX sh syntax.
221 This is crucial to properly handle command line arguments
222 with spaces, quotes, double-quotes, etc. on darwin/win32...
225 regex
= re
.compile('[^\w!%+,\-./:@^]')
226 quote_regex
= re
.compile("((?:'\\''){2,})")
234 raise ValueError('No way to quote strings '
235 'containing null(\\000) bytes')
237 # = does need quoting else in command position it's a
238 # program-local environment setting
239 match
= regex
.search(s
)
240 if match
and '=' not in s
:
242 s
= s
.replace("'", "'\\''")
244 # make multiple ' in a row look simpler
245 # '\'''\'''\'' -> '"'''"'
246 quote_match
= quote_regex
.match(s
)
248 quotes
= match
.group(1)
249 s
.replace(quotes
, ("'" *(len(quotes
)/4)) + "\"'")
252 if s
.startswith("''"):