comparison rhodecode/lib/paster_commands/cleanup.py @ 3340:f1491bad8339 beta

unified RhodeCode paster commands - moved them to commont paster_commands package - re-use sqlalchemy session initializaiton - some docs updates
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 09 Feb 2013 22:21:31 +0100
parents rhodecode/lib/cleanup.py@f62d805544a4
children c8fd8cca71f2
comparison
equal deleted inserted replaced
3339:b76a595b7a5e 3340:f1491bad8339
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.lib.paster_commands.make_rcextensions
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 cleanup-repos paster command for RhodeCode
7
8
9 :created_on: Jul 14, 2012
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
13 """
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 from __future__ import with_statement
27
28 import os
29 import sys
30 import re
31 import shutil
32 import logging
33 import datetime
34
35 from os.path import dirname as dn, join as jn
36 #to get the rhodecode import
37 rc_path = dn(dn(dn(os.path.realpath(__file__))))
38 sys.path.append(rc_path)
39 from rhodecode.lib.utils import BasePasterCommand, ask_ok, REMOVED_REPO_PAT
40
41 from rhodecode.lib.utils2 import safe_str
42 from rhodecode.model.db import RhodeCodeUi
43
44
45 log = logging.getLogger(__name__)
46
47
48 class Command(BasePasterCommand):
49
50 max_args = 1
51 min_args = 1
52
53 usage = "CONFIG_FILE"
54 group_name = "RhodeCode"
55 takes_config_file = -1
56 parser = BasePasterCommand.standard_parser(verbose=True)
57 summary = "Cleanup deleted repos"
58
59 def _parse_older_than(self, val):
60 regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
61 parts = regex.match(val)
62 if not parts:
63 return
64 parts = parts.groupdict()
65 time_params = {}
66 for (name, param) in parts.iteritems():
67 if param:
68 time_params[name] = int(param)
69 return datetime.timedelta(**time_params)
70
71 def _extract_date(self, name):
72 """
73 Extract the date part from rm__<date> pattern of removed repos,
74 and convert it to datetime object
75
76 :param name:
77 """
78 date_part = name[4:19] # 4:19 since we don't parse milisecods
79 return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
80
81 def command(self):
82 #get SqlAlchemy session
83 self._init_session()
84
85 repos_location = RhodeCodeUi.get_repos_location()
86 to_remove = []
87 for dn, dirs, f in os.walk(safe_str(repos_location)):
88 for loc in dirs:
89 if REMOVED_REPO_PAT.match(loc):
90 to_remove.append([os.path.join(dn, loc),
91 self._extract_date(loc)])
92
93 #filter older than (if present)!
94 now = datetime.datetime.now()
95 older_than = self.options.older_than
96 if older_than:
97 to_remove_filtered = []
98 older_than_date = self._parse_older_than(older_than)
99 for name, date_ in to_remove:
100 repo_age = now - date_
101 if repo_age > older_than_date:
102 to_remove_filtered.append([name, date_])
103
104 to_remove = to_remove_filtered
105 print >> sys.stdout, 'removing [%s] deleted repos older than %s[%s]' \
106 % (len(to_remove), older_than, older_than_date)
107 else:
108 print >> sys.stdout, 'removing all [%s] deleted repos' \
109 % len(to_remove)
110 if self.options.dont_ask or not to_remove:
111 # don't ask just remove !
112 remove = True
113 else:
114 remove = ask_ok('are you sure to remove listed repos \n%s [y/n]?'
115 % ', \n'.join(['%s removed on %s'
116 % (safe_str(x[0]), safe_str(x[1])) for x in to_remove]))
117
118 if remove:
119 for name, date_ in to_remove:
120 print >> sys.stdout, 'removing repository %s' % name
121 shutil.rmtree(os.path.join(repos_location, name))
122 else:
123 print 'nothing done exiting...'
124 sys.exit(0)
125
126 def update_parser(self):
127 self.parser.add_option('--older-than',
128 action='store',
129 dest='older_than',
130 help=(
131 "only remove repos that have been removed "
132 "at least given time ago "
133 "ex. --older-than=30d deletes repositores "
134 "removed more than 30days ago. Possible options "
135 "d[ays]/h[ours]/m[inutes]/s[seconds]. OPTIONAL"),
136 )
137 self.parser.add_option('--dont-ask',
138 action='store_true',
139 dest='dont_ask',
140 help=("Don't ask to remove repos"))