8687.15.18
by Karl Fogel
Add the copyright header block to files under lib/canonical/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
3 |
|
4 |
"""Remove specific translation messages from the database."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
__all__ = [ |
|
13636.1.19
by Henning Eggers
Expose and use process_options. |
8 |
'process_options', |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
9 |
'RemoveTranslations', |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
10 |
'remove_translations', |
11 |
]
|
|
12 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
13 |
import logging |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
14 |
from optparse import ( |
15 |
Option, |
|
16 |
OptionValueError, |
|
17 |
)
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
18 |
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
19 |
from zope.component import getUtility |
20 |
||
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
21 |
from lp.services.database.postgresql import drop_tables |
22 |
from lp.services.database.sqlbase import ( |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
23 |
cursor, |
24 |
sqlvalues, |
|
25 |
)
|
|
26 |
from lp.services.scripts.base import ( |
|
27 |
LaunchpadScript, |
|
28 |
LaunchpadScriptFailure, |
|
29 |
)
|
|
8751.1.8
by Danilo Šegan
Fix most lint warnings. |
30 |
from lp.translations.interfaces.translationmessage import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
31 |
RosettaTranslationOrigin, |
32 |
)
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
33 |
|
34 |
||
13636.1.14
by Henning Eggers
Rename to processing. |
35 |
def process_bool_option(value): |
36 |
"""Validation and conversion for Boolean argument."""
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
37 |
value = value.lower() |
38 |
bool_representations = { |
|
39 |
'true': True, |
|
40 |
'1': True, |
|
41 |
'false': False, |
|
42 |
'0': False, |
|
43 |
}
|
|
44 |
||
45 |
if value not in bool_representations: |
|
46 |
raise OptionValueError("Invalid boolean value: %s" % value) |
|
47 |
||
48 |
return bool_representations[value] |
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
49 |
|
50 |
||
51 |
def get_id(identifier, lookup_function=None): |
|
52 |
"""Look up id of object identified by a string.
|
|
53 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
54 |
Raises `OptionValueError` if the option's value appears invalid.
|
55 |
||
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
56 |
:param identifier: String identifying an object. If entirely
|
57 |
numeric, taken as id. Otherwise, passed to lookup_function.
|
|
58 |
:param lookup_function: Callback that will take `identifier` as
|
|
59 |
its argument and return a numeric object id. If no object
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
60 |
has the given identifier, may raise a `LookUpError` or return
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
61 |
None.
|
62 |
:return: Numeric object id, or None if no identifier is given.
|
|
63 |
"""
|
|
64 |
if identifier is None or identifier == '': |
|
65 |
return None |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
66 |
elif isinstance(identifier, basestring) and identifier == '': |
67 |
return None |
|
68 |
elif isinstance(identifier, int): |
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
69 |
return identifier |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
70 |
elif identifier.isdigit(): |
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
71 |
return int(identifier) |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
72 |
elif lookup_function is None: |
73 |
raise OptionValueError("Expected numeric id, got '%s'." % identifier) |
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
74 |
else: |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
75 |
try: |
76 |
result = lookup_function(identifier) |
|
77 |
except LookupError: |
|
78 |
raise OptionValueError("'%s' not found." % identifier) |
|
79 |
||
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
80 |
if result is None: |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
81 |
raise OptionValueError("'%s' not found." % identifier) |
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
82 |
return result |
83 |
||
84 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
85 |
def get_person_id(name): |
86 |
"""`get_id` helper. Look up person by name."""
|
|
11666.3.3
by Curtis Hovey
Fixed cyclic imports. |
87 |
# XXX sinzui 2010-10-04 bug=654537: Account and EmailAddress cause cyclic
|
88 |
# imports because they are not in the lp tree.
|
|
89 |
from lp.registry.interfaces.person import IPersonSet |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
90 |
person = getUtility(IPersonSet).getByName(name) |
91 |
if person is None: |
|
92 |
return None |
|
93 |
return person.id |
|
94 |
||
95 |
||
96 |
def get_origin(name): |
|
97 |
"""`get_id` helper. Look up `RosettaTranslationOrigin` by name."""
|
|
98 |
try: |
|
99 |
return getattr(RosettaTranslationOrigin, name).value |
|
100 |
except AttributeError: |
|
101 |
return None |
|
102 |
||
103 |
||
13636.1.14
by Henning Eggers
Rename to processing. |
104 |
def process_origin_option(value): |
105 |
"""Validation and conversion for `RosettaTranslationsOrigin`."""
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
106 |
return get_id(value, get_origin) |
107 |
||
108 |
||
13636.1.14
by Henning Eggers
Rename to processing. |
109 |
def process_person_option(value): |
110 |
"""Validation and conversion for `Person`."""
|
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
111 |
return get_id(value, get_person_id) |
112 |
||
13636.1.19
by Henning Eggers
Expose and use process_options. |
113 |
|
13636.1.15
by Henning Eggers
List special options. |
114 |
# Options that need special processing.
|
115 |
OPTIONS_TO_PROCESS = { |
|
116 |
'submitter': process_person_option, |
|
117 |
'reviewer': process_person_option, |
|
118 |
'origin': process_origin_option, |
|
119 |
'is_current_ubuntu': process_bool_option, |
|
120 |
'is_current_upstream': process_bool_option, |
|
121 |
}
|
|
122 |
||
13636.1.19
by Henning Eggers
Expose and use process_options. |
123 |
|
124 |
def process_options(options): |
|
125 |
"""Process options that need special processing."""
|
|
126 |
for option_name, process_func in OPTIONS_TO_PROCESS.items(): |
|
127 |
option_value = getattr(options, option_name) |
|
13636.1.21
by Henning Eggers
Really fix script. And test. |
128 |
if option_value is not None: |
129 |
setattr(options, option_name, process_func(option_value)) |
|
13636.1.19
by Henning Eggers
Expose and use process_options. |
130 |
|
131 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
132 |
def is_nonempty_list(list_option): |
133 |
"""Is list_option a non-empty a nonempty list of option values?"""
|
|
134 |
return list_option is not None and len(list_option) > 0 |
|
135 |
||
136 |
||
137 |
def is_nonempty_string(string_option): |
|
138 |
"""Is string_option a non-empty option value?"""
|
|
139 |
return string_option is not None and string_option != '' |
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
140 |
|
141 |
||
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
142 |
def compose_language_match(language_code): |
143 |
"""Compose SQL condition for matching a language in the deletion query.
|
|
144 |
||
11122.3.4
by Danilo Šegan
Get rid of the remaining variant usage. |
145 |
:param: Language code to match.
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
146 |
:return: SQL condition in string form.
|
147 |
"""
|
|
11122.3.17
by Danilo Segan
Apply review comments from jtv as well. |
148 |
return 'Language.code = %s' % sqlvalues(language_code) |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
149 |
|
150 |
||
151 |
def add_bool_match(conditions, expression, match_value): |
|
152 |
"""Add match for tri-state Boolean to SQL conditions.
|
|
153 |
||
154 |
:param conditions: Set of SQL condition clauses to add to.
|
|
155 |
:param expression: Variable or other SQL expression to match on.
|
|
156 |
:param match_value: If given, the Boolean value to match. If left
|
|
157 |
as None, no condition is added.
|
|
158 |
"""
|
|
159 |
if match_value is None: |
|
160 |
return
|
|
161 |
||
162 |
if match_value: |
|
163 |
match = expression |
|
164 |
else: |
|
165 |
match = 'NOT (%s)' % expression |
|
166 |
conditions.add(match) |
|
167 |
||
168 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
169 |
class RemoveTranslations(LaunchpadScript): |
170 |
"""Remove specific `TranslationMessage`s from the database.
|
|
171 |
||
172 |
The script accepts a wide range of options to specify exactly which
|
|
173 |
messages need deleting. It will refuse to run if the options are so
|
|
174 |
non-specific that the command is more likely to be a mistake than a
|
|
175 |
valid use case. In borderline cases, it may be persuaded to run
|
|
176 |
using a "force" option.
|
|
177 |
"""
|
|
178 |
||
179 |
description = "Delete matching translation messages from the database." |
|
180 |
loglevel = logging.INFO |
|
181 |
||
182 |
my_options = [ |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
183 |
Option( |
184 |
'-s', '--submitter', dest='submitter', |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
185 |
help="Submitter match: delete only messages with this " |
186 |
"submitter."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
187 |
Option( |
188 |
'-r', '--reviewer', dest='reviewer', |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
189 |
help="Reviewer match: delete only messages with this reviewer."), |
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
190 |
Option( |
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
191 |
'-x', '--reject-license', action='store_true', |
192 |
dest='reject_license', |
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
193 |
help="Match submitters who rejected the license agreement."), |
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
194 |
Option( |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
195 |
'-i', '--id', action='append', dest='ids', type='int', |
196 |
help="ID of message to delete. May be specified multiple " |
|
197 |
"times."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
198 |
Option( |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
199 |
'-p', '--potemplate', dest='potemplate', type='int', |
200 |
help="Template id match. Delete only messages in this " |
|
201 |
"template."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
202 |
Option( |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
203 |
'-l', '--language', dest='language', |
204 |
help="Language match. Deletes (default) or spares (with -L) " |
|
205 |
"messages in this language."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
206 |
Option( |
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
207 |
'-L', '--not-language', action='store_true', dest='not_language', |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
208 |
help="Invert language match: spare messages in given language."), |
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
209 |
Option( |
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
210 |
'-C', '--is-current-ubuntu', dest='is_current_ubuntu', |
211 |
help="Match on is_current_ubuntu value (True or False)."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
212 |
Option( |
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
213 |
'-I', '--is-current-upstream', dest='is_current_upstream', |
214 |
help="Match on is_current_upstream value (True or False)."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
215 |
Option( |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
216 |
'-m', '--msgid', dest='msgid', |
217 |
help="Match on (singular) msgid text."), |
|
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
218 |
Option( |
219 |
'-o', '--origin', dest='origin', |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
220 |
help="Origin match: delete only messages with this origin code."), |
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
221 |
Option( |
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
222 |
'-f', '--force', action='store_true', dest='force', |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
223 |
help="Override safety check on moderately unsafe action."), |
13636.1.13
by Henning Eggers
Removed ExtendedOption. |
224 |
Option( |
7131.5.2
by Jeroen Vermeulen
Finally added that --dry-run option. Removed some test noise. |
225 |
'-d', '--dry-run', action='store_true', dest='dry_run', |
11666.3.7
by Curtis Hovey
Hushed lint. |
226 |
help="Go through the motions, but don't really delete."), |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
227 |
]
|
228 |
||
229 |
def add_my_options(self): |
|
230 |
"""See `LaunchpadScript`."""
|
|
231 |
self.parser.add_options(self.my_options) |
|
232 |
||
233 |
def _check_constraints_safety(self): |
|
234 |
"""Are these options to the deletion script sufficiently safe?
|
|
7519.2.61
by Danilo Šegan
Fix remove-translations-by script and related tests. |
235 |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
236 |
:return: Boolean approval and output message. All disapprovals come
|
237 |
with an explanation; some approvals come with an informational
|
|
238 |
message.
|
|
239 |
"""
|
|
240 |
if is_nonempty_list(self.options.ids): |
|
241 |
return (True, None) |
|
242 |
if is_nonempty_string(self.options.submitter): |
|
243 |
return (True, None) |
|
244 |
if is_nonempty_string(self.options.reviewer): |
|
245 |
return (True, None) |
|
246 |
||
247 |
forced = self.options.force |
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
248 |
|
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
249 |
if is_nonempty_string(self.options.potemplate) and forced: |
250 |
return ( |
|
251 |
True, |
|
252 |
"Safety override in effect. Deleting translations for "
|
|
253 |
"template %s." % self.options.potemplate) |
|
254 |
||
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
255 |
if self.options.reject_license: |
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
256 |
if self.options.is_current_upstream == False: |
257 |
# "Remove non-is_current_upstream messages submitted by users
|
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
258 |
# who rejected the license."
|
259 |
return (True, None) |
|
260 |
||
261 |
rosettaweb_key = RosettaTranslationOrigin.ROSETTAWEB.value |
|
262 |
if self.options.origin == rosettaweb_key: |
|
263 |
# "Remove messages submitted directly in Launchpad by
|
|
264 |
# users who rejected the license."
|
|
265 |
return (True, None) |
|
266 |
||
267 |
if forced: |
|
268 |
return ( |
|
269 |
True, |
|
270 |
"Safety override in effect. Removing translations "
|
|
271 |
"by users who rejected the license, regardless of "
|
|
272 |
"origin.") |
|
273 |
||
274 |
return ( |
|
275 |
False, |
|
276 |
"To delete the translations by users who "
|
|
277 |
"rejected the translations license, specify at least "
|
|
278 |
"--origin=ROSETTAWEB or --is-imported=False.") |
|
279 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
280 |
return ( |
281 |
False, |
|
282 |
"Refusing unsafe deletion. Use matching options to constrain "
|
|
283 |
"deletion to a safe subset.") |
|
284 |
||
285 |
def main(self): |
|
286 |
"""See `LaunchpadScript`."""
|
|
13636.1.21
by Henning Eggers
Really fix script. And test. |
287 |
process_options(self.options) |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
288 |
(result, message) = self._check_constraints_safety() |
289 |
if not result: |
|
290 |
raise LaunchpadScriptFailure(message) |
|
291 |
if message is not None: |
|
292 |
self.logger.warn(message) |
|
293 |
||
7131.5.2
by Jeroen Vermeulen
Finally added that --dry-run option. Removed some test noise. |
294 |
if self.options.dry_run: |
295 |
self.logger.info("Dry run only. Not really deleting.") |
|
296 |
||
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
297 |
remove_translations(logger=self.logger, |
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
298 |
submitter=self.options.submitter, |
299 |
reject_license=self.options.reject_license, |
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
300 |
reviewer=self.options.reviewer, |
301 |
ids=self.options.ids, |
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
302 |
potemplate=self.options.potemplate, |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
303 |
language_code=self.options.language, |
304 |
not_language=self.options.not_language, |
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
305 |
is_current_ubuntu=self.options.is_current_ubuntu, |
306 |
is_current_upstream=self.options.is_current_upstream, |
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
307 |
msgid_singular=self.options.msgid, |
308 |
origin=self.options.origin) |
|
7131.5.2
by Jeroen Vermeulen
Finally added that --dry-run option. Removed some test noise. |
309 |
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
310 |
if self.options.dry_run: |
311 |
if self.txn is not None: |
|
312 |
self.txn.abort() |
|
313 |
else: |
|
7131.5.2
by Jeroen Vermeulen
Finally added that --dry-run option. Removed some test noise. |
314 |
self.txn.commit() |
6987.2.2
by Jeroen Vermeulen
Moved Launchpadscript into c.l.scripts, extended OptionParser to handle custom option types. |
315 |
|
316 |
||
12305.1.3
by Abel Deuring
fixed test failures in remove-translations-by.txt |
317 |
def warn_about_deleting_current_messages(cur, from_text, where_text, logger): |
12305.1.2
by Abel Deuring
implemented reviewer's comments |
318 |
# Deleting currently used translations is a bit harmful. Log
|
319 |
# them so that we have a clue which messages might have to be
|
|
320 |
# translated again. Note that this script tries to find
|
|
321 |
# another translation that becomes current -- but only in one
|
|
322 |
# situation: If we delete a shared translation which is current
|
|
323 |
# in Ubuntu, a shared translation which is current in upstream
|
|
324 |
# becomes the current Ubuntu translation. In other cases (deleting
|
|
325 |
# a diverged translation, deleting a shared translation which
|
|
326 |
# is current upstream) we do not attempt to find another current
|
|
327 |
# message.
|
|
328 |
if logger is not None and logger.getEffectiveLevel() <= logging.WARN: |
|
329 |
query = """ |
|
12305.1.3
by Abel Deuring
fixed test failures in remove-translations-by.txt |
330 |
SELECT
|
331 |
TranslationMessage.id, TranslationMessage.is_current_upstream,
|
|
332 |
TranslationMessage.is_current_ubuntu
|
|
333 |
FROM %s |
|
334 |
WHERE %s AND ( |
|
335 |
TranslationMessage.is_current_upstream OR
|
|
336 |
TranslationMessage.is_current_ubuntu)
|
|
337 |
""" % (from_text, where_text) |
|
12305.1.2
by Abel Deuring
implemented reviewer's comments |
338 |
cur.execute(query) |
339 |
rows = cur.fetchall() |
|
340 |
if cur.rowcount > 0: |
|
341 |
logger.warn( |
|
342 |
'Deleting messages currently in use:') |
|
343 |
for (id, is_current_upstream, is_current_ubuntu) in rows: |
|
344 |
current = [] |
|
345 |
if is_current_upstream: |
|
346 |
current.append('upstream') |
|
347 |
if is_current_ubuntu: |
|
348 |
current.append('Ubuntu') |
|
349 |
logger.warn( |
|
350 |
'Message %i is a current translation in %s' |
|
351 |
% (id, ' and '.join(current))) |
|
352 |
||
13636.1.6
by Henning Eggers
Removed lint. |
353 |
|
11666.3.7
by Curtis Hovey
Hushed lint. |
354 |
def remove_translations(logger=None, submitter=None, reviewer=None, |
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
355 |
reject_license=False, ids=None, potemplate=None, |
356 |
language_code=None, not_language=False, |
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
357 |
is_current_ubuntu=None, is_current_upstream=None, |
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
358 |
msgid_singular=None, origin=None): |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
359 |
"""Remove specified translation messages.
|
360 |
||
361 |
:param logger: Optional logger to write output to.
|
|
362 |
:param submitter: Delete only messages submitted by this person.
|
|
363 |
:param reviewer: Delete only messages reviewed by this person.
|
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
364 |
:param reject_license: Delete only messages submitted by persons who
|
365 |
have rejected the licensing agreement.
|
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
366 |
:param ids: Delete only messages with these `TranslationMessage` ids.
|
367 |
:param potemplate: Delete only messages in this template.
|
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
368 |
:param language_code: Language code. Depending on `not_language`,
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
369 |
either delete messages in this language or spare messages in this
|
370 |
language that would otherwise be deleted.
|
|
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
371 |
:param not_language: Whether to spare (True) or delete (False)
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
372 |
messages in this language.
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
373 |
:param is_current_ubuntu: Delete only messages with this is_current_ubuntu
|
374 |
value.
|
|
375 |
:param is_current_upstream: Delete only messages with this
|
|
376 |
is_current_upstream value.
|
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
377 |
:param msgid_singular: Delete only messages with this singular msgid.
|
378 |
:param origin: Delete only messages with this `TranslationOrigin` code.
|
|
379 |
||
380 |
:return: Number of messages deleted.
|
|
381 |
"""
|
|
382 |
joins = set() |
|
383 |
conditions = set() |
|
384 |
if submitter is not None: |
|
385 |
conditions.add( |
|
386 |
'TranslationMessage.submitter = %s' % sqlvalues(submitter)) |
|
387 |
if reviewer is not None: |
|
388 |
conditions.add( |
|
389 |
'TranslationMessage.reviewer = %s' % sqlvalues(reviewer)) |
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
390 |
if reject_license: |
391 |
joins.add('TranslationRelicensingAgreement') |
|
392 |
conditions.add( |
|
393 |
'TranslationMessage.submitter = '
|
|
394 |
'TranslationRelicensingAgreement.person') |
|
395 |
conditions.add( |
|
396 |
'NOT TranslationRelicensingAgreement.allow_relicensing') |
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
397 |
if ids is not None: |
398 |
conditions.add('TranslationMessage.id IN %s' % sqlvalues(ids)) |
|
399 |
if potemplate is not None: |
|
7519.2.61
by Danilo Šegan
Fix remove-translations-by script and related tests. |
400 |
joins.add('TranslationTemplateItem') |
401 |
conditions.add( |
|
402 |
'TranslationTemplateItem.potmsgset '
|
|
403 |
' = TranslationMessage.potmsgset') |
|
404 |
conditions.add( |
|
405 |
'TranslationTemplateItem.potemplate = %s' % sqlvalues(potemplate)) |
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
406 |
|
407 |
if language_code is not None: |
|
408 |
joins.add('Language') |
|
7519.2.61
by Danilo Šegan
Fix remove-translations-by script and related tests. |
409 |
conditions.add('Language.id = TranslationMessage.language') |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
410 |
language_match = compose_language_match(language_code) |
6987.2.1
by Jeroen Vermeulen
Made options processing testable, and tested. Fixed bug with --id. |
411 |
if not_language: |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
412 |
conditions.add('NOT (%s)' % language_match) |
413 |
else: |
|
414 |
conditions.add(language_match) |
|
415 |
||
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
416 |
add_bool_match( |
417 |
conditions, 'TranslationMessage.is_current_ubuntu', is_current_ubuntu) |
|
418 |
add_bool_match( |
|
419 |
conditions, 'TranslationMessage.is_current_upstream', |
|
420 |
is_current_upstream) |
|
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
421 |
|
422 |
if msgid_singular is not None: |
|
423 |
joins.add('POTMsgSet') |
|
424 |
conditions.add('POTMsgSet.id = TranslationMessage.potmsgset') |
|
425 |
joins.add('POMsgID') |
|
426 |
conditions.add('POMsgID.id = POTMsgSet.msgid_singular') |
|
427 |
conditions.add('POMsgID.msgid = %s' % sqlvalues(msgid_singular)) |
|
428 |
||
429 |
if origin is not None: |
|
430 |
conditions.add('TranslationMessage.origin = %s' % sqlvalues(origin)) |
|
431 |
||
432 |
assert len(conditions) > 0, "That would delete ALL translations, maniac!" |
|
433 |
||
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
434 |
cur = cursor() |
435 |
drop_tables(cur, 'temp_doomed_message') |
|
436 |
||
437 |
joins.add('TranslationMessage') |
|
438 |
from_text = ', '.join(joins) |
|
439 |
where_text = ' AND\n '.join(conditions) |
|
440 |
||
12305.1.3
by Abel Deuring
fixed test failures in remove-translations-by.txt |
441 |
warn_about_deleting_current_messages(cur, from_text, where_text, logger) |
12305.1.1
by Abel Deuring
Log warnings in the remove_translations script if current translations are removed. Removed the theoretically impossible case of finding a diverged translation being current in upstream which is linked to a POTemplate having a diverged translation being current in Ubuntu. |
442 |
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
443 |
# Keep track of messages we're going to delete.
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
444 |
# Don't bother indexing this. We'd more likely end up optimizing
|
445 |
# away the operator's "oh-shit-ctrl-c" time than helping anyone.
|
|
446 |
query = """ |
|
447 |
CREATE TEMP TABLE temp_doomed_message AS
|
|
448 |
SELECT TranslationMessage.id, NULL::integer AS imported_message
|
|
449 |
FROM %s |
|
450 |
WHERE %s |
|
451 |
""" % (from_text, where_text) |
|
452 |
cur.execute(query) |
|
453 |
||
12305.1.1
by Abel Deuring
Log warnings in the remove_translations script if current translations are removed. Removed the theoretically impossible case of finding a diverged translation being current in upstream which is linked to a POTemplate having a diverged translation being current in Ubuntu. |
454 |
# Note which shared messages are masked by the messages we're
|
455 |
# going to delete. We'll be making those the current ones.
|
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
456 |
query = """ |
12305.1.2
by Abel Deuring
implemented reviewer's comments |
457 |
UPDATE temp_doomed_message
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
458 |
SET imported_message = Imported.id
|
459 |
FROM TranslationMessage Doomed, TranslationMessage Imported
|
|
460 |
WHERE
|
|
461 |
Doomed.id = temp_doomed_message.id AND
|
|
462 |
-- Is alternative for the message we're about to delete.
|
|
463 |
Imported.potmsgset = Doomed.potmsgset AND
|
|
7519.2.61
by Danilo Šegan
Fix remove-translations-by script and related tests. |
464 |
Imported.language = Doomed.language AND
|
12305.1.1
by Abel Deuring
Log warnings in the remove_translations script if current translations are removed. Removed the theoretically impossible case of finding a diverged translation being current in upstream which is linked to a POTemplate having a diverged translation being current in Ubuntu. |
465 |
Imported.potemplate IS NULL AND
|
466 |
Doomed.potemplate IS NULL AND
|
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
467 |
-- Is used upstream.
|
468 |
Imported.is_current_upstream IS TRUE AND
|
|
7160.3.2
by Jeroen Vermeulen
Review changes. |
469 |
-- Was masked by the message we're about to delete.
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
470 |
Doomed.is_current_ubuntu IS TRUE AND
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
471 |
Imported.id <> Doomed.id
|
472 |
"""
|
|
473 |
cur.execute(query) |
|
474 |
||
7160.3.2
by Jeroen Vermeulen
Review changes. |
475 |
if logger is not None and logger.getEffectiveLevel() <= logging.DEBUG: |
476 |
# Dump sample of doomed messages for debugging purposes.
|
|
477 |
cur.execute(""" |
|
478 |
SELECT *
|
|
479 |
FROM temp_doomed_message
|
|
480 |
ORDER BY id
|
|
481 |
LIMIT 20
|
|
482 |
""") |
|
483 |
rows = cur.fetchall() |
|
484 |
if cur.rowcount > 0: |
|
485 |
logger.debug("Sample of messages to be deleted follows.") |
|
486 |
logger.debug("%10s %10s" % ("[message]", "[unmasks]")) |
|
487 |
for (doomed, unmasked) in rows: |
|
488 |
if unmasked is None: |
|
489 |
unmasked = '--' |
|
490 |
logger.debug("%10s %10s" % (doomed, unmasked)) |
|
491 |
||
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
492 |
cur.execute(""" |
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
493 |
DELETE FROM TranslationMessage
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
494 |
USING temp_doomed_message
|
495 |
WHERE TranslationMessage.id = temp_doomed_message.id
|
|
496 |
""") |
|
497 |
||
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
498 |
rows_deleted = cur.rowcount |
499 |
if logger is not None: |
|
500 |
if rows_deleted > 0: |
|
501 |
logger.info("Deleting %d message(s)." % rows_deleted) |
|
502 |
else: |
|
503 |
logger.warn("No rows match; not deleting anything.") |
|
504 |
||
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
505 |
cur.execute(""" |
506 |
UPDATE TranslationMessage
|
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
507 |
SET is_current_ubuntu = TRUE
|
7131.5.1
by Jeroen Vermeulen
Unmask imported messages that were obscured by ones we're deleting. Support deletion based on license answer. |
508 |
FROM temp_doomed_message
|
509 |
WHERE TranslationMessage.id = temp_doomed_message.imported_message
|
|
510 |
""") |
|
511 |
||
512 |
if cur.rowcount > 0 and logger is not None: |
|
513 |
logger.debug("Unmasking %d imported message(s)." % cur.rowcount) |
|
514 |
||
515 |
drop_tables(cur, 'temp_doomed_message') |
|
516 |
||
6934.4.1
by Jeroen Vermeulen
New function, and driver script, for admins to delete selected translation messages. |
517 |
return rows_deleted |