~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Copyright 2011 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Job for merging translations."""


__metaclass__ = type


__all__ = [
    'TranslationMergeJob',
    'TranslationSplitJob',
    ]

import logging

from lazr.lifecycle.interfaces import (
    IObjectCreatedEvent,
    IObjectDeletedEvent,
    )
import transaction
from zope.interface import (
    classProvides,
    implements,
    )

from lp.services.job.interfaces.job import (
    IRunnableJob,
    )
from lp.services.job.runner import BaseRunnableJob
from lp.translations.interfaces.translationpackagingjob import (
    ITranslationPackagingJobSource,
    )
from lp.translations.model.translationsharingjob import (
    TranslationSharingJob,
    TranslationSharingJobDerived,
    TranslationSharingJobType,
    )
from lp.translations.translationmerger import (
    TransactionManager,
    TranslationMerger,
    )
from lp.translations.utilities.translationsplitter import TranslationSplitter


class TranslationPackagingJob(TranslationSharingJobDerived, BaseRunnableJob):
    """Iterate through all Translation job types."""

    classProvides(ITranslationPackagingJobSource)

    _translation_packaging_job_types = []

    @staticmethod
    def _register_subclass(cls):
        TranslationSharingJobDerived._register_subclass(cls)
        job_type = getattr(cls, 'class_job_type', None)
        if job_type is not None:
            cls._translation_packaging_job_types.append(job_type)

    @classmethod
    def forPackaging(cls, packaging):
        """Create a TranslationPackagingJob for a Packaging.

        :param packaging: The `Packaging` to create the job for.
        :return: A `TranslationMergeJob`.
        """
        return cls.create(
            packaging.productseries, packaging.distroseries,
            packaging.sourcepackagename)

    @classmethod
    def iterReady(cls):
        """See `IJobSource`."""
        clause = TranslationSharingJob.job_type.is_in(
            cls._translation_packaging_job_types)
        return super(TranslationPackagingJob, cls).iterReady([clause])


class TranslationMergeJob(TranslationPackagingJob):
    """Job for merging translations between a product and sourcepackage."""

    implements(IRunnableJob)

    class_job_type = TranslationSharingJobType.PACKAGING_MERGE

    create_on_event = IObjectCreatedEvent

    def run(self):
        """See `IRunnableJob`."""
        logger = logging.getLogger()
        if not self.distroseries.distribution.full_functionality:
            logger.warning(
                'Skipping merge for unsupported distroseries "%s".' %
                self.distroseries.displayname)
            return
        logger.info(
            'Merging %s and %s', self.productseries.displayname,
            self.sourcepackage.displayname)
        tm = TransactionManager(transaction.manager, False)
        TranslationMerger.mergePackagingTemplates(
            self.productseries, self.sourcepackagename, self.distroseries, tm)


class TranslationSplitJob(TranslationPackagingJob):
    """Job for splitting translations between a product and sourcepackage."""

    implements(IRunnableJob)

    class_job_type = TranslationSharingJobType.PACKAGING_SPLIT

    create_on_event = IObjectDeletedEvent

    def run(self):
        """See `IRunnableJob`."""
        logger = logging.getLogger()
        logger.info(
            'Splitting %s and %s', self.productseries.displayname,
            self.sourcepackage.displayname)
        TranslationSplitter(self.productseries, self.sourcepackage).split()