comparison rhodecode/model/repo.py @ 2031:82a88013a3fd

merge 1.3 into stable
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 26 Feb 2012 17:25:09 +0200
parents 24aeb43bbf51 14dffcfebb02
children dc2584ba5fbc
comparison
equal deleted inserted replaced
2005:ab0e122b38a7 2031:82a88013a3fd
5 5
6 Repository model for rhodecode 6 Repository model for rhodecode
7 7
8 :created_on: Jun 5, 2010 8 :created_on: Jun 5, 2010
9 :author: marcink 9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details. 11 :license: GPLv3, see COPYING for more details.
12 """ 12 """
13 # This program is free software: you can redistribute it and/or modify 13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by 14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or 15 # the Free Software Foundation, either version 3 of the License, or
26 import shutil 26 import shutil
27 import logging 27 import logging
28 import traceback 28 import traceback
29 from datetime import datetime 29 from datetime import datetime
30 30
31 from vcs.utils.lazy import LazyProperty 31 from rhodecode.lib.vcs.backends import get_backend
32 from vcs.backends import get_backend 32
33 33 from rhodecode.lib import LazyProperty
34 from rhodecode.lib import safe_str, safe_unicode 34 from rhodecode.lib import safe_str, safe_unicode
35 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.hooks import log_create_repository
35 37
36 from rhodecode.model import BaseModel 38 from rhodecode.model import BaseModel
37 from rhodecode.model.caching_query import FromCache 39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
38 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \ 40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
39 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group 41
40 42
41 log = logging.getLogger(__name__) 43 log = logging.getLogger(__name__)
42 44
43 45
44 class RepoModel(BaseModel): 46 class RepoModel(BaseModel):
47
48 def __get_user(self, user):
49 return self._get_instance(User, user, callback=User.get_by_username)
50
51 def __get_users_group(self, users_group):
52 return self._get_instance(UsersGroup, users_group,
53 callback=UsersGroup.get_by_group_name)
54
55 def __get_repos_group(self, repos_group):
56 return self._get_instance(RepoGroup, repos_group,
57 callback=RepoGroup.get_by_group_name)
58
59 def __get_repo(self, repository):
60 return self._get_instance(Repository, repository,
61 callback=Repository.get_by_repo_name)
62
63 def __get_perm(self, permission):
64 return self._get_instance(Permission, permission,
65 callback=Permission.get_by_key)
45 66
46 @LazyProperty 67 @LazyProperty
47 def repos_path(self): 68 def repos_path(self):
48 """Get's the repositories root path from database 69 """
70 Get's the repositories root path from database
49 """ 71 """
50 72
51 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() 73 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
52 return q.ui_value 74 return q.ui_value
53 75
58 if cache: 80 if cache:
59 repo = repo.options(FromCache("sql_cache_short", 81 repo = repo.options(FromCache("sql_cache_short",
60 "get_repo_%s" % repo_id)) 82 "get_repo_%s" % repo_id))
61 return repo.scalar() 83 return repo.scalar()
62 84
85 def get_repo(self, repository):
86 return self.__get_repo(repository)
87
63 def get_by_repo_name(self, repo_name, cache=False): 88 def get_by_repo_name(self, repo_name, cache=False):
64 repo = self.sa.query(Repository)\ 89 repo = self.sa.query(Repository)\
65 .filter(Repository.repo_name == repo_name) 90 .filter(Repository.repo_name == repo_name)
66 91
67 if cache: 92 if cache:
68 repo = repo.options(FromCache("sql_cache_short", 93 repo = repo.options(FromCache("sql_cache_short",
69 "get_repo_%s" % repo_name)) 94 "get_repo_%s" % repo_name))
70 return repo.scalar() 95 return repo.scalar()
71
72 96
73 def get_users_js(self): 97 def get_users_js(self):
74 98
75 users = self.sa.query(User).filter(User.active == True).all() 99 users = self.sa.query(User).filter(User.active == True).all()
76 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},''' 100 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
91 for gr in users_groups]) 115 for gr in users_groups])
92 return users_groups_array 116 return users_groups_array
93 117
94 def _get_defaults(self, repo_name): 118 def _get_defaults(self, repo_name):
95 """ 119 """
96 Get's information about repository, and returns a dict for 120 Get's information about repository, and returns a dict for
97 usage in forms 121 usage in forms
98 122
99 :param repo_name: 123 :param repo_name:
100 """ 124 """
101 125
102 repo_info = Repository.get_by_repo_name(repo_name) 126 repo_info = Repository.get_by_repo_name(repo_name)
103 127
128 defaults.update({'g_perm_%s' % p.users_group.users_group_name: 152 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
129 p.permission.permission_name}) 153 p.permission.permission_name})
130 154
131 return defaults 155 return defaults
132 156
133
134 def update(self, repo_name, form_data): 157 def update(self, repo_name, form_data):
135 try: 158 try:
136 cur_repo = self.get_by_repo_name(repo_name, cache=False) 159 cur_repo = self.get_by_repo_name(repo_name, cache=False)
137 160
138 # update permissions 161 # update permissions
139 for member, perm, member_type in form_data['perms_updates']: 162 for member, perm, member_type in form_data['perms_updates']:
140 if member_type == 'user': 163 if member_type == 'user':
141 r2p = self.sa.query(RepoToPerm)\ 164 # this updates existing one
142 .filter(RepoToPerm.user == User.get_by_username(member))\ 165 RepoModel().grant_user_permission(
143 .filter(RepoToPerm.repository == cur_repo)\ 166 repo=cur_repo, user=member, perm=perm
144 .one() 167 )
145
146 r2p.permission = self.sa.query(Permission)\
147 .filter(Permission.permission_name ==
148 perm).scalar()
149 self.sa.add(r2p)
150 else: 168 else:
151 g2p = self.sa.query(UsersGroupRepoToPerm)\ 169 RepoModel().grant_users_group_permission(
152 .filter(UsersGroupRepoToPerm.users_group == 170 repo=cur_repo, group_name=member, perm=perm
153 UsersGroup.get_by_group_name(member))\ 171 )
154 .filter(UsersGroupRepoToPerm.repository ==
155 cur_repo).one()
156
157 g2p.permission = self.sa.query(Permission)\
158 .filter(Permission.permission_name ==
159 perm).scalar()
160 self.sa.add(g2p)
161
162 # set new permissions 172 # set new permissions
163 for member, perm, member_type in form_data['perms_new']: 173 for member, perm, member_type in form_data['perms_new']:
164 if member_type == 'user': 174 if member_type == 'user':
165 r2p = RepoToPerm() 175 RepoModel().grant_user_permission(
166 r2p.repository = cur_repo 176 repo=cur_repo, user=member, perm=perm
167 r2p.user = User.get_by_username(member) 177 )
168
169 r2p.permission = self.sa.query(Permission)\
170 .filter(Permission.
171 permission_name == perm)\
172 .scalar()
173 self.sa.add(r2p)
174 else: 178 else:
175 g2p = UsersGroupRepoToPerm() 179 RepoModel().grant_users_group_permission(
176 g2p.repository = cur_repo 180 repo=cur_repo, group_name=member, perm=perm
177 g2p.users_group = UsersGroup.get_by_group_name(member) 181 )
178 g2p.permission = self.sa.query(Permission)\
179 .filter(Permission.
180 permission_name == perm)\
181 .scalar()
182 self.sa.add(g2p)
183 182
184 # update current repo 183 # update current repo
185 for k, v in form_data.items(): 184 for k, v in form_data.items():
186 if k == 'user': 185 if k == 'user':
187 cur_repo.user = User.get_by_username(v) 186 cur_repo.user = User.get_by_username(v)
188 elif k == 'repo_name': 187 elif k == 'repo_name':
189 pass 188 pass
190 elif k == 'repo_group': 189 elif k == 'repo_group':
191 cur_repo.group = Group.get(v) 190 cur_repo.group = RepoGroup.get(v)
192 191
193 else: 192 else:
194 setattr(cur_repo, k, v) 193 setattr(cur_repo, k, v)
195 194
196 new_name = cur_repo.get_new_name(form_data['repo_name']) 195 new_name = cur_repo.get_new_name(form_data['repo_name'])
200 199
201 if repo_name != new_name: 200 if repo_name != new_name:
202 # rename repository 201 # rename repository
203 self.__rename_repo(old=repo_name, new=new_name) 202 self.__rename_repo(old=repo_name, new=new_name)
204 203
205 self.sa.commit()
206 return cur_repo 204 return cur_repo
207 except: 205 except:
208 log.error(traceback.format_exc()) 206 log.error(traceback.format_exc())
209 self.sa.rollback()
210 raise 207 raise
211 208
212 def create(self, form_data, cur_user, just_db=False, fork=False): 209 def create(self, form_data, cur_user, just_db=False, fork=False):
210 from rhodecode.model.scm import ScmModel
213 211
214 try: 212 try:
215 if fork: 213 if fork:
216 repo_name = form_data['fork_name'] 214 fork_parent_id = form_data['fork_parent_id']
217 org_name = form_data['repo_name'] 215
218 org_full_name = org_name 216 # repo name is just a name of repository
219 217 # while repo_name_full is a full qualified name that is combined
220 else: 218 # with name and path of group
221 org_name = repo_name = form_data['repo_name'] 219 repo_name = form_data['repo_name']
222 repo_name_full = form_data['repo_name_full'] 220 repo_name_full = form_data['repo_name_full']
223 221
224 new_repo = Repository() 222 new_repo = Repository()
225 new_repo.enable_statistics = False 223 new_repo.enable_statistics = False
224
226 for k, v in form_data.items(): 225 for k, v in form_data.items():
227 if k == 'repo_name': 226 if k == 'repo_name':
228 if fork: 227 v = repo_name_full
229 v = repo_name
230 else:
231 v = repo_name_full
232 if k == 'repo_group': 228 if k == 'repo_group':
233 k = 'group_id' 229 k = 'group_id'
234
235 if k == 'description': 230 if k == 'description':
236 v = safe_unicode(v) or repo_name 231 v = v or repo_name
237 232
238 setattr(new_repo, k, v) 233 setattr(new_repo, k, v)
239 234
240 if fork: 235 if fork:
241 parent_repo = self.sa.query(Repository)\ 236 parent_repo = Repository.get(fork_parent_id)
242 .filter(Repository.repo_name == org_full_name).one()
243 new_repo.fork = parent_repo 237 new_repo.fork = parent_repo
244 238
245 new_repo.user_id = cur_user.user_id 239 new_repo.user_id = cur_user.user_id
246 self.sa.add(new_repo) 240 self.sa.add(new_repo)
247 241
248 #create default permission 242 def _create_default_perms():
249 repo_to_perm = RepoToPerm() 243 # create default permission
250 default = 'repository.read' 244 repo_to_perm = UserRepoToPerm()
251 for p in User.get_by_username('default').user_perms: 245 default = 'repository.read'
252 if p.permission.permission_name.startswith('repository.'): 246 for p in User.get_by_username('default').user_perms:
253 default = p.permission.permission_name 247 if p.permission.permission_name.startswith('repository.'):
254 break 248 default = p.permission.permission_name
255 249 break
256 default_perm = 'repository.none' if form_data['private'] else default 250
257 251 default_perm = 'repository.none' if form_data['private'] else default
258 repo_to_perm.permission_id = self.sa.query(Permission)\ 252
259 .filter(Permission.permission_name == default_perm)\ 253 repo_to_perm.permission_id = self.sa.query(Permission)\
260 .one().permission_id 254 .filter(Permission.permission_name == default_perm)\
261 255 .one().permission_id
262 repo_to_perm.repository = new_repo 256
263 repo_to_perm.user_id = User.get_by_username('default').user_id 257 repo_to_perm.repository = new_repo
264 258 repo_to_perm.user_id = User.get_by_username('default').user_id
265 self.sa.add(repo_to_perm) 259
260 self.sa.add(repo_to_perm)
261
262 if fork:
263 if form_data.get('copy_permissions'):
264 repo = Repository.get(fork_parent_id)
265 user_perms = UserRepoToPerm.query()\
266 .filter(UserRepoToPerm.repository == repo).all()
267 group_perms = UsersGroupRepoToPerm.query()\
268 .filter(UsersGroupRepoToPerm.repository == repo).all()
269
270 for perm in user_perms:
271 UserRepoToPerm.create(perm.user, new_repo,
272 perm.permission)
273
274 for perm in group_perms:
275 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
276 perm.permission)
277 else:
278 _create_default_perms()
279 else:
280 _create_default_perms()
266 281
267 if not just_db: 282 if not just_db:
268 self.__create_repo(repo_name, form_data['repo_type'], 283 self.__create_repo(repo_name, form_data['repo_type'],
269 form_data['repo_group'], 284 form_data['repo_group'],
270 form_data['clone_uri']) 285 form_data['clone_uri'])
271 286
272 self.sa.commit() 287 # now automatically start following this repository as owner
273
274 #now automatically start following this repository as owner
275 from rhodecode.model.scm import ScmModel
276 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, 288 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
277 cur_user.user_id) 289 cur_user.user_id)
290 log_create_repository(new_repo.get_dict(),
291 created_by=cur_user.username)
278 return new_repo 292 return new_repo
279 except: 293 except:
280 log.error(traceback.format_exc()) 294 log.error(traceback.format_exc())
281 self.sa.rollback()
282 raise 295 raise
283 296
284 def create_fork(self, form_data, cur_user): 297 def create_fork(self, form_data, cur_user):
298 """
299 Simple wrapper into executing celery task for fork creation
300
301 :param form_data:
302 :param cur_user:
303 """
285 from rhodecode.lib.celerylib import tasks, run_task 304 from rhodecode.lib.celerylib import tasks, run_task
286 run_task(tasks.create_repo_fork, form_data, cur_user) 305 run_task(tasks.create_repo_fork, form_data, cur_user)
287 306
288 def delete(self, repo): 307 def delete(self, repo):
308 repo = self.__get_repo(repo)
289 try: 309 try:
290 self.sa.delete(repo) 310 self.sa.delete(repo)
291 self.__delete_repo(repo) 311 self.__delete_repo(repo)
292 self.sa.commit()
293 except: 312 except:
294 log.error(traceback.format_exc()) 313 log.error(traceback.format_exc())
295 self.sa.rollback()
296 raise 314 raise
297 315
298 def delete_perm_user(self, form_data, repo_name): 316 def grant_user_permission(self, repo, user, perm):
317 """
318 Grant permission for user on given repository, or update existing one
319 if found
320
321 :param repo: Instance of Repository, repository_id, or repository name
322 :param user: Instance of User, user_id or username
323 :param perm: Instance of Permission, or permission_name
324 """
325 user = self.__get_user(user)
326 repo = self.__get_repo(repo)
327 permission = self.__get_perm(perm)
328
329 # check if we have that permission already
330 obj = self.sa.query(UserRepoToPerm)\
331 .filter(UserRepoToPerm.user == user)\
332 .filter(UserRepoToPerm.repository == repo)\
333 .scalar()
334 if obj is None:
335 # create new !
336 obj = UserRepoToPerm()
337 obj.repository = repo
338 obj.user = user
339 obj.permission = permission
340 self.sa.add(obj)
341
342 def revoke_user_permission(self, repo, user):
343 """
344 Revoke permission for user on given repository
345
346 :param repo: Instance of Repository, repository_id, or repository name
347 :param user: Instance of User, user_id or username
348 """
349 user = self.__get_user(user)
350 repo = self.__get_repo(repo)
351
352 obj = self.sa.query(UserRepoToPerm)\
353 .filter(UserRepoToPerm.repository == repo)\
354 .filter(UserRepoToPerm.user == user)\
355 .one()
356 self.sa.delete(obj)
357
358 def grant_users_group_permission(self, repo, group_name, perm):
359 """
360 Grant permission for users group on given repository, or update
361 existing one if found
362
363 :param repo: Instance of Repository, repository_id, or repository name
364 :param group_name: Instance of UserGroup, users_group_id,
365 or users group name
366 :param perm: Instance of Permission, or permission_name
367 """
368 repo = self.__get_repo(repo)
369 group_name = self.__get_users_group(group_name)
370 permission = self.__get_perm(perm)
371
372 # check if we have that permission already
373 obj = self.sa.query(UsersGroupRepoToPerm)\
374 .filter(UsersGroupRepoToPerm.users_group == group_name)\
375 .filter(UsersGroupRepoToPerm.repository == repo)\
376 .scalar()
377
378 if obj is None:
379 # create new
380 obj = UsersGroupRepoToPerm()
381
382 obj.repository = repo
383 obj.users_group = group_name
384 obj.permission = permission
385 self.sa.add(obj)
386
387 def revoke_users_group_permission(self, repo, group_name):
388 """
389 Revoke permission for users group on given repository
390
391 :param repo: Instance of Repository, repository_id, or repository name
392 :param group_name: Instance of UserGroup, users_group_id,
393 or users group name
394 """
395 repo = self.__get_repo(repo)
396 group_name = self.__get_users_group(group_name)
397
398 obj = self.sa.query(UsersGroupRepoToPerm)\
399 .filter(UsersGroupRepoToPerm.repository == repo)\
400 .filter(UsersGroupRepoToPerm.users_group == group_name)\
401 .one()
402 self.sa.delete(obj)
403
404 def delete_stats(self, repo_name):
405 """
406 removes stats for given repo
407
408 :param repo_name:
409 """
299 try: 410 try:
300 self.sa.query(RepoToPerm)\ 411 obj = self.sa.query(Statistics)\
301 .filter(RepoToPerm.repository \ 412 .filter(Statistics.repository ==
302 == self.get_by_repo_name(repo_name))\ 413 self.get_by_repo_name(repo_name))\
303 .filter(RepoToPerm.user_id == form_data['user_id']).delete() 414 .one()
304 self.sa.commit() 415 self.sa.delete(obj)
305 except: 416 except:
306 log.error(traceback.format_exc()) 417 log.error(traceback.format_exc())
307 self.sa.rollback()
308 raise
309
310 def delete_perm_users_group(self, form_data, repo_name):
311 try:
312 self.sa.query(UsersGroupRepoToPerm)\
313 .filter(UsersGroupRepoToPerm.repository \
314 == self.get_by_repo_name(repo_name))\
315 .filter(UsersGroupRepoToPerm.users_group_id \
316 == form_data['users_group_id']).delete()
317 self.sa.commit()
318 except:
319 log.error(traceback.format_exc())
320 self.sa.rollback()
321 raise
322
323 def delete_stats(self, repo_name):
324 try:
325 self.sa.query(Statistics)\
326 .filter(Statistics.repository == \
327 self.get_by_repo_name(repo_name)).delete()
328 self.sa.commit()
329 except:
330 log.error(traceback.format_exc())
331 self.sa.rollback()
332 raise 418 raise
333 419
334 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False): 420 def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
335 """ 421 """
336 makes repository on filesystem. It's group aware means it'll create 422 makes repository on filesystem. It's group aware means it'll create
343 :param clone_uri: 429 :param clone_uri:
344 """ 430 """
345 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group 431 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
346 432
347 if new_parent_id: 433 if new_parent_id:
348 paths = Group.get(new_parent_id).full_path.split(Group.url_sep()) 434 paths = RepoGroup.get(new_parent_id)\
435 .full_path.split(RepoGroup.url_sep())
349 new_parent_path = os.sep.join(paths) 436 new_parent_path = os.sep.join(paths)
350 else: 437 else:
351 new_parent_path = '' 438 new_parent_path = ''
352 439
353 repo_path = os.path.join(*map(lambda x:safe_str(x), 440 # we need to make it str for mercurial
441 repo_path = os.path.join(*map(lambda x: safe_str(x),
354 [self.repos_path, new_parent_path, repo_name])) 442 [self.repos_path, new_parent_path, repo_name]))
355
356 443
357 # check if this path is not a repository 444 # check if this path is not a repository
358 if is_valid_repo(repo_path, self.repos_path): 445 if is_valid_repo(repo_path, self.repos_path):
359 raise Exception('This path %s is a valid repository' % repo_path) 446 raise Exception('This path %s is a valid repository' % repo_path)
360 447
361 # check if this path is a group 448 # check if this path is a group
362 if is_valid_repos_group(repo_path, self.repos_path): 449 if is_valid_repos_group(repo_path, self.repos_path):
363 raise Exception('This path %s is a valid group' % repo_path) 450 raise Exception('This path %s is a valid group' % repo_path)
364 451
365 log.info('creating repo %s in %s @ %s', repo_name, repo_path, 452 log.info('creating repo %s in %s @ %s' % (
366 clone_uri) 453 repo_name, safe_unicode(repo_path), clone_uri
454 )
455 )
367 backend = get_backend(alias) 456 backend = get_backend(alias)
368 457
369 backend(repo_path, create=True, src_url=clone_uri) 458 backend(repo_path, create=True, src_url=clone_uri)
370
371 459
372 def __rename_repo(self, old, new): 460 def __rename_repo(self, old, new):
373 """ 461 """
374 renames repository on filesystem 462 renames repository on filesystem
375 463
376 :param old: old name 464 :param old: old name
377 :param new: new name 465 :param new: new name
378 """ 466 """
379 log.info('renaming repo from %s to %s', old, new) 467 log.info('renaming repo from %s to %s' % (old, new))
380 468
381 old_path = os.path.join(self.repos_path, old) 469 old_path = os.path.join(self.repos_path, old)
382 new_path = os.path.join(self.repos_path, new) 470 new_path = os.path.join(self.repos_path, new)
383 if os.path.isdir(new_path): 471 if os.path.isdir(new_path):
384 raise Exception('Was trying to rename to already existing dir %s' \ 472 raise Exception(
385 % new_path) 473 'Was trying to rename to already existing dir %s' % new_path
474 )
386 shutil.move(old_path, new_path) 475 shutil.move(old_path, new_path)
387 476
388 def __delete_repo(self, repo): 477 def __delete_repo(self, repo):
389 """ 478 """
390 removes repo from filesystem, the removal is acctually made by 479 removes repo from filesystem, the removal is acctually made by
393 by reverting the renames on this repository 482 by reverting the renames on this repository
394 483
395 :param repo: repo object 484 :param repo: repo object
396 """ 485 """
397 rm_path = os.path.join(self.repos_path, repo.repo_name) 486 rm_path = os.path.join(self.repos_path, repo.repo_name)
398 log.info("Removing %s", rm_path) 487 log.info("Removing %s" % (rm_path))
399 #disable hg/git 488 # disable hg/git
400 alias = repo.repo_type 489 alias = repo.repo_type
401 shutil.move(os.path.join(rm_path, '.%s' % alias), 490 shutil.move(os.path.join(rm_path, '.%s' % alias),
402 os.path.join(rm_path, 'rm__.%s' % alias)) 491 os.path.join(rm_path, 'rm__.%s' % alias))
403 #disable repo 492 # disable repo
404 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \ 493 _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
405 % (datetime.today()\ 494 repo.repo_name)
406 .strftime('%Y%m%d_%H%M%S_%f'), 495 shutil.move(rm_path, os.path.join(self.repos_path, _d))
407 repo.repo_name)))
408