~launchpad-pqm/launchpad/devel

7675.845.13 by Edwin Grubbs
Added cron script.
1
#!/usr/bin/python -S
2
#
3
# Copyright 2009, 2010 Canonical Ltd.  This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
5
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
6
"""Handle jobs for multiple job source classes."""
7675.845.13 by Edwin Grubbs
Added cron script.
7
8
__metaclass__ = type
9
7675.845.20 by Edwin Grubbs
Formatted imports and delinted.
10
from optparse import IndentedHelpFormatter
7675.845.15 by Edwin Grubbs
Better cron script.
11
import os
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
12
import subprocess
7675.845.15 by Edwin Grubbs
Better cron script.
13
import sys
7675.845.16 by Edwin Grubbs
not working
14
import textwrap
7675.845.15 by Edwin Grubbs
Better cron script.
15
7675.845.20 by Edwin Grubbs
Formatted imports and delinted.
16
import _pythonpath
7675.845.15 by Edwin Grubbs
Better cron script.
17
7675.845.20 by Edwin Grubbs
Formatted imports and delinted.
18
from canonical.config import config
13851.3.1 by Gavin Panella
Make --exclude work with process-job-source-groups.py.
19
from canonical.launchpad.helpers import english_list
7675.845.16 by Edwin Grubbs
not working
20
from lp.services.propertycache import cachedproperty
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
21
from lp.services.scripts.base import LaunchpadCronScript
7675.845.15 by Edwin Grubbs
Better cron script.
22
23
7675.845.16 by Edwin Grubbs
not working
24
class LongEpilogHelpFormatter(IndentedHelpFormatter):
25
    """Preserve newlines in epilog."""
26
27
    def format_epilog(self, epilog):
28
        if epilog:
29
            return '\n%s\n' % epilog
30
        else:
31
            return ""
32
33
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
34
class ProcessJobSourceGroups(LaunchpadCronScript):
7675.845.16 by Edwin Grubbs
not working
35
    """Handle each job source in a separate process with ProcessJobSource."""
7675.845.15 by Edwin Grubbs
Better cron script.
36
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
37
    def add_my_options(self):
38
        self.parser.usage = "%prog [ -e JOB_SOURCE ] GROUP [GROUP]..."
39
        self.parser.epilog = (
7675.845.16 by Edwin Grubbs
not working
40
            textwrap.fill(
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
41
            "At least one group must be specified. Excluding job sources "
42
            "is useful when you want to run all the other job sources in "
43
            "a group.")
7675.845.16 by Edwin Grubbs
not working
44
            + "\n\n" + self.group_help)
45
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
46
        self.parser.formatter = LongEpilogHelpFormatter()
47
        self.parser.add_option(
7675.845.16 by Edwin Grubbs
not working
48
            '-e', '--exclude', dest='excluded_job_sources',
49
            metavar="JOB_SOURCE", default=[], action='append',
50
            help="Exclude specific job sources.")
7675.845.22 by Edwin Grubbs
Suggestions from reviewer.
51
        self.parser.add_option(
52
            '--wait', dest='do_wait', default=False, action='store_true',
53
            help="Wait for the child processes to finish. This is useful "
54
                 "for testing, but it shouldn't be used in a cronjob, since "
55
                 "it would prevent the cronjob from processing new jobs "
56
                 "if just one of the child processes is still processing, "
57
                 "and each process only handles a single job source class.")
7675.845.15 by Edwin Grubbs
Better cron script.
58
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
59
    def main(self):
60
        selected_groups = self.args
61
        if len(selected_groups) == 0:
62
            self.parser.print_help()
7675.845.16 by Edwin Grubbs
not working
63
            sys.exit(1)
64
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
65
        selected_job_sources = set()
66
        # Include job sources from selected groups.
67
        for group in selected_groups:
68
            selected_job_sources.update(self.grouped_sources[group])
69
        # Then, exclude job sources.
70
        for source in self.options.excluded_job_sources:
71
            if source not in selected_job_sources:
13851.3.1 by Gavin Panella
Make --exclude work with process-job-source-groups.py.
72
                self.logger.info(
73
                    '%r is not in %s' % (
74
                        source, english_list(selected_groups, "or")))
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
75
            else:
76
                selected_job_sources.remove(source)
77
        # Process job sources.
78
        command = os.path.join(
79
            os.path.dirname(sys.argv[0]), 'process-job-source.py')
80
        child_args = [command]
7675.845.15 by Edwin Grubbs
Better cron script.
81
        if self.options.verbose:
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
82
            child_args.append('-v')
83
        children = []
84
        for job_source in selected_job_sources:
85
            child = subprocess.Popen(child_args + [job_source])
86
            children.append(child)
7675.845.23 by Edwin Grubbs
Addressed more review comments.
87
        if self.options.do_wait:
88
            for child in children:
89
                child.wait()
7675.845.15 by Edwin Grubbs
Better cron script.
90
7675.845.16 by Edwin Grubbs
not working
91
    @cachedproperty
7675.845.15 by Edwin Grubbs
Better cron script.
92
    def all_job_sources(self):
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
93
        job_sources = config['process-job-source-groups'].job_sources
7675.845.15 by Edwin Grubbs
Better cron script.
94
        return [job_source.strip() for job_source in job_sources.split(',')]
7675.845.13 by Edwin Grubbs
Added cron script.
95
7675.845.16 by Edwin Grubbs
not working
96
    @cachedproperty
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
97
    def grouped_sources(self):
7675.845.16 by Edwin Grubbs
not working
98
        groups = {}
99
        for source in self.all_job_sources:
100
            if source not in config:
101
                continue
102
            section = config[source]
103
            group = groups.setdefault(section.crontab_group, [])
104
            group.append(source)
105
        return groups
106
107
    @cachedproperty
108
    def group_help(self):
109
        return '\n\n'.join(
110
            'Group: %s\n    %s' % (group, '\n    '.join(sources))
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
111
            for group, sources in sorted(self.grouped_sources.items()))
7675.845.16 by Edwin Grubbs
not working
112
7675.845.13 by Edwin Grubbs
Added cron script.
113
114
if __name__ == '__main__':
7675.845.17 by Edwin Grubbs
Working as two separate cron scripts.
115
    script = ProcessJobSourceGroups()
116
    script.lock_and_run()