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