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
11 from method_missing import MethodMissingMixin
12 from errors import GitCommandError
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')
20 class Git(MethodMissingMixin):
22 The Git class manages communication with the Git binary
24 def __init__(self, git_dir):
25 super(Git, self).__init__()
26 self.git_dir = git_dir
32 def execute(self, command,
35 with_extended_output=False,
37 with_raw_output=False,
40 Handles executing the command on the shell and consumes and returns
41 the returned information (stdout)
44 The command argument list to execute
47 Standard input filehandle passed to subprocess.Popen.
50 Whether to use the current working directory from os.getcwd().
51 GitPython uses get_work_tree() as its working directory by
52 default and get_git_dir() for bare repositories.
54 ``with_extended_output``
55 Whether to return a (status, stdout, stderr) tuple.
58 Whether to raise an exception when git returns a non-zero status.
61 Whether to avoid stripping off trailing whitespace.
64 str(output) # extended_output = False (Default)
65 tuple(int(status), str(output)) # extended_output = True
68 if GIT_PYTHON_TRACE and not GIT_PYTHON_TRACE == 'full':
69 print ' '.join(command)
71 # Allow the user to have the command executed in their working dir.
72 if with_keep_cwd or self.git_dir is None:
78 proc = subprocess.Popen(command,
81 stderr=subprocess.PIPE,
82 stdout=subprocess.PIPE
85 # Wait for the process to return
87 stdout_value = proc.stdout.read()
88 stderr_value = proc.stderr.read()
94 # Strip off trailing whitespace by default
95 if not with_raw_output:
96 stdout_value = stdout_value.rstrip()
97 stderr_value = stderr_value.rstrip()
99 if with_exceptions and status != 0:
100 raise GitCommandError(command, status, stderr_value)
102 if GIT_PYTHON_TRACE == 'full':
104 print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value)
106 print "%s -> %d: '%s'" % (command, status, stdout_value)
108 print "%s -> %d" % (command, status)
110 # Allow access to the command's status code
111 if with_extended_output:
112 return (status, stdout_value, stderr_value)
116 def transform_kwargs(self, **kwargs):
118 Transforms Python style kwargs into git command line options.
121 for k, v in kwargs.items():
124 args.append("-%s" % k)
125 elif type(v) is not bool:
126 args.append("-%s%s" % (k, v))
129 args.append("--%s" % dashify(k))
130 elif type(v) is not bool:
131 args.append("--%s=%s" % (dashify(k), v))
134 def method_missing(self, method, *args, **kwargs):
136 Run the given git command with the specified arguments and return
137 the result as a String
143 is the list of arguments
146 is a dict of keyword arguments.
147 This function accepts the same optional keyword arguments
151 git.rev_list('master', max_count=10, header=True)
157 # Handle optional arguments prior to calling transform_kwargs
158 # otherwise these'll end up in args, which is bad.
160 for kwarg in execute_kwargs:
162 _kwargs[kwarg] = kwargs.pop(kwarg)
166 # Prepare the argument list
167 opt_args = self.transform_kwargs(**kwargs)
168 ext_args = map(str, args)
169 args = opt_args + ext_args
171 call = ["git", dashify(method)]
174 return self.execute(call, **_kwargs)