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