launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #17346
[Merge] lp:~wgrant/launchpad/copy-translations-from-anywhere-actually into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/copy-translations-from-anywhere-actually into lp:launchpad.
Commit message:
copy-translations-from-parent.py is now copy-distroseries-translations.py, and it takes explicit --from-distribution/--from-series options. previous_series is still the default.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/copy-translations-from-anywhere-actually/+merge/231329
copy-translations-from-parent.py is now copy-distroseries-translations.py, and it takes explicit --from-distribution/--from-series options. previous_series is still the default.
--
https://code.launchpad.net/~wgrant/launchpad/copy-translations-from-anywhere-actually/+merge/231329
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/copy-translations-from-anywhere-actually into lp:launchpad.
=== modified file 'lib/lp/translations/doc/distroseries-translations-copy.txt'
--- lib/lp/translations/doc/distroseries-translations-copy.txt 2014-08-19 03:59:56 +0000
+++ lib/lp/translations/doc/distroseries-translations-copy.txt 2014-08-19 10:19:43 +0000
@@ -10,8 +10,7 @@
>>> login("foo.bar@xxxxxxxxxxxxx")
>>> foobuntu = factory.makeDistribution('foobuntu', 'Foobuntu')
>>> barty = factory.makeDistroSeries(foobuntu, '99.0', name='barty')
- >>> carty = factory.makeDistroSeries(
- ... foobuntu, '99.1', name='carty', previous_series=barty)
+ >>> carty = factory.makeDistroSeries(foobuntu, '99.1', name='carty')
Functions to create source packages, templates and and translations.
@@ -66,7 +65,7 @@
We need a transaction manager (in this case a fake one) to make the copy work.
>>> from lp.testing.faketransaction import FakeTransaction
- >>> transaction_stub = FakeTransaction()
+ >>> txn = FakeTransaction()
Performing the migration
@@ -79,7 +78,8 @@
>>> from lp.services.log.logger import DevNullLogger
>>> from lp.translations.model.distroseries_translations_copy import (
... copy_active_translations)
- >>> copy_active_translations(carty, transaction_stub, DevNullLogger())
+ >>> logger = DevNullLogger()
+ >>> copy_active_translations(barty, carty, txn, logger)
All current templates were copied from the parent series but the deactivated
template template3 was not copied.
@@ -129,11 +129,11 @@
again as it only operates on distroseries without any translation templates.
Because of message sharing incremental copies are no longer needed.
- >>> copy_active_translations(carty, transaction_stub, DevNullLogger())
+ >>> copy_active_translations(barty, carty, txn, logger)
Traceback (most recent call last):
...
AssertionError:
- The child series must not yet have any translation templates.
+ The target series must not yet have any translation templates.
Running the script
@@ -160,7 +160,7 @@
>>> from lp.testing.script import run_script
>>> returnvalue, output, error_output = run_script(
- ... 'scripts/copy-translations-from-parent.py',
+ ... 'scripts/copy-distroseries-translations.py',
... ['--distribution=foobuntu', '--series=darty'])
>>> returnvalue
1
@@ -188,7 +188,7 @@
>>> transaction.abort()
>>> darty = DistroSeries.get(darty_id)
>>> returnvalue, output, error_output = run_script(
- ... 'scripts/copy-translations-from-parent.py',
+ ... 'scripts/copy-distroseries-translations.py',
... ['--distribution=foobuntu', '--series=darty', '--force'])
>>> returnvalue
0
@@ -196,7 +196,8 @@
INFO Creating lockfile:
/var/lock/launchpad-copy-missing-translations-foobuntu-darty.lock
INFO Starting...
- INFO Populating blank distroseries darty with translations from barty.
+ INFO Populating blank distroseries foobuntu darty with
+ translations from foobuntu barty.
INFO Extracting from potemplate into
"temp_potemplate_holding_foobuntu_darty"...
INFO Extracting from translationtemplateitem into
@@ -231,3 +232,40 @@
>>> print sorted([template.name for template in dartempls])
[u'template1', u'template2']
+The script defaults to copying from the given series' previous_series,
+but that can be overridden.
+
+ >>> grumpy = factory.makeDistroSeries(
+ ... distribution=factory.makeDistribution(name="notbuntu"),
+ ... name='grumpy')
+ >>> grumpy_id = grumpy.id
+ >>> transaction.commit()
+
+ >>> returnvalue, output, error_output = run_script(
+ ... 'scripts/copy-distroseries-translations.py',
+ ... ['--distribution=notbuntu', '--series=grumpy'])
+ >>> returnvalue
+ 2
+ >>> print error_output
+ INFO Creating lockfile:
+ /var/lock/launchpad-copy-missing-translations-notbuntu-grumpy.lock
+ Usage: copy-distroseries-translations.py [options]
+ copy-distroseries-translations.py: error: No source series specified
+ and target has no previous series.
+ <BLANKLINE>
+
+ >>> returnvalue, output, error_output = run_script(
+ ... 'scripts/copy-distroseries-translations.py',
+ ... ['--distribution=notbuntu', '--series=grumpy',
+ ... '--from-distribution=foobuntu' , '--from-series=darty'])
+ >>> returnvalue
+ 0
+ >>> print error_output
+ INFO Creating lockfile:
+ /var/lock/launchpad-copy-missing-translations-notbuntu-grumpy.lock
+ INFO Starting...
+ INFO Populating blank distroseries notbuntu grumpy with
+ translations from foobuntu darty.
+ ...
+ INFO Done.
+ <BLANKLINE>
=== modified file 'lib/lp/translations/model/distroseries_translations_copy.py'
--- lib/lp/translations/model/distroseries_translations_copy.py 2012-05-08 03:10:09 +0000
+++ lib/lp/translations/model/distroseries_translations_copy.py 2014-08-19 10:19:43 +0000
@@ -1,7 +1,7 @@
# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
-"""Functions to copy translations from previous to child distroseries."""
+"""Functions to copy translations from one distroseries to another."""
__metaclass__ = type
@@ -47,16 +47,18 @@
""" % params)
-def copy_active_translations(child, transaction, logger):
- """Furnish untranslated child `DistroSeries` with previous series's
- translations.
+def copy_active_translations(source, target, transaction, logger):
+ """Populate target `DistroSeries` with source series' translations.
+
+ The target must not already have any translations.
This method uses `MultiTableCopy` to copy data.
- Translation data for the new series ("child") is first copied into holding
- tables called e.g. "temp_POTemplate_holding_ubuntu_feisty" and processed
- there. Then, near the end of the procedure, the contents of these holding
- tables are all poured back into the original tables.
+ Translation data for the new series ("target") is first copied into
+ holding tables called e.g. "temp_POTemplate_holding_ubuntu_feisty"
+ and processed there. Then, near the end of the procedure, the
+ contents of these holding tables are all poured back into the
+ original tables.
If this procedure fails, it may leave holding tables behind. This was
done deliberately to leave some forensics information for failures, and
@@ -68,24 +70,19 @@
process of being poured back into its source table. In that case the
sensible thing to do is probably to continue pouring it.
"""
- previous_series = child.previous_series
- if previous_series is None:
- # We don't have a previous series from where we could copy
- # translations.
- return
-
translation_tables = ['potemplate', 'translationtemplateitem', 'pofile']
- full_name = "%s_%s" % (child.distribution.name, child.name)
+ full_name = "%s_%s" % (target.distribution.name, target.name)
copier = MultiTableCopy(full_name, translation_tables, logger=logger)
# Incremental copy of updates is no longer supported
- assert not child.has_translation_templates, (
- "The child series must not yet have any translation templates.")
+ assert not target.has_translation_templates, (
+ "The target series must not yet have any translation templates.")
logger.info(
- "Populating blank distroseries %s with translations from %s." %
- (child.name, previous_series.name))
+ "Populating blank distroseries %s %s with translations from %s %s." %
+ (target.distribution.name, target.name, source.distribution.name,
+ source.name))
# 1. Extraction phase--for every table involved (called a "source table"
# in MultiTableCopy parlance), we create a "holding table." We fill that
@@ -110,7 +107,7 @@
# Copy relevant POTemplates from existing series into a holding table,
# complete with their original id fields.
- where = 'distroseries = %s AND iscurrent' % quote(previous_series)
+ where = 'distroseries = %s AND iscurrent' % quote(source)
copier.extract('potemplate', [], where)
# Now that we have the data "in private," where nobody else can see it,
@@ -126,14 +123,14 @@
datecreated =
timezone('UTC'::text,
('now'::text)::timestamp(6) with time zone)
- ''' % (copier.getHoldingTableName('potemplate'), quote(child)))
+ ''' % (copier.getHoldingTableName('potemplate'), quote(target)))
# Copy each TranslationTemplateItem whose template we copied, and let
# MultiTableCopy replace each potemplate reference with a reference to
# our copy of the original POTMsgSet's potemplate.
copier.extract('translationtemplateitem', ['potemplate'], 'sequence > 0')
- # Copy POFiles, making them refer to the child's copied POTemplates.
+ # Copy POFiles, making them refer to the target's copied POTemplates.
copier.extract(
'pofile', ['potemplate'],
batch_pouring_callback=omit_redundant_pofiles)
=== modified file 'lib/lp/translations/scripts/copy_distroseries_translations.py'
--- lib/lp/translations/scripts/copy_distroseries_translations.py 2014-08-19 05:13:06 +0000
+++ lib/lp/translations/scripts/copy_distroseries_translations.py 2014-08-19 10:19:43 +0000
@@ -73,16 +73,16 @@
series.defer_translation_imports = self.defer_translation_imports
-def copy_distroseries_translations(distroseries, txn, logger):
- """Copy `distroseries` translations from its parents.
+def copy_distroseries_translations(source, target, txn, logger):
+ """Copy translations into a new `DistroSeries`.
- Wraps around `DistroSeries.copyMissingTranslationsFromParent`, but also
- ensures that the `hide_all_translations` and `defer_translation_imports`
- flags are set. After copying they are restored to their previous state.
+ Wraps around `copy_active_translations`, but also ensures that the
+ `hide_all_translations` and `defer_translation_imports` flags are
+ set. After copying they are restored to their previous state.
"""
statekeeper = SeriesStateKeeper()
- statekeeper.prepare(distroseries)
- name = distroseries.name
+ statekeeper.prepare(target)
+ name = target.name
txn.commit()
txn.begin()
@@ -90,15 +90,15 @@
try:
# Do the actual work.
- assert distroseries.defer_translation_imports, (
+ assert target.defer_translation_imports, (
"defer_translation_imports not set!"
" That would corrupt translation data mixing new imports"
" with the information being copied.")
- assert distroseries.hide_all_translations, (
+ assert target.hide_all_translations, (
"hide_all_translations not set!"
" That would allow users to see and modify incomplete"
" translation state.")
- copy_active_translations(distroseries, txn, logger)
+ copy_active_translations(source, target, txn, logger)
except:
copy_failed = True
# Give us a fresh transaction for proper cleanup.
=== modified file 'lib/lp/translations/tests/test_distroseries_translations_copy.py'
--- lib/lp/translations/tests/test_distroseries_translations_copy.py 2012-06-14 05:18:22 +0000
+++ lib/lp/translations/tests/test_distroseries_translations_copy.py 2014-08-19 10:19:43 +0000
@@ -38,8 +38,7 @@
# place and does not copy it. (Nor does it raise an error.)
existing_series = self.factory.makeDistroSeries(name='existing')
new_series = self.factory.makeDistroSeries(
- name='new', distribution=existing_series.distribution,
- previous_series=existing_series)
+ name='new', distribution=existing_series.distribution)
template = self.factory.makePOTemplate(distroseries=existing_series)
pofile = self.factory.makePOFile(potemplate=template)
self.factory.makeCurrentTranslationMessage(
@@ -62,7 +61,8 @@
MultiTableCopy._pourTable = pour_or_stop_at_pofile
try:
copy_active_translations(
- new_series, FakeTransaction(), DevNullLogger())
+ existing_series, new_series, FakeTransaction(),
+ DevNullLogger())
except EarlyExit as e:
pour_args = e.args
pour_kwargs = e.kwargs
=== renamed file 'scripts/copy-translations-from-parent.py' => 'scripts/copy-distroseries-translations.py'
--- scripts/copy-translations-from-parent.py 2013-03-25 23:39:42 +0000
+++ scripts/copy-distroseries-translations.py 2014-08-19 10:19:43 +0000
@@ -32,9 +32,17 @@
def add_my_options(self):
self.parser.add_option('-d', '--distribution', dest='distro',
default='ubuntu',
- help='Name of distribution to copy translations in.')
+ help='The target distribution.')
self.parser.add_option('-s', '--series', dest='series',
- help='Name of distroseries whose translations should be updated')
+ help='The target distroseries.')
+ self.parser.add_option('--from-distribution', dest='from_distro',
+ help=(
+ "The source distribution (if omitted, target's previous "
+ "series will be used)."))
+ self.parser.add_option('--from-series', dest='from_series',
+ help=(
+ "The source distroseries (if omitted, target's previous "
+ "series will be used)."))
self.parser.add_option('-f', '--force', dest='force',
action="store_true", default=False,
help="Don't check if target's UI and imports are blocked; "
@@ -46,13 +54,23 @@
return getUtility(IDistributionSet)[self.options.distro][series]
def main(self):
- series = self._getTargetSeries()
+ target = getUtility(IDistributionSet)[self.options.distro][
+ self.options.series]
+ if self.options.from_distro:
+ source = getUtility(IDistributionSet)[self.options.from_distro][
+ self.options.from_series]
+ else:
+ source = target.previous_series
+ if source is None:
+ self.parser.error(
+ "No source series specified and target has no previous "
+ "series.")
# Both translation UI and imports for this series should be blocked
# while the copy is in progress, to reduce the chances of deadlocks or
# other conflicts.
blocked = (
- series.hide_all_translations and series.defer_translation_imports)
+ target.hide_all_translations and target.defer_translation_imports)
if not blocked and not self.options.force:
self.txn.abort()
self.logger.error(
@@ -66,7 +84,7 @@
self.logger.info('Starting...')
# Actual work is done here.
- copy_distroseries_translations(series, self.txn, self.logger)
+ copy_distroseries_translations(source, target, self.txn, self.logger)
# We would like to update the DistroRelase statistics, but it takes
# too long so this should be done after.
Follow ups