2 # Copyright (C) 2008 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
12 return string
.replace('_', '-')
14 # Enables debugging of GitPython's git commands
15 GIT_PYTHON_TRACE
= os
.environ
.get("GIT_PYTHON_TRACE", False)
17 execute_kwargs
= ('istream', 'with_keep_cwd', 'with_extended_output',
18 'with_exceptions', 'with_raw_output')
21 if sys
.platform
== 'win32':
22 extra
= {'shell': True}
26 The Git class manages communication with the Git binary
28 def __init__(self
, git_dir
):
29 super(Git
, self
).__init
__()
30 self
.git_dir
= git_dir
32 def __getattr__(self
, name
):
34 raise AttributeError(name
)
35 return lambda *args
, **kwargs
: self
._call
_process
(name
, *args
, **kwargs
)
41 def execute(self
, command
,
44 with_extended_output
=False,
46 with_raw_output
=False,
49 Handles executing the command on the shell and consumes and returns
50 the returned information (stdout)
53 The command argument list to execute
56 Standard input filehandle passed to subprocess.Popen.
59 Whether to use the current working directory from os.getcwd().
60 GitPython uses get_work_tree() as its working directory by
61 default and get_git_dir() for bare repositories.
63 ``with_extended_output``
64 Whether to return a (status, stdout, stderr) tuple.
67 Whether to raise an exception when git returns a non-zero status.
70 Whether to avoid stripping off trailing whitespace.
73 str(output) # extended_output = False (Default)
74 tuple(int(status), str(output)) # extended_output = True
77 if GIT_PYTHON_TRACE
and not GIT_PYTHON_TRACE
== 'full':
78 print ' '.join(command
)
80 # Allow the user to have the command executed in their working dir.
81 if with_keep_cwd
or self
.git_dir
is None:
87 proc
= subprocess
.Popen(command
,
90 stderr
=subprocess
.PIPE
,
91 stdout
=subprocess
.PIPE
,
94 # Wait for the process to return
96 stdout_value
= proc
.stdout
.read().decode('utf-8')
97 stderr_value
= proc
.stderr
.read().decode('utf-8')
106 # Strip off trailing whitespace by default
107 if not with_raw_output
:
108 stdout_value
= stdout_value
.rstrip()
109 stderr_value
= stderr_value
.rstrip()
111 if with_exceptions
and status
!= 0:
112 raise GitCommandError(command
, status
, stderr_value
)
114 if GIT_PYTHON_TRACE
== 'full':
116 print "%s -> %d: '%s' !! '%s'" % (command
, status
, stdout_value
, stderr_value
)
118 print "%s -> %d: '%s'" % (command
, status
, stdout_value
)
120 print "%s -> %d" % (command
, status
)
122 # Allow access to the command's status code
123 if with_extended_output
:
124 return (status
, stdout_value
, stderr_value
)
128 def transform_kwargs(self
, **kwargs
):
130 Transforms Python style kwargs into git command line options.
133 for k
, v
in kwargs
.items():
136 args
.append("-%s" % k
)
137 elif type(v
) is not bool:
138 args
.append("-%s%s" % (k
, v
))
141 args
.append("--%s" % dashify(k
))
142 elif type(v
) is not bool:
143 args
.append("--%s=%s" % (dashify(k
), v
))
146 def _call_process(self
, method
, *args
, **kwargs
):
148 Run the given git command with the specified arguments and return
149 the result as a String
155 is the list of arguments
158 is a dict of keyword arguments.
159 This function accepts the same optional keyword arguments
163 git.rev_list('master', max_count=10, header=True)
169 # Handle optional arguments prior to calling transform_kwargs
170 # otherwise these'll end up in args, which is bad.
172 for kwarg
in execute_kwargs
:
174 _kwargs
[kwarg
] = kwargs
.pop(kwarg
)
178 # Prepare the argument list
179 opt_args
= self
.transform_kwargs(**kwargs
)
180 ext_args
= [a
.encode('utf-8') for a
in args
]
181 args
= opt_args
+ ext_args
183 call
= ["git", dashify(method
)]
186 return self
.execute(call
, **_kwargs
)