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