~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
151
152
153
154
#!/usr/bin/python -S
#
# Copyright 2009 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).


"""Tool for 'mass-retrying' build records.

It supports build collections based distroseries and/or distroarchseries.
"""

__metaclass__ = type

import _pythonpath

from optparse import OptionParser
import sys

from zope.component import getUtility

# Still needed fake import to stop circular imports.
import canonical.launchpad.interfaces

from canonical.database.sqlbase import ISOLATION_LEVEL_READ_COMMITTED
from lp.app.errors import NotFoundError
from canonical.launchpad.scripts import (
    execute_zcml_for_scripts, logger_options, logger)
from canonical.lp import initZopeless
from lp.buildmaster.enums import BuildStatus
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.pocket import PackagePublishingPocket


def main():
    parser = OptionParser()
    logger_options(parser)

    parser.add_option("-d", "--distribution",
                      dest="distribution", metavar="DISTRIBUTION",
                      default="ubuntu", help="distribution name")

    parser.add_option("-s", "--suite",
                      dest="suite", metavar="SUITE", default=None,
                      help="suite name")

    parser.add_option("-a", "--architecture",
                      dest="architecture", metavar="ARCH", default=None,
                      help="architecture tag")

    parser.add_option("-N", "--dry-run", action="store_true",
                      dest="dryrun", metavar="DRY_RUN", default=False,
                      help="Whether to treat this as a dry-run or not.")

    parser.add_option("-F", "--failed", action="store_true",
                      dest="failed", default=False,
                      help="Reset builds in FAILED state.")

    parser.add_option("-D", "--dep-wait", action="store_true",
                      dest="depwait", default=False,
                      help="Reset builds in DEPWAIT state.")

    parser.add_option("-C", "--chroot-wait", action="store_true",
                      dest="chrootwait", default=False,
                      help="Reset builds in CHROOTWAIT state.")

    (options, args) = parser.parse_args()

    log = logger(options, "build-mass-retry")

    log.debug("Intitialising connection.")
    execute_zcml_for_scripts()
    ztm = initZopeless(dbuser="fiera",
                       isolation=ISOLATION_LEVEL_READ_COMMITTED)

    try:
        distribution = getUtility(IDistributionSet)[options.distribution]
    except NotFoundError, info:
        log.error("Distribution not found: %s" % info)
        return 1

    try:
        if options.suite is not None:
            series, pocket = distribution.getDistroSeriesAndPocket(
                options.suite)
        else:
            series = distribution.currentseries
            pocket = PackagePublishingPocket.RELEASE
    except NotFoundError, info:
        log.error("Suite not found: %s" % info)
        return 1

    # store distroseries as the current IHasBuildRecord provider
    build_provider = series

    if options.architecture:
        try:
            dar = series[options.architecture]
        except NotFoundError, info:
            log.error(info)
            return 1

        # store distroarchseries as the current IHasBuildRecord provider
        build_provider = dar

    log.info("Initializing Build Mass-Retry for '%s/%s'"
              % (build_provider.title, pocket.name))

    requested_states_map = {
        BuildStatus.FAILEDTOBUILD : options.failed,
        BuildStatus.MANUALDEPWAIT : options.depwait,
        BuildStatus.CHROOTWAIT : options.chrootwait,
        }

    # XXX cprov 2006-08-31: one query per requested state
    # could organise it in a single one nicely if I have
    # an empty SQLResult instance, than only iteration + union()
    # would work.
    for target_state, requested in requested_states_map.items():
        if not requested:
            continue

        log.info("Processing builds in '%s'" % target_state.title)
        target_builds = build_provider.getBuildRecords(
            build_state=target_state, pocket=pocket)

        for build in target_builds:
            # Skip builds for superseded sources; they won't ever
            # actually build.
            if not build.current_source_publication:
                log.debug(
                    'Skipping superseded %s (%s)' % (build.title, build.id))
                continue

            if not build.can_be_retried:
                log.warn('Can not retry %s (%s)' % (build.title, build.id))
                continue

            log.info('Retrying %s (%s)' % (build.title, build.id))
            build.retry()

    log.info("Success.")

    if options.dryrun:
        ztm.abort()
        log.info('Dry-run.')
    else:
        ztm.commit()
        log.info("Committed")

    return 0


if __name__ == '__main__':
    sys.exit(main())