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