~launchpad-pqm/launchpad/devel

2733 by Canonical.com Patch Queue Manager
Upload processor. r=stevea
1
#!/usr/bin/env python
2
"""Upload processor.
3
4
Given a bunch of context information and a bunch of files, process them as
5
an upload to a distro/whatever within the launchpad.
6
"""
7
8
import _pythonpath
9
10
import os
11
import sys
12
13
from optparse import OptionParser
14
from email import message_from_string
15
16
from zope.component import getUtility
17
18
from canonical.lp import initZopeless
19
from canonical.config import config
20
from canonical.launchpad.scripts import (execute_zcml_for_scripts,
21
                                         logger, logger_options)
22
from canonical.launchpad.mail import sendmail
23
from canonical.encoding import ascii_smash
24
25
from contrib.glock import GlobalLock
26
27
from canonical.archivepublisher.nascentupload import NascentUpload, UploadError
28
from canonical.archivepublisher.uploadpolicy import (
29
    findPolicyByOptions, policy_options, UploadPolicyError)
30
31
def main():
32
    # Parse command-line arguments
33
    parser = OptionParser()
34
    logger_options(parser)
35
    policy_options(parser)
36
37
    parser.add_option("-N", "--dry-run", action="store_true",
38
                      dest="dryrun", metavar="DRY_RUN", default=False,
39
                      help="Whether to treat this as a dry-run or not.")
40
    global options
41
    (options, args) = parser.parse_args()
42
43
    global log
44
    log = logger(options, "process-upload")
45
46
    if len(args) != 1:
47
        log.error("Need to be given exactly one non-option argument. "
48
                  "Namely the fsroot for the upload.")
49
        return 1
50
51
    fsroot = args[0]
52
53
    log.debug("Acquiring lock")
54
    lock = GlobalLock('/var/lock/launchpad-process-upload.lock')
55
    lock.acquire(blocking=True)
56
57
    log.debug("Initialising connection.")
58
    global ztm
59
    ztm = initZopeless(dbuser=config.uploader.dbuser)
60
61
    execute_zcml_for_scripts()
62
63
    try:
64
        if not os.path.isdir(fsroot):
65
            raise ValueError("%s is not a directory" % fsroot)
66
        log.info("Finding policy.")
67
        policy = findPolicyByOptions(options)
68
69
        uploads = []
70
71
        for root, dirs, files in os.walk(fsroot):
72
            assert(len(dirs) == 0)
73
            for filename in files:
74
                if filename.endswith(".changes"):
75
                    uploads.append(
76
                        NascentUpload(policy, fsroot, filename, log))
77
78
        for upload in uploads:
79
            process_upload(upload)
80
81
    finally:
82
        log.debug("Rolling back any remaining transactions.")
83
        ztm.abort()
84
        log.debug("Releasing lock")
85
        lock.release()
86
87
    return 0
88
89
def send_mails(mails):
90
    """Send the mails provided using the launchpad mail infrastructure."""
91
    for mail_text in mails:
92
        mail_message = message_from_string(ascii_smash(mail_text))
93
        if mail_message['To'] is None:
94
            log.debug("Unable to parse message for rejection!")
95
            log.debug("This will cause the sendmail() to assert.")
96
            print repr(mail_text)
97
        mail_message['X-Katie'] = "Launchpad actually"
98
        if options.dryrun:
99
            log.info("Would be sending a mail:")
100
            log.info("   Subject: %s" % mail_message['Subject'])
101
            log.info("   Recipients: %s" % mail_message['To'])
102
            log.info("   Body:")
103
            for line in mail_message.get_payload().split("\n"):
104
                log.info(line)
105
        sendmail(mail_message)
106
        
107
def process_upload(upload):
108
    """Process an upload as provided."""
109
    ztm.begin()
110
    log.info("Processing upload %s" % upload.changes_filename)
111
    try:
112
        try:
113
            upload.process()
114
        except UploadPolicyError, e:
115
            upload.reject("UploadPolicyError made it out to the main loop: "
116
                          "%s " % e)
117
        except UploadError, e:
118
            upload.reject("UploadError made it out to the main loop: %s" % e)
119
        if upload.rejected:
120
            mails = upload.do_reject()
121
            ztm.abort()
122
            send_mails(mails)
123
        else:
2756 by Canonical.com Patch Queue Manager
Queue-Accepted processor and some upload tweaks to fit it. r=stevea
124
            successful, mails = upload.do_accept()
125
            if not successful:
126
                log.info("Rejection during accept. Aborting partial accept.")
127
                ztm.abort()
2733 by Canonical.com Patch Queue Manager
Upload processor. r=stevea
128
            send_mails(mails)
129
        if options.dryrun:
130
            log.info("Dry run, aborting the transaction for this upload.")
131
            ztm.abort()
132
        else:
2756 by Canonical.com Patch Queue Manager
Queue-Accepted processor and some upload tweaks to fit it. r=stevea
133
            log.info("Committing the transaction and any mails associated"
134
                     "with this upload.")
2733 by Canonical.com Patch Queue Manager
Upload processor. r=stevea
135
            ztm.commit()
136
    finally:
137
        ztm.abort()
138
139
if __name__ == '__main__':
140
    sys.exit(main())
141