Git doesn't create the destination directory structure for you in
[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                         os.makedirs(os.path.split(self.path)[0])
101                         git.clone(self.path, url, checkout=False)
102
103                 if self.exclude:
104                         git.exclude(self.path, self.exclude)
105
106                 if branch != git.branch_active(self.path):
107                         remote = 'origin/%s' % branch
108                         git.branch_create(self.path, branch, remote)
109
110                 git.checkout(self.path, branch)
111
112         def __clone_in_place(self, url):
113                 tmp = os.path.join(self.path, 'tmp')
114                 git.clone(tmp, url, checkout=False)
115
116                 try:
117                         tmpdb = git.database_path(tmp)
118                         db = git.database_path(self.path)
119
120                         if config.debug:
121                                 print 'Moving git database to', self.path
122
123                         os.rename(tmpdb, db)
124                 finally:
125                         os.rmdir(tmp)
126
127         def rebase(self):
128                 print 'Rebasing', self
129
130                 git.remote_update(self.path)
131                 git.rebase(self.path)
132
133         def pull(self):
134                 print 'Pulling', self
135
136                 git.pull(self.path)
137
138         def other_files(self):
139                 return git.ls_files(self.path, ['-o'], exclude=self.exclude)
140
141         def is_dirty(self):
142                 return git.any_files(self.path, ['-m', '-d'],
143                                      exclude=self.exclude)
144
145         def clean(self):
146                 print 'Cleaning', self
147
148                 paths = [os.path.join(self.path,i) for i in self.other_files()]
149                 paths.sort()
150                 paths.reverse()
151
152                 for path in paths:
153                         if config.debug:
154                                 print 'Removing', path
155
156                         if os.path.islink(path) or not os.path.isdir(path):
157                                 os.remove(path)
158                         else:
159                                 remove_tree(path)
160
161         def get_hash(self):
162                 if not self.__hash:
163                         self.__hash = git.rev_parse(self.path, 'HEAD')
164                 return self.__hash
165
166         def describe(self):
167                 return git.describe(self.path)
168
169         def archive(self, name, path):
170                 print 'Archiving', self
171
172                 url, branch = self.__get_url_branch()
173
174                 git.archive(self.path, path,
175                             prefix=name + os.path.sep,
176                             treeish=branch)
177
178         def dump_log(self, path):
179                 print 'Generating change log for', self
180
181                 url, branch = self.__get_url_branch()
182
183                 fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0644)
184                 try:
185                         git.log(self.path, [branch], fd=fd)
186                 finally:
187                         os.close(fd)
188
189         def changes(self):
190                 print 'Comparing', self
191
192                 branch, remote = self.__get_branch_remote()
193
194                 output = git.changes(self.path, remote)
195                 if output:
196                         print
197                         for line in output:
198                                 print ' ', line
199                         print
200
201                         return True
202                 else:
203                         return False