~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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# 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',
    'TranslationTemplateChangeJob',
    ]

import logging

from lazr.lifecycle.interfaces import (
    IObjectCreatedEvent,
    IObjectDeletedEvent,
    IObjectModifiedEvent,
    )
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,
    TranslationTemplateSplitter,
    )


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.info(
                '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()


class TranslationTemplateChangeJob(TranslationPackagingJob):
    """Job for merging/splitting translations when template is changed."""

    implements(IRunnableJob)

    class_job_type = TranslationSharingJobType.TEMPLATE_CHANGE

    create_on_event = IObjectModifiedEvent

    @classmethod
    def forPOTemplate(cls, potemplate):
        """Create a TranslationTemplateChangeJob for a POTemplate.

        :param potemplate: The `POTemplate` to create the job for.
        :return: A `TranslationTemplateChangeJob`.
        """
        return cls.create(potemplate=potemplate)

    def run(self):
        """See `IRunnableJob`."""
        logger = logging.getLogger()
        logger.info("Sanitizing translations for '%s'" % (
                self.potemplate.displayname))
        TranslationTemplateSplitter(self.potemplate).split()
        tm = TransactionManager(transaction.manager, False)
        TranslationMerger.mergeModifiedTemplates(self.potemplate, tm)