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