rebase command
[matrix.git] / matrix / git.py
1 # Copyright (C) 2007-2008 Movial Oy
2 # Authors: Timo Savola <tsavola@movial.fi>
3 #          Toni Timonen
4
5 import os, sys
6 import bz2
7
8 import config
9
10 class Error(RuntimeError):
11         def __init__(self, args, workdir=None):
12                 command = ' '.join(args)
13
14                 if workdir:
15                         message = 'Failed in %s: %s' % (workdir, command)
16                 else:
17                         message = 'Failed: %s' % command
18
19                 RuntimeError.__init__(self, message)
20
21 def call(args, workdir=None, quiet=False, fail=False):
22         args = ['git'] + args
23
24         if config.debug:
25                 if workdir:
26                         print 'Executing in %s:' % workdir,
27                 else:
28                         print 'Executing:',
29
30                 print ' '.join(args)
31
32         pid = os.fork()
33         if pid == 0:
34                 try:
35                         if workdir:
36                                 os.chdir(workdir)
37
38                         if quiet:
39                                 fd = os.open('/dev/null', os.O_WRONLY)
40                                 os.dup2(fd, 1)
41                                 os.dup2(fd, 2)
42                                 if fd not in (1, 2):
43                                         os.close(fd)
44
45                         os.execvp(args[0], args)
46
47                 except Exception, e:
48                         print >>sys.stderr, e
49
50                 os._exit(127)
51
52         pid, status = os.waitpid(pid, 0)
53         if status != 0 and fail:
54                 raise Error(args, workdir)
55
56         return status
57
58 def call_output(args, workdir=None, fd=None, lines=True,wait=True):
59         args = ['git'] + args
60
61         if config.debug:
62                 if workdir:
63                         print 'Executing in %s:' % workdir,
64                 else:
65                         print 'Executing:',
66
67                 print ' '.join(args)
68
69         if fd is None:
70                 input, output = os.pipe()
71
72         pid = os.fork()
73         if pid == 0:
74                 try:
75                         if workdir:
76                                 os.chdir(workdir)
77
78                         if fd is not None:
79                                 if fd != 1:
80                                         os.dup2(fd, 1)
81                         else:
82                                 os.close(input)
83                                 if output != 1:
84                                         os.dup2(output, 1)
85                                         os.close(output)
86
87                         os.execvp(args[0], args)
88
89                 except Exception, e:
90                         print >>sys.stderr, e
91
92                 os._exit(127)
93
94         if fd is None:
95                 os.close(output)
96
97                 f = os.fdopen(input, 'r')
98                 if lines:
99                         contents = f.readlines()
100                 else:
101                         contents = f.read()
102                 f.close()
103
104         if not wait and fd is not None:
105                 return
106         pid, status = os.waitpid(pid, 0)
107         if status != 0:
108                 raise Error(args, workdir)
109
110         if fd is None:
111                 if lines:
112                         return [i.strip() for i in contents]
113                 else:
114                         return contents
115
116 def peek_remote(url, quiet=False):
117         args = ['peek-remote', url]
118         return call(args, quiet=quiet, fail=not quiet) == 0
119
120 def clone(name, url, checkout=True):
121         options = []
122         if not checkout:
123                 options = ['-n']
124
125         call(['clone'] + options + [url, name], fail=True)
126
127 def remote_update(name):
128         call(['remote', 'update'], workdir=name)
129
130 def rebase(name, refspec='origin'):
131         cmd = ['rebase', refspec]
132         if call(cmd, workdir=name) != 0:
133                 raise Error(cmd, name)
134
135 def pull(name, url=None, refspec=None):
136         if url is None and refspec is None:
137                 cmd = ['pull']
138         else:
139                 cmd = ['pull',url,refspec]
140         if call(cmd, workdir=name) != 0:
141                 raise Error(cmd, name)
142
143 def checkout(name, branch=None):
144         cmd = ['checkout']
145         if branch:
146                 cmd.append(branch)
147
148         call(cmd, workdir=name, fail=True)
149
150 def rev_parse(name, arg):
151         lines = call_output(['rev-parse', arg], workdir=name)
152         if lines:
153                 return lines[0].strip()
154         else:
155                 return None
156
157 def getvar(name,var):
158         res=call_output(['config',var],workdir=name)
159         if res and len(res)==1:
160                 return res[0]
161         return None
162
163 def ls_tree(name, treeish, name_only=False, recursive=False):
164         options = []
165         if name_only:
166                 options.append('--name-only')
167         if recursive:
168                 options.append('-r')
169
170         return call_output(['ls-tree'] + options + [treeish], workdir=name)
171
172 def ls_files(name, options):
173         return call_output(['ls-files'] + options, workdir=name)
174
175
176 def archive(name, arch_name,prefix=None,branch='HEAD'):
177         cmd = ['archive','--format=tar']
178         if prefix:
179                 cmd.append('--prefix=%s'%prefix)
180
181         inp,out = os.pipe()
182         call_output(cmd+[branch],workdir=name,fd=out,wait=False)
183         os.close(out)
184         infile=os.fdopen(inp)
185         outfile=bz2.BZ2File(arch_name,'w')
186         data=infile.read(1024*50)
187         while data:
188                 outfile.write(data)
189                 data=infile.read(1024*50)
190         infile.close()
191         outfile.close()
192
193 def describe(name,branch='HEAD'):
194         cmd={'args':['describe',branch],'workdir':name}
195         try:
196                 call(quiet=True,fail=True,**cmd)
197                 res=call_output(**cmd)
198         except Error,e:
199                 return None
200
201         if res and len(res)==1:
202                 return res[0]
203         return None
204
205 def cat_file(name, hash, blob=False, size=False):
206         if blob:
207                 option = 'blob'
208         elif size:
209                 option = '-s'
210         else:
211                 return None
212
213         contents = call_output(['cat-file', option, hash], workdir=name,
214                                lines=False)
215
216         if size:
217                 return int(contents.strip())
218         else:
219                 return contents
220
221 def log(name, options, fd=None):
222         return call_output(['log'] + options + ['--'], workdir=name, fd=fd)
223
224 def exclude(name, line):
225         file = open(os.path.join(name, '.git', 'info', 'exclude'), 'a')
226         try:
227                 print >>file, line
228         finally:
229                 file.close()
230
231 def contains_database(name):
232         return os.path.exists(os.path.join(name, '.git'))