models: remove the need for parameter registration
[git-cola.git] / cola / git.py
blob52782de987e8b27468d724a6add995c498dc3795
1 # cmd.py
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
7 import os
8 import sys
9 import subprocess
10 from cola import utils
11 from cola.exception import GitCommandError
13 def dashify(string):
14 return string.replace('_', '-')
16 # Enables debugging of GitPython's git commands
17 GIT_PYTHON_TRACE = os.environ.get("GIT_PYTHON_TRACE", False)
19 execute_kwargs = ('istream', 'with_keep_cwd', 'with_extended_output',
20 'with_exceptions', 'with_raw_output')
22 class Git(object):
23 """
24 The Git class manages communication with the Git binary
25 """
26 def __init__(self):
27 self._git_cwd = None
29 def set_cwd(self, path):
30 self._git_cwd = path
32 def __getattr__(self, name):
33 if name[0] == '_':
34 raise AttributeError(name)
35 return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
37 def execute(self, command,
38 istream=None,
39 with_keep_cwd=False,
40 with_extended_output=False,
41 with_exceptions=True,
42 with_raw_output=False):
43 """
44 Handles executing the command on the shell and consumes and returns
45 the returned information (stdout)
47 ``command``
48 The command argument list to execute
50 ``istream``
51 Standard input filehandle passed to subprocess.Popen.
53 ``with_keep_cwd``
54 Whether to use the current working directory from os.getcwd().
55 GitPython uses the cwd set by set_cwd() by default.
57 ``with_extended_output``
58 Whether to return a (status, stdout, stderr) tuple.
60 ``with_exceptions``
61 Whether to raise an exception when git returns a non-zero status.
63 ``with_raw_output``
64 Whether to avoid stripping off trailing whitespace.
66 Returns
67 str(output) # extended_output = False (Default)
68 tuple(int(status), str(output)) # extended_output = True
69 """
71 if GIT_PYTHON_TRACE and not GIT_PYTHON_TRACE == 'full':
72 print ' '.join(command)
74 # Allow the user to have the command executed in their working dir.
75 if with_keep_cwd or not self._git_cwd:
76 cwd = os.getcwd()
77 else:
78 cwd=self._git_cwd
80 # Start the process
81 if sys.platform == 'win32':
82 command = utils.shell_quote(*command)
84 proc = subprocess.Popen(command,
85 cwd=cwd,
86 shell=sys.platform == 'win32',
87 stdin=istream,
88 stderr=subprocess.PIPE,
89 stdout=subprocess.PIPE)
90 # Wait for the process to return
91 stdout_value, stderr_value = proc.communicate()
92 if not stdout_value:
93 stdout_value = ''
94 if not stderr_value:
95 stderr_value = ''
96 status = proc.returncode
98 # Strip off trailing whitespace by default
99 if not with_raw_output:
100 stdout_value = stdout_value.rstrip()
101 stderr_value = stderr_value.rstrip()
103 if with_exceptions and status:
104 raise GitCommandError(command, status, stderr_value)
106 if GIT_PYTHON_TRACE == 'full':
107 if stderr_value:
108 print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value)
109 elif stdout_value:
110 print "%s -> %d: '%s'" % (command, status, stdout_value)
111 else:
112 print "%s -> %d" % (command, status)
114 # Allow access to the command's status code
115 if with_extended_output:
116 return (status, stdout_value, stderr_value)
117 else:
118 if stdout_value and stderr_value:
119 return stderr_value + '\n' + stdout_value
120 elif stdout_value:
121 return stdout_value
122 else:
123 return stderr_value
125 def transform_kwargs(self, **kwargs):
127 Transforms Python style kwargs into git command line options.
129 args = []
130 for k, v in kwargs.items():
131 if len(k) == 1:
132 if v is True:
133 args.append("-%s" % k)
134 elif type(v) is not bool:
135 args.append("-%s%s" % (k, v))
136 else:
137 if v is True:
138 args.append("--%s" % dashify(k))
139 elif type(v) is not bool:
140 args.append("--%s=%s" % (dashify(k), v))
141 return args
143 def _call_process(self, method, *args, **kwargs):
145 Run the given git command with the specified arguments and return
146 the result as a String
148 ``method``
149 is the command
151 ``args``
152 is the list of arguments
154 ``kwargs``
155 is a dict of keyword arguments.
156 This function accepts the same optional keyword arguments
157 as execute().
159 Examples
160 git.rev_list('master', max_count=10, header=True)
162 Returns
163 Same as execute()
166 # Handle optional arguments prior to calling transform_kwargs
167 # otherwise these'll end up in args, which is bad.
168 _kwargs = {}
169 for kwarg in execute_kwargs:
170 try:
171 _kwargs[kwarg] = kwargs.pop(kwarg)
172 except KeyError:
173 pass
175 # Prepare the argument list
176 opt_args = self.transform_kwargs(**kwargs)
177 ext_args = [a.encode('utf-8') for a in args]
178 args = opt_args + ext_args
180 call = ['git', dashify(method)]
181 call.extend(args)
183 return self.execute(call, **_kwargs)