Prettify 'matrix changes' output
[matrix.git] / matrix / repositories.py
1 # Copyright (C) 2006-2008 Movial Oy
2 # Authors: Timo Savola <tsavola@movial.fi>
3
4 import os
5
6 import git
7 import log
8 from config import config
9
10 Error = RuntimeError
11
12 class Repository(object):
13         def __init__(self, name, path, branch, url=None, exclude=None):
14                 self.name = name
15                 self.path = path
16                 self.branch = branch
17                 self.url = url
18                 self.exclude = exclude
19                 self.__url_branch = None
20                 self.__hash = None
21
22         def __str__(self):
23                 return self.path
24
25         def exists(self):
26                 return git.contains_database(self.path)
27
28         def __get_url_branch(self):
29                 if not self.__url_branch:
30                         if self.exists():
31                                 self.__url_branch = self.__old_url_branch()
32
33                         if not self.__url_branch:
34                                 self.__url_branch = self.__new_url_branch()
35
36                         if config.debug:
37                                 url, branch = self.__url_branch
38                                 print 'Using URL:', url
39                                 print 'Using branch:', branch
40
41                 return self.__url_branch
42
43         def __new_url_branch(self):
44                 if self.url:
45                         return self.url, self.branch
46
47                 rev_roots = config.roots[:]
48                 rev_roots.reverse()
49
50                 for root, branch in rev_roots:
51                         for suffix in ('.git', ''):
52                                 url = root
53                                 while url.endswith("/"):
54                                         url = url[:-1]
55                                 url += "/" + self.name + suffix
56
57                                 if config.debug:
58                                         print 'Trying', url
59
60                                 if git.url_exists(url):
61                                         if self.branch:
62                                                 return url, self.branch
63                                         else:
64                                                 return url, branch
65
66                 raise Error('Failed to locate repository under any root: ' + \
67                             '%s.git' % self.name)
68
69         def __old_url_branch(self):
70                 branch, remote = self.__get_branch_remote()
71
72                 url = git.config_get(self.path, 'remote.%s.url' % remote)
73                 if not url:
74                         return None
75
76                 return url, branch
77
78         def __get_branch_remote(self):
79                 branch = git.branch_active(self.path)
80                 if not branch:
81                         return None
82
83                 remote = git.config_get(self.path, 'branch.%s.remote' % branch)
84                 if not remote:
85                         remote = 'origin'
86                         if config.debug:
87                                 print 'Branch "%s" has no configured remote,' \
88                                       ' assuming "%s"' % (branch, remote)
89
90                 return branch, remote
91
92         def clone(self):
93                 print 'Cloning', self
94
95                 url, branch = self.__get_url_branch()
96
97                 if os.path.exists(self.path):
98                         self.__clone_in_place(url)
99                 else:
100                         dirpath = os.path.dirname(self.path)
101                         if dirpath and not os.path.exists(dirpath):
102                                 os.makedirs(dirpath)
103
104                         git.clone(self.path, url, checkout=False)
105
106                 if self.exclude:
107                         git.exclude(self.path, self.exclude)
108
109                 if branch != git.branch_active(self.path):
110                         remote = 'origin/%s' % branch
111                         git.branch_create(self.path, branch, remote)
112
113                 git.checkout(self.path, branch)
114
115         def __clone_in_place(self, url):
116                 tmp = os.path.join(self.path, 'tmp')
117                 git.clone(tmp, url, checkout=False)
118
119                 try:
120                         tmpdb = git.database_path(tmp)
121                         db = git.database_path(self.path)
122
123                         if config.debug:
124                                 print 'Moving git database to', self.path
125
126                         os.rename(tmpdb, db)
127                 finally:
128                         os.rmdir(tmp)
129
130         def update(self):
131                 print 'Updating', self
132
133                 git.remote_update(self.path)
134
135         def rebase(self):
136                 print 'Rebasing', self
137
138                 git.rebase(self.path)
139
140         def pull(self):
141                 print 'Pulling', self
142
143                 git.pull(self.path)
144
145         def other_files(self):
146                 return git.ls_files(self.path, ['-o'], exclude=self.exclude)
147
148         def is_dirty(self):
149                 return git.any_files(self.path, ['-m', '-d'],
150                                      exclude=self.exclude)
151
152         def clean(self):
153                 print 'Cleaning', self
154
155                 paths = [os.path.join(self.path,i) for i in self.other_files()]
156                 paths.sort()
157                 paths.reverse()
158
159                 for path in paths:
160                         if config.debug:
161                                 print 'Removing', path
162
163                         if os.path.islink(path) or not os.path.isdir(path):
164                                 os.remove(path)
165                         else:
166                                 remove_tree(path)
167
168         def get_hash(self):
169                 if not self.__hash:
170                         self.__hash = git.rev_parse(self.path, 'HEAD')
171                 return self.__hash
172
173         def describe(self):
174                 return git.describe(self.path)
175
176         def archive(self, name, path):
177                 print 'Archiving', self
178
179                 url, branch = self.__get_url_branch()
180
181                 git.archive(self.path, path,
182                             prefix=name + os.path.sep,
183                             treeish=branch)
184
185         def dump_log(self, path):
186                 print 'Generating change log for', self
187
188                 url, branch = self.__get_url_branch()
189
190                 fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0644)
191                 try:
192                         git.log(self.path, [branch], fd=fd)
193                 finally:
194                         os.close(fd)
195
196         def changes(self):
197                 if config.debug:
198                         print 'Comparing', self
199
200                 branch, remote = self.__get_branch_remote()
201
202                 output = git.changes(self.path, "%s/%s" % (remote, branch))
203                 if not output:
204                         return False
205
206                 if config.verbose:
207                         print 'Changes in', str(self) + ":"
208                         for line in output:
209                                 print ' ', line
210                         print
211                 elif len(output) == 1:
212                         print "One local commit in", str(self)
213                 else:
214                         print len(output), "local commits in", str(self)
215
216                 return True