##// END OF EJS Templates
cleanup-repos: reintroduce paster command...
Mads Kiilerich -
r4560:b1679034 default
parent child Browse files
Show More
@@ -0,0 +1,155 b''
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
15 kallithea.lib.paster_commands.cleanup
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
18 cleanup-repos paster command for Kallithea
19
20
21 This file was forked by the Kallithea project in July 2014.
22 Original author and date, and relevant copyright and licensing information is below:
23 :created_on: Jul 14, 2012
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH.
26 :license: GPLv3, see LICENSE.md for more details.
27 """
28
29 from __future__ import with_statement
30
31 import os
32 import sys
33 import re
34 import shutil
35 import logging
36 import datetime
37
38 from kallithea.lib.utils import BasePasterCommand, ask_ok, REMOVED_REPO_PAT
39 from kallithea.lib.utils2 import safe_str
40 from kallithea.model.db import Ui
41
42 # Add location of top level folder to sys.path
43 from os.path import dirname as dn
44 rc_path = dn(dn(dn(os.path.realpath(__file__))))
45 sys.path.append(rc_path)
46
47 log = logging.getLogger(__name__)
48
49
50 class Command(BasePasterCommand):
51
52 max_args = 1
53 min_args = 1
54
55 usage = "CONFIG_FILE"
56 group_name = "Kallithea"
57 takes_config_file = -1
58 parser = BasePasterCommand.standard_parser(verbose=True)
59 summary = "Cleanup deleted repos"
60
61 def _parse_older_than(self, val):
62 regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
63 parts = regex.match(val)
64 if not parts:
65 return
66 parts = parts.groupdict()
67 time_params = {}
68 for (name, param) in parts.iteritems():
69 if param:
70 time_params[name] = int(param)
71 return datetime.timedelta(**time_params)
72
73 def _extract_date(self, name):
74 """
75 Extract the date part from rm__<date> pattern of removed repos,
76 and convert it to datetime object
77
78 :param name:
79 """
80 date_part = name[4:19] # 4:19 since we don't parse milisecods
81 return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
82
83 def command(self):
84 #get SqlAlchemy session
85 self._init_session()
86
87 repos_location = Ui.get_repos_location()
88 to_remove = []
89 for dn, dirs, f in os.walk(safe_str(repos_location)):
90 alldirs = list(dirs)
91 del dirs[:]
92 if ('.hg' in alldirs or
93 'objects' in alldirs and ('refs' in alldirs or 'packed-refs' in f)):
94 continue
95 for loc in alldirs:
96 if REMOVED_REPO_PAT.match(loc):
97 to_remove.append([os.path.join(dn, loc),
98 self._extract_date(loc)])
99 else:
100 dirs.append(loc)
101
102 #filter older than (if present)!
103 now = datetime.datetime.now()
104 older_than = self.options.older_than
105 if older_than:
106 to_remove_filtered = []
107 older_than_date = self._parse_older_than(older_than)
108 for name, date_ in to_remove:
109 repo_age = now - date_
110 if repo_age > older_than_date:
111 to_remove_filtered.append([name, date_])
112
113 to_remove = to_remove_filtered
114 print >> sys.stdout, 'removing %s deleted repos older than %s (%s)' \
115 % (len(to_remove), older_than, older_than_date)
116 else:
117 print >> sys.stdout, 'removing all [%s] deleted repos' \
118 % len(to_remove)
119 if self.options.dont_ask or not to_remove:
120 # don't ask just remove !
121 remove = True
122 else:
123 remove = ask_ok('the following repositories will be deleted completely:\n%s\n'
124 'are you sure you want to remove them [y/n]?'
125 % ', \n'.join(['%s removed on %s'
126 % (safe_str(x[0]), safe_str(x[1])) for x in to_remove]))
127
128 if remove:
129 for path, date_ in to_remove:
130 print >> sys.stdout, 'removing repository %s' % path
131 shutil.rmtree(path)
132 else:
133 print 'nothing done exiting...'
134 sys.exit(0)
135
136 def update_parser(self):
137 self.parser.add_option(
138 '--older-than',
139 action='store',
140 dest='older_than',
141 help=("only remove repos that have been removed "
142 "at least given time ago. "
143 "The default is to remove all removed repositories. "
144 "Possible suffixes: "
145 "d (days), h (hours), m (minutes), s (seconds). "
146 "For example --older-than=30d deletes repositories "
147 "removed more than 30 days ago.")
148 )
149
150 self.parser.add_option(
151 '--dont-ask',
152 action="store_true",
153 dest="dont_ask",
154 help="remove repositories without asking for confirmation."
155 )
@@ -172,6 +172,7 b' setup('
172
172
173 [paste.global_paster_command]
173 [paste.global_paster_command]
174 setup-db=kallithea.lib.paster_commands.setup_db:Command
174 setup-db=kallithea.lib.paster_commands.setup_db:Command
175 cleanup-repos=kallithea.lib.paster_commands.cleanup:Command
175 update-repoinfo=kallithea.lib.paster_commands.update_repoinfo:Command
176 update-repoinfo=kallithea.lib.paster_commands.update_repoinfo:Command
176 make-rcext=kallithea.lib.paster_commands.make_rcextensions:Command
177 make-rcext=kallithea.lib.paster_commands.make_rcextensions:Command
177 repo-scan=kallithea.lib.paster_commands.repo_scan:Command
178 repo-scan=kallithea.lib.paster_commands.repo_scan:Command
General Comments 0
You need to be logged in to leave comments. Login now