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
15 from cola
import errors
17 cmdlock
= threading
.Lock()
21 return string
.replace('_', '-')
23 # Enables debugging of GitPython's git commands
24 GIT_PYTHON_TRACE
= os
.environ
.get("GIT_PYTHON_TRACE", False)
26 execute_kwargs
= ('cwd',
34 if sys
.platform
== 'win32':
35 extra
= {'shell': True}
39 The Git class manages communication with the Git binary
42 self
._git
_cwd
= None #: The working directory used by execute()
44 def set_cwd(self
, path
):
45 """Sets the current directory."""
48 def __getattr__(self
, name
):
50 raise AttributeError(name
)
51 return lambda *args
, **kwargs
: self
._call
_process
(name
, *args
, **kwargs
)
57 with_exceptions
=False,
58 with_raw_output
=False,
62 Execute a command and returns its output
65 The command argument list to execute
68 Readable filehandle passed to subprocess.Popen.
71 The working directory when running commands.
75 Whether to return a (status, unicode(output)) tuple.
78 Whether to include stderr in the output stream
81 Whether to raise an exception when git returns a non-zero status.
84 Whether to avoid stripping off trailing whitespace.
87 unicode(stdout) # Default
88 unicode(stdout+stderr) # with_stderr=True
89 tuple(int(status), unicode(output)) # with_status=True
93 if GIT_PYTHON_TRACE
and not GIT_PYTHON_TRACE
== 'full':
94 print ' '.join(command
)
96 # Allow the user to have the command executed in their working dir.
101 stderr
= subprocess
.STDOUT
105 if sys
.platform
== 'win32':
106 command
= map(replace_carot
, command
)
109 # Guard against thread-unsafe .git/index.lock files
113 proc
= subprocess
.Popen(command
,
117 stdout
=subprocess
.PIPE
,
121 # Some systems interrupt system calls and throw OSError
122 if e
.errno
== errno
.EINTR
:
126 # Wait for the process to return
128 output
= core
.read_nointr(proc
.stdout
)
130 status
= core
.wait_nointr(proc
)
135 # Let the next thread in
138 if with_exceptions
and status
!= 0:
139 cmdstr
= 'Error running: %s\n%s' % (' '.join(command
), str(e
))
140 raise errors
.GitCommandError(cmdstr
, status
, output
)
142 if not with_raw_output
:
143 output
= output
.rstrip()
145 if GIT_PYTHON_TRACE
== 'full':
147 print "%s -> %d: '%s'" % (command
, status
, output
)
149 print "%s -> %d" % (command
, status
)
151 # Allow access to the command's status code
153 return (status
, output
)
157 def transform_kwargs(self
, **kwargs
):
159 Transforms Python style kwargs into git command line options.
162 for k
, v
in kwargs
.items():
165 args
.append("-%s" % k
)
166 elif type(v
) is not bool:
167 args
.append("-%s%s" % (k
, v
))
170 args
.append("--%s" % dashify(k
))
171 elif type(v
) is not bool:
172 args
.append("--%s=%s" % (dashify(k
), v
))
175 def _call_process(self
, cmd
, *args
, **kwargs
):
177 Run the given git command with the specified arguments and return
178 the result as a String
184 is the list of arguments
187 is a dict of keyword arguments.
188 This function accepts the same optional keyword arguments
192 git.rev_list('master', max_count=10, header=True)
198 # Handle optional arguments prior to calling transform_kwargs
199 # otherwise they'll end up in args, which is bad.
200 _kwargs
= dict(cwd
=self
._git
_cwd
)
201 for kwarg
in execute_kwargs
:
203 _kwargs
[kwarg
] = kwargs
.pop(kwarg
)
205 # Prepare the argument list
206 opt_args
= self
.transform_kwargs(**kwargs
)
207 ext_args
= map(core
.encode
, args
)
208 args
= opt_args
+ ext_args
210 call
= ['git', dashify(cmd
)]
213 return self
.execute(call
, **_kwargs
)
216 def replace_carot(cmd_arg
):
218 Guard against the windows command shell.
220 In the Windows shell, a carat character (^) may be used for
221 line continuation. To guard against this, escape the carat
222 by using two of them.
224 http://technet.microsoft.com/en-us/library/cc723564.aspx
227 return cmd_arg
.replace('^', '^^')
230 def shell_quote(*strings
):
232 Quote strings so that they can be suitably martialled
233 off to the shell. This method supports POSIX sh syntax.
234 This is crucial to properly handle command line arguments
235 with spaces, quotes, double-quotes, etc. on darwin/win32...
238 regex
= re
.compile('[^\w!%+,\-./:@^]')
239 quote_regex
= re
.compile("((?:'\\''){2,})")
247 raise ValueError('No way to quote strings '
248 'containing null(\\000) bytes')
250 # = does need quoting else in command position it's a
251 # program-local environment setting
252 match
= regex
.search(s
)
253 if match
and '=' not in s
:
255 s
= s
.replace("'", "'\\''")
257 # make multiple ' in a row look simpler
258 # '\'''\'''\'' -> '"'''"'
259 quote_match
= quote_regex
.match(s
)
261 quotes
= match
.group(1)
262 s
.replace(quotes
, ("'" *(len(quotes
)/4)) + "\"'")
265 if s
.startswith("''"):