queue.py 48.5 KB
Newer Older
J
New.  
James Troup 已提交
1 2
#!/usr/bin/env python

3 4
# Queue utility functions for dak
# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006  James Troup <james@nocrew.org>
J
New.  
James Troup 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

###############################################################################

22
import cPickle, errno, os, pg, re, stat, sys, time
23
import apt_inst, apt_pkg
24
import utils, database
J
New.  
James Troup 已提交
25

26
from types import *
J
New.  
James Troup 已提交
27 28 29

###############################################################################

30 31 32 33
re_isanum = re.compile (r"^\d+$")
re_default_answer = re.compile(r"\[(.*)\]")
re_fdnic = re.compile(r"\n\n")
re_bin_only_nmu = re.compile(r"\+b\d+$")
J
James Troup 已提交
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
################################################################################

# Determine what parts in a .changes are NEW

def determine_new(changes, files, projectB, warn=1):
    new = {}

    # Build up a list of potentially new things
    for file in files.keys():
        f = files[file]
        # Skip byhand elements
        if f["type"] == "byhand":
            continue
        pkg = f["package"]
        priority = f["priority"]
        section = f["section"]
        type = get_type(f)
        component = f["component"]

        if type == "dsc":
            priority = "source"
        if not new.has_key(pkg):
            new[pkg] = {}
            new[pkg]["priority"] = priority
            new[pkg]["section"] = section
            new[pkg]["type"] = type
            new[pkg]["component"] = component
            new[pkg]["files"] = []
        else:
            old_type = new[pkg]["type"]
            if old_type != type:
                # source gets trumped by deb or udeb
                if old_type == "dsc":
                    new[pkg]["priority"] = priority
                    new[pkg]["section"] = section
                    new[pkg]["type"] = type
                    new[pkg]["component"] = component
        new[pkg]["files"].append(file)
        if f.has_key("othercomponents"):
            new[pkg]["othercomponents"] = f["othercomponents"]

    for suite in changes["suite"].keys():
        suite_id = database.get_suite_id(suite)
        for pkg in new.keys():
            component_id = database.get_component_id(new[pkg]["component"])
            type_id = database.get_override_type_id(new[pkg]["type"])
            q = projectB.query("SELECT package FROM override WHERE package = '%s' AND suite = %s AND component = %s AND type = %s" % (pkg, suite_id, component_id, type_id))
            ql = q.getresult()
            if ql:
                for file in new[pkg]["files"]:
                    if files[file].has_key("new"):
                        del files[file]["new"]
                del new[pkg]

    if warn:
        if changes["suite"].has_key("stable"):
            print "WARNING: overrides will be added for stable!"
            if changes["suite"].has_key("oldstable"):
                print "WARNING: overrides will be added for OLDstable!"
        for pkg in new.keys():
            if new[pkg].has_key("othercomponents"):
                print "WARNING: %s already present in %s distribution." % (pkg, new[pkg]["othercomponents"])

    return new

################################################################################

def get_type(f):
    # Determine the type
    if f.has_key("dbtype"):
        type = f["dbtype"]
    elif f["type"] in [ "orig.tar.gz", "orig.tar.bz2", "tar.gz", "tar.bz2", "diff.gz", "diff.bz2", "dsc" ]:
        type = "dsc"
    else:
        fubar("invalid type (%s) for new.  Dazed, confused and sure as heck not continuing." % (type))

    # Validate the override type
    type_id = database.get_override_type_id(type)
    if type_id == -1:
        fubar("invalid type (%s) for new.  Say wha?" % (type))

    return type

################################################################################

# check if section/priority values are valid

def check_valid(new):
    for pkg in new.keys():
        section = new[pkg]["section"]
        priority = new[pkg]["priority"]
        type = new[pkg]["type"]
        new[pkg]["section id"] = database.get_section_id(section)
        new[pkg]["priority id"] = database.get_priority_id(new[pkg]["priority"])
        # Sanity checks
        di = section.find("debian-installer") != -1
        if (di and type != "udeb") or (not di and type == "udeb"):
            new[pkg]["section id"] = -1
        if (priority == "source" and type != "dsc") or \
           (priority != "source" and type == "dsc"):
            new[pkg]["priority id"] = -1


J
New.  
James Troup 已提交
138 139 140 141 142 143
###############################################################################

# Convenience wrapper to carry around all the package information in

class Pkg:
    def __init__(self, **kwds):
144
        self.__dict__.update(kwds)
J
New.  
James Troup 已提交
145 146

    def update(self, **kwds):
147
        self.__dict__.update(kwds)
J
New.  
James Troup 已提交
148 149 150

###############################################################################

151
class Upload:
J
New.  
James Troup 已提交
152 153

    def __init__(self, Cnf):
154 155 156
        self.Cnf = Cnf
        self.accept_count = 0
        self.accept_bytes = 0L
J
New.  
James Troup 已提交
157
        self.pkg = Pkg(changes = {}, dsc = {}, dsc_files = {}, files = {},
158
                       legacy_source_untouchable = {})
J
New.  
James Troup 已提交
159 160

        # Initialize the substitution template mapping global
161 162 163 164
        Subst = self.Subst = {}
        Subst["__ADMIN_ADDRESS__"] = Cnf["Dinstall::MyAdminAddress"]
        Subst["__BUG_SERVER__"] = Cnf["Dinstall::BugServer"]
        Subst["__DISTRO__"] = Cnf["Dinstall::MyDistribution"]
165
        Subst["__DAK_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"]
J
New.  
James Troup 已提交
166

167
        self.projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]))
168
        database.init(Cnf, self.projectB)
J
New.  
James Troup 已提交
169 170 171 172 173

    ###########################################################################

    def init_vars (self):
        for i in [ "changes", "dsc", "files", "dsc_files", "legacy_source_untouchable" ]:
174 175 176 177
            exec "self.pkg.%s.clear();" % (i)
        self.pkg.orig_tar_id = None
        self.pkg.orig_tar_location = ""
        self.pkg.orig_tar_gz = None
J
New.  
James Troup 已提交
178 179 180 181

    ###########################################################################

    def update_vars (self):
182
        dump_filename = self.pkg.changes_file[:-8]+".dak"
183 184
        dump_file = utils.open_file(dump_filename)
        p = cPickle.Unpickler(dump_file)
J
New.  
James Troup 已提交
185
        for i in [ "changes", "dsc", "files", "dsc_files", "legacy_source_untouchable" ]:
186
            exec "self.pkg.%s.update(p.load());" % (i)
J
New.  
James Troup 已提交
187
        for i in [ "orig_tar_id", "orig_tar_location" ]:
188 189
            exec "self.pkg.%s = p.load();" % (i)
        dump_file.close()
J
New.  
James Troup 已提交
190 191 192

    ###########################################################################

193 194 195
    # This could just dump the dictionaries as is, but I'd like to
    # avoid this so there's some idea of what process-accepted &
    # process-new use from process-unchecked
J
New.  
James Troup 已提交
196 197 198 199

    def dump_vars(self, dest_dir):
        for i in [ "changes", "dsc", "files", "dsc_files",
                   "legacy_source_untouchable", "orig_tar_id", "orig_tar_location" ]:
200
            exec "%s = self.pkg.%s;" % (i,i)
201
        dump_filename = os.path.join(dest_dir,self.pkg.changes_file[:-8] + ".dak")
202
        dump_file = utils.open_file(dump_filename, 'w')
J
James Troup 已提交
203
        try:
204
            os.chmod(dump_filename, 0660)
J
James Troup 已提交
205 206
        except OSError, e:
            if errno.errorcode[e.errno] == 'EPERM':
207
                perms = stat.S_IMODE(os.stat(dump_filename)[stat.ST_MODE])
J
James Troup 已提交
208
                if perms & stat.S_IROTH:
209
                    utils.fubar("%s is world readable and chmod failed." % (dump_filename))
J
James Troup 已提交
210
            else:
211
                raise
J
James Troup 已提交
212

213
        p = cPickle.Pickler(dump_file, 1)
J
New.  
James Troup 已提交
214
        for i in [ "d_changes", "d_dsc", "d_files", "d_dsc_files" ]:
215
            exec "%s = {}" % i
J
New.  
James Troup 已提交
216 217
        ## files
        for file in files.keys():
218
            d_files[file] = {}
J
New.  
James Troup 已提交
219 220 221
            for i in [ "package", "version", "architecture", "type", "size",
                       "md5sum", "component", "location id", "source package",
                       "source version", "maintainer", "dbtype", "files id",
222
                       "new", "section", "priority", "othercomponents",
223
                       "pool name", "original component" ]:
J
New.  
James Troup 已提交
224
                if files[file].has_key(i):
225
                    d_files[file][i] = files[file][i]
J
New.  
James Troup 已提交
226 227
        ## changes
        # Mandatory changes fields
228 229 230 231 232
        for i in [ "distribution", "source", "architecture", "version",
                   "maintainer", "urgency", "fingerprint", "changedby822",
                   "changedby2047", "changedbyname", "maintainer822",
                   "maintainer2047", "maintainername", "maintaineremail",
                   "closes", "changes" ]:
233
            d_changes[i] = changes[i]
J
New.  
James Troup 已提交
234
        # Optional changes fields
J
James Troup 已提交
235
        for i in [ "changed-by", "filecontents", "format", "process-new note", "adv id", "distribution-version" ]:
J
James Troup 已提交
236
            if changes.has_key(i):
237
                d_changes[i] = changes[i]
J
New.  
James Troup 已提交
238
        ## dsc
239
        for i in [ "source", "version", "maintainer", "fingerprint",
A
Anthony Towns 已提交
240
                   "uploaders", "bts changelog", "dm-upload-allowed" ]:
J
New.  
James Troup 已提交
241
            if dsc.has_key(i):
242
                d_dsc[i] = dsc[i]
J
New.  
James Troup 已提交
243 244
        ## dsc_files
        for file in dsc_files.keys():
245
            d_dsc_files[file] = {}
J
New.  
James Troup 已提交
246 247
            # Mandatory dsc_files fields
            for i in [ "size", "md5sum" ]:
248
                d_dsc_files[file][i] = dsc_files[file][i]
J
New.  
James Troup 已提交
249 250 251
            # Optional dsc_files fields
            for i in [ "files id" ]:
                if dsc_files[file].has_key(i):
252
                    d_dsc_files[file][i] = dsc_files[file][i]
J
New.  
James Troup 已提交
253 254 255

        for i in [ d_changes, d_dsc, d_files, d_dsc_files,
                   legacy_source_untouchable, orig_tar_id, orig_tar_location ]:
256 257
            p.dump(i)
        dump_file.close()
J
New.  
James Troup 已提交
258 259 260 261 262 263

    ###########################################################################

    # Set up the per-package template substitution mappings

    def update_subst (self, reject_message = ""):
264 265
        Subst = self.Subst
        changes = self.pkg.changes
266
        # If 'dak process-unchecked' crashed out in the right place, architecture may still be a string.
J
New.  
James Troup 已提交
267
        if not changes.has_key("architecture") or not isinstance(changes["architecture"], DictType):
268
            changes["architecture"] = { "Unknown" : "" }
269 270
        # and maintainer2047 may not exist.
        if not changes.has_key("maintainer2047"):
271
            changes["maintainer2047"] = self.Cnf["Dinstall::MyEmailAddress"]
J
New.  
James Troup 已提交
272

273 274 275
        Subst["__ARCHITECTURE__"] = " ".join(changes["architecture"].keys())
        Subst["__CHANGES_FILENAME__"] = os.path.basename(self.pkg.changes_file)
        Subst["__FILE_CONTENTS__"] = changes.get("filecontents", "")
J
New.  
James Troup 已提交
276 277 278

        # For source uploads the Changed-By field wins; otherwise Maintainer wins.
        if changes["architecture"].has_key("source") and changes["changedby822"] != "" and (changes["changedby822"] != changes["maintainer822"]):
279
            Subst["__MAINTAINER_FROM__"] = changes["changedby2047"]
280
            Subst["__MAINTAINER_TO__"] = "%s, %s" % (changes["changedby2047"],
281 282
                                                     changes["maintainer2047"])
            Subst["__MAINTAINER__"] = changes.get("changed-by", "Unknown")
J
New.  
James Troup 已提交
283
        else:
284 285 286
            Subst["__MAINTAINER_FROM__"] = changes["maintainer2047"]
            Subst["__MAINTAINER_TO__"] = changes["maintainer2047"]
            Subst["__MAINTAINER__"] = changes.get("maintainer", "Unknown")
J
New.  
James Troup 已提交
287
        if self.Cnf.has_key("Dinstall::TrackingServer") and changes.has_key("source"):
288
            Subst["__MAINTAINER_TO__"] += "\nBcc: %s@%s" % (changes["source"], self.Cnf["Dinstall::TrackingServer"])
J
New.  
James Troup 已提交
289

290 291
        # Apply any global override of the Maintainer field
        if self.Cnf.get("Dinstall::OverrideMaintainer"):
292 293
            Subst["__MAINTAINER_TO__"] = self.Cnf["Dinstall::OverrideMaintainer"]
            Subst["__MAINTAINER_FROM__"] = self.Cnf["Dinstall::OverrideMaintainer"]
294

295 296 297
        Subst["__REJECT_MESSAGE__"] = reject_message
        Subst["__SOURCE__"] = changes.get("source", "Unknown")
        Subst["__VERSION__"] = changes.get("version", "Unknown")
J
New.  
James Troup 已提交
298 299 300 301

    ###########################################################################

    def build_summaries(self):
302 303
        changes = self.pkg.changes
        files = self.pkg.files
J
New.  
James Troup 已提交
304

305
        byhand = summary = new = ""
J
New.  
James Troup 已提交
306 307 308 309

        # changes["distribution"] may not exist in corner cases
        # (e.g. unreadable changes files)
        if not changes.has_key("distribution") or not isinstance(changes["distribution"], DictType):
310
            changes["distribution"] = {}
J
New.  
James Troup 已提交
311

312
        override_summary ="";
313 314
        file_keys = files.keys()
        file_keys.sort()
J
New.  
James Troup 已提交
315 316 317
        for file in file_keys:
            if files[file].has_key("byhand"):
                byhand = 1
318
                summary += file + " byhand\n"
J
New.  
James Troup 已提交
319 320
            elif files[file].has_key("new"):
                new = 1
321
                summary += "(new) %s %s %s\n" % (file, files[file]["priority"], files[file]["section"])
J
New.  
James Troup 已提交
322
                if files[file].has_key("othercomponents"):
323
                    summary += "WARNING: Already present in %s distribution.\n" % (files[file]["othercomponents"])
J
New.  
James Troup 已提交
324
                if files[file]["type"] == "deb":
325
                    deb_fh = utils.open_file(file)
326
                    summary += apt_pkg.ParseSection(apt_inst.debExtractControl(deb_fh))["Description"] + '\n'
327
                    deb_fh.close()
J
New.  
James Troup 已提交
328
            else:
329
                files[file]["pool name"] = utils.poolify (changes.get("source",""), files[file]["component"])
J
New.  
James Troup 已提交
330
                destination = self.Cnf["Dir::PoolRoot"] + files[file]["pool name"] + file
331
                summary += file + "\n  to " + destination + "\n"
332 333
		if not files[file].has_key("type"):
		    files[file]["type"] = "unknown"
334
                if files[file]["type"] in ["deb", "udeb", "dsc"]:
335 336 337 338 339
                    # (queue/unchecked), there we have override entries already, use them
                    # (process-new), there we dont have override entries, use the newly generated ones.
                    override_prio = files[file].get("override priority", files[file]["priority"])
                    override_sect = files[file].get("override section", files[file]["section"])
                    override_summary += "%s - %s %s\n" % (file, override_prio, override_sect)
J
New.  
James Troup 已提交
340

341
        short_summary = summary
J
New.  
James Troup 已提交
342 343

        # This is for direport's benefit...
344
        f = re_fdnic.sub("\n .\n", changes.get("changes",""))
J
New.  
James Troup 已提交
345 346

        if byhand or new:
347
            summary += "Changes: " + f
J
New.  
James Troup 已提交
348

349 350
        summary += "\n\nOverride entries for your package:\n" + override_summary + "\n"

351
        summary += self.announce(short_summary, 0)
J
New.  
James Troup 已提交
352

353
        return (summary, short_summary)
J
New.  
James Troup 已提交
354 355 356

    ###########################################################################

357
    def close_bugs (self, summary, action):
358 359 360
        changes = self.pkg.changes
        Subst = self.Subst
        Cnf = self.Cnf
J
New.  
James Troup 已提交
361

362
        bugs = changes["closes"].keys()
J
New.  
James Troup 已提交
363

364
        if not bugs:
365
            return summary
J
New.  
James Troup 已提交
366

367
        bugs.sort()
368 369 370 371 372 373 374
        summary += "Closing bugs: "
        for bug in bugs:
            summary += "%s " % (bug)
            if action:
                Subst["__BUG_NUMBER__"] = bug
                if changes["distribution"].has_key("stable"):
                    Subst["__STABLE_WARNING__"] = """
375 376 377 378
Note that this package is not part of the released stable Debian
distribution.  It may have dependencies on other unreleased software,
or other instabilities.  Please take care if you wish to install it.
The update will eventually make its way into the next released Debian
379
distribution."""
380 381 382 383 384 385
                else:
                    Subst["__STABLE_WARNING__"] = ""
                    mail_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/process-unchecked.bug-close")
                    utils.send_mail (mail_message)
        if action:
            self.Logger.log(["closing bugs"]+bugs)
386
        summary += "\n"
387

388
        return summary
389 390 391 392

    ###########################################################################

    def announce (self, short_summary, action):
393 394 395
        Subst = self.Subst
        Cnf = self.Cnf
        changes = self.pkg.changes
396 397 398

        # Only do announcements for source uploads with a recent dpkg-dev installed
        if float(changes.get("format", 0)) < 1.6 or not changes["architecture"].has_key("source"):
399
            return ""
J
New.  
James Troup 已提交
400

401 402 403
        lists_done = {}
        summary = ""
        Subst["__SHORT_SUMMARY__"] = short_summary
404 405

        for dist in changes["distribution"].keys():
406
            list = Cnf.Find("Suite::%s::Announce" % (dist))
407
            if list == "" or lists_done.has_key(list):
408 409 410
                continue
            lists_done[list] = 1
            summary += "Announcing to %s\n" % (list)
411 412

            if action:
413
                Subst["__ANNOUNCE_LIST_ADDRESS__"] = list
414
                if Cnf.get("Dinstall::TrackingServer") and changes["architecture"].has_key("source"):
415
                    Subst["__ANNOUNCE_LIST_ADDRESS__"] = Subst["__ANNOUNCE_LIST_ADDRESS__"] + "\nBcc: %s@%s" % (changes["source"], Cnf["Dinstall::TrackingServer"])
416
                mail_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/process-unchecked.announce")
417
                utils.send_mail (mail_message)
418

J
James Troup 已提交
419
        if Cnf.FindB("Dinstall::CloseBugs"):
420
            summary = self.close_bugs(summary, action)
421

422
        return summary
J
New.  
James Troup 已提交
423 424 425 426

    ###########################################################################

    def accept (self, summary, short_summary):
427 428 429 430 431 432
        Cnf = self.Cnf
        Subst = self.Subst
        files = self.pkg.files
        changes = self.pkg.changes
        changes_file = self.pkg.changes_file
        dsc = self.pkg.dsc
J
New.  
James Troup 已提交
433 434

        print "Accepting."
435
        self.Logger.log(["Accepting changes",changes_file])
J
New.  
James Troup 已提交
436

437
        self.dump_vars(Cnf["Dir::Queue::Accepted"])
J
New.  
James Troup 已提交
438 439

        # Move all the files into the accepted directory
440 441
        utils.move(changes_file, Cnf["Dir::Queue::Accepted"])
        file_keys = files.keys()
J
New.  
James Troup 已提交
442
        for file in file_keys:
443
            utils.move(file, Cnf["Dir::Queue::Accepted"])
444
            self.accept_bytes += float(files[file]["size"])
445
        self.accept_count += 1
J
New.  
James Troup 已提交
446 447 448 449

        # Send accept mail, announce to lists, close bugs and check for
        # override disparities
        if not Cnf["Dinstall::Options::No-Mail"]:
450 451
            Subst["__SUITE__"] = ""
            Subst["__SUMMARY__"] = summary
452
            mail_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/process-unchecked.accepted")
453
            utils.send_mail(mail_message)
J
New.  
James Troup 已提交
454 455
            self.announce(short_summary, 1)

456 457 458 459 460 461 462 463 464 465 466 467

        ## Helper stuff for DebBugs Version Tracking
        if Cnf.Find("Dir::Queue::BTSVersionTrack"):
            # ??? once queue/* is cleared on *.d.o and/or reprocessed
            # the conditionalization on dsc["bts changelog"] should be
            # dropped.

            # Write out the version history from the changelog
            if changes["architecture"].has_key("source") and \
               dsc.has_key("bts changelog"):

                temp_filename = utils.temp_filename(Cnf["Dir::Queue::BTSVersionTrack"],
468 469 470 471
                                                    dotprefix=1, perms=0644)
                version_history = utils.open_file(temp_filename, 'w')
                version_history.write(dsc["bts changelog"])
                version_history.close()
472
                filename = "%s/%s" % (Cnf["Dir::Queue::BTSVersionTrack"],
473 474
                                      changes_file[:-8]+".versions")
                os.rename(temp_filename, filename)
475 476 477

            # Write out the binary -> source mapping.
            temp_filename = utils.temp_filename(Cnf["Dir::Queue::BTSVersionTrack"],
478 479
                                                dotprefix=1, perms=0644)
            debinfo = utils.open_file(temp_filename, 'w')
480
            for file in file_keys:
481
                f = files[file]
482 483 484
                if f["type"] == "deb":
                    line = " ".join([f["package"], f["version"],
                                     f["architecture"], f["source package"],
485 486 487
                                     f["source version"]])
                    debinfo.write(line+"\n")
            debinfo.close()
488
            filename = "%s/%s" % (Cnf["Dir::Queue::BTSVersionTrack"],
489 490
                                  changes_file[:-8]+".debinfo")
            os.rename(temp_filename, filename)
491

492 493 494 495 496
        self.queue_build("accepted", Cnf["Dir::Queue::Accepted"])

    ###########################################################################

    def queue_build (self, queue, path):
497 498 499 500 501 502 503 504
        Cnf = self.Cnf
        Subst = self.Subst
        files = self.pkg.files
        changes = self.pkg.changes
        changes_file = self.pkg.changes_file
        dsc = self.pkg.dsc
        file_keys = files.keys()

505
        ## Special support to enable clean auto-building of queued packages
506
        queue_id = database.get_or_set_queue_id(queue)
507

508
        self.projectB.query("BEGIN WORK")
509
        for suite in changes["distribution"].keys():
510
            if suite not in Cnf.ValueList("Dinstall::QueueBuildSuites"):
511
                continue
512
            suite_id = database.get_suite_id(suite)
513
            dest_dir = Cnf["Dir::QueueBuild"]
514
            if Cnf.FindB("Dinstall::SecurityQueueBuild"):
515
                dest_dir = os.path.join(dest_dir, suite)
516
            for file in file_keys:
517 518
                src = os.path.join(path, file)
                dest = os.path.join(dest_dir, file)
519
                if Cnf.FindB("Dinstall::SecurityQueueBuild"):
520
                    # Copy it since the original won't be readable by www-data
521
                    utils.copy(src, dest)
522 523
                else:
                    # Create a symlink to it
524
                    os.symlink(src, dest)
J
James Troup 已提交
525
                # Add it to the list of packages for later processing by apt-ftparchive
526
                self.projectB.query("INSERT INTO queue_build (suite, queue, filename, in_queue) VALUES (%s, %s, '%s', 't')" % (suite_id, queue_id, dest))
J
James Troup 已提交
527 528
            # If the .orig.tar.gz is in the pool, create a symlink to
            # it (if one doesn't already exist)
529 530 531
            if self.pkg.orig_tar_id:
                # Determine the .orig.tar.gz file name
                for dsc_file in self.pkg.dsc_files.keys():
532
                    if dsc_file.endswith(".orig.tar.gz"):
533 534
                        filename = dsc_file
                dest = os.path.join(dest_dir, filename)
535 536 537
                # If it doesn't exist, create a symlink
                if not os.path.exists(dest):
                    # Find the .orig.tar.gz in the pool
538 539
                    q = self.projectB.query("SELECT l.path, f.filename from location l, files f WHERE f.id = %s and f.location = l.id" % (self.pkg.orig_tar_id))
                    ql = q.getresult()
540
                    if not ql:
541 542 543
                        utils.fubar("[INTERNAL ERROR] Couldn't find id %s in files table." % (self.pkg.orig_tar_id))
                    src = os.path.join(ql[0][0], ql[0][1])
                    os.symlink(src, dest)
J
James Troup 已提交
544
                    # Add it to the list of packages for later processing by apt-ftparchive
545
                    self.projectB.query("INSERT INTO queue_build (suite, queue, filename, in_queue) VALUES (%s, %s, '%s', 't')" % (suite_id, queue_id, dest))
546 547
                # if it does, update things to ensure it's not removed prematurely
                else:
548
                    self.projectB.query("UPDATE queue_build SET in_queue = 't', last_used = NULL WHERE filename = '%s' AND suite = %s" % (dest, suite_id))
J
James Troup 已提交
549

550
        self.projectB.query("COMMIT WORK")
551

J
New.  
James Troup 已提交
552 553 554
    ###########################################################################

    def check_override (self):
555 556 557 558
        Subst = self.Subst
        changes = self.pkg.changes
        files = self.pkg.files
        Cnf = self.Cnf
J
New.  
James Troup 已提交
559

560 561 562 563 564 565 566
        # Abandon the check if:
        #  a) it's a non-sourceful upload
        #  b) override disparity checks have been disabled
        #  c) we're not sending mail
        if not changes["architecture"].has_key("source") or \
           not Cnf.FindB("Dinstall::OverrideDisparityCheck") or \
           Cnf["Dinstall::Options::No-Mail"]:
567
            return
J
New.  
James Troup 已提交
568

569 570 571
        summary = ""
        file_keys = files.keys()
        file_keys.sort()
J
James Troup 已提交
572
        for file in file_keys:
J
New.  
James Troup 已提交
573
            if not files[file].has_key("new") and files[file]["type"] == "deb":
574 575
                section = files[file]["section"]
                override_section = files[file]["override section"]
576
                if section.lower() != override_section.lower() and section != "-":
577 578 579
                    summary += "%s: package says section is %s, override says %s.\n" % (file, section, override_section)
                priority = files[file]["priority"]
                override_priority = files[file]["override priority"]
J
New.  
James Troup 已提交
580
                if priority != override_priority and priority != "-":
581
                    summary += "%s: package says priority is %s, override says %s.\n" % (file, priority, override_priority)
J
New.  
James Troup 已提交
582 583

        if summary == "":
584
            return
J
New.  
James Troup 已提交
585

586
        Subst["__SUMMARY__"] = summary
587
        mail_message = utils.TemplateSubst(Subst,self.Cnf["Dir::Templates"]+"/process-unchecked.override-disparity")
588
        utils.send_mail(mail_message)
J
New.  
James Troup 已提交
589 590 591

    ###########################################################################

592 593 594 595 596
    def force_reject (self, files):
        """Forcefully move files from the current directory to the
           reject directory.  If any file already exists in the reject
           directory it will be moved to the morgue to make way for
           the new file."""
J
New.  
James Troup 已提交
597 598 599 600 601 602

        Cnf = self.Cnf

        for file in files:
            # Skip any files which don't exist or which we don't have permission to copy.
            if os.access(file,os.R_OK) == 0:
603 604
                continue
            dest_file = os.path.join(Cnf["Dir::Queue::Reject"], file)
J
New.  
James Troup 已提交
605
            try:
606
                dest_fd = os.open(dest_file, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0644)
J
New.  
James Troup 已提交
607 608 609
            except OSError, e:
                # File exists?  Let's try and move it to the morgue
                if errno.errorcode[e.errno] == 'EEXIST':
610
                    morgue_file = os.path.join(Cnf["Dir::Morgue"],Cnf["Dir::MorgueReject"],file)
J
New.  
James Troup 已提交
611
                    try:
612
                        morgue_file = utils.find_next_free(morgue_file)
J
New.  
James Troup 已提交
613 614 615
                    except utils.tried_too_hard_exc:
                        # Something's either gone badly Pete Tong, or
                        # someone is trying to exploit us.
616 617 618
                        utils.warn("**WARNING** failed to move %s from the reject directory to the morgue." % (file))
                        return
                    utils.move(dest_file, morgue_file, perms=0660)
J
New.  
James Troup 已提交
619
                    try:
620
                        dest_fd = os.open(dest_file, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0644)
J
New.  
James Troup 已提交
621 622
                    except OSError, e:
                        # Likewise
623 624
                        utils.warn("**WARNING** failed to claim %s in the reject directory." % (file))
                        return
J
New.  
James Troup 已提交
625
                else:
626
                    raise
J
New.  
James Troup 已提交
627 628
            # If we got here, we own the destination file, so we can
            # safely overwrite it.
629
            utils.move(file, dest_file, 1, perms=0660)
630
            os.close(dest_fd)
631

J
New.  
James Troup 已提交
632 633 634
    ###########################################################################

    def do_reject (self, manual = 0, reject_message = ""):
J
James Troup 已提交
635 636 637
        # If we weren't given a manual rejection message, spawn an
        # editor so the user can add one in...
        if manual and not reject_message:
638
            temp_filename = utils.temp_filename()
J
James Troup 已提交
639
            editor = os.environ.get("EDITOR","vi")
640
            answer = 'E'
J
James Troup 已提交
641 642
            while answer == 'E':
                os.system("%s %s" % (editor, temp_filename))
643 644 645 646 647
                temp_fh = utils.open_file(temp_filename)
                reject_message = "".join(temp_fh.readlines())
                temp_fh.close()
                print "Reject message:"
                print utils.prefix_multi_line_string(reject_message,"  ",include_blank_lines=1)
J
James Troup 已提交
648
                prompt = "[R]eject, Edit, Abandon, Quit ?"
649
                answer = "XXX"
650
                while prompt.find(answer) == -1:
651 652
                    answer = utils.our_raw_input(prompt)
                    m = re_default_answer.search(prompt)
J
James Troup 已提交
653
                    if answer == "":
654 655 656
                        answer = m.group(1)
                    answer = answer[:1].upper()
            os.unlink(temp_filename)
J
James Troup 已提交
657
            if answer == 'A':
658
                return 1
J
James Troup 已提交
659
            elif answer == 'Q':
660
                sys.exit(0)
J
James Troup 已提交
661

J
New.  
James Troup 已提交
662 663
        print "Rejecting.\n"

664 665 666
        Cnf = self.Cnf
        Subst = self.Subst
        pkg = self.pkg
J
New.  
James Troup 已提交
667

668 669
        reason_filename = pkg.changes_file[:-8] + ".reason"
        reason_filename = Cnf["Dir::Queue::Reject"] + '/' + reason_filename
J
New.  
James Troup 已提交
670 671

        # Move all the files into the reject directory
672 673
        reject_files = pkg.files.keys() + [pkg.changes_file]
        self.force_reject(reject_files)
J
New.  
James Troup 已提交
674 675 676

        # If we fail here someone is probably trying to exploit the race
        # so let's just raise an exception ...
J
James Troup 已提交
677
        if os.path.exists(reason_filename):
678 679
            os.unlink(reason_filename)
        reason_fd = os.open(reason_filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0644)
J
New.  
James Troup 已提交
680 681

        if not manual:
682 683
            Subst["__REJECTOR_ADDRESS__"] = Cnf["Dinstall::MyEmailAddress"]
            Subst["__MANUAL_REJECT_MESSAGE__"] = ""
684
            Subst["__CC__"] = "X-DAK-Rejection: automatic (moo)\nX-Katie-Rejection: automatic (moo)"
685
            os.write(reason_fd, reject_message)
686
            reject_mail_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/queue.rejected")
J
New.  
James Troup 已提交
687 688
        else:
            # Build up the rejection email
689
            user_email_address = utils.whoami() + " <%s>" % (Cnf["Dinstall::MyAdminAddress"])
J
New.  
James Troup 已提交
690

691 692 693
            Subst["__REJECTOR_ADDRESS__"] = user_email_address
            Subst["__MANUAL_REJECT_MESSAGE__"] = reject_message
            Subst["__CC__"] = "Cc: " + Cnf["Dinstall::MyEmailAddress"]
694
            reject_mail_message = utils.TemplateSubst(Subst,Cnf["Dir::Templates"]+"/queue.rejected")
J
New.  
James Troup 已提交
695
            # Write the rejection email out as the <foo>.reason file
696
            os.write(reason_fd, reject_mail_message)
J
James Troup 已提交
697

698
        os.close(reason_fd)
J
New.  
James Troup 已提交
699 700 701

        # Send the rejection mail if appropriate
        if not Cnf["Dinstall::Options::No-Mail"]:
702
            utils.send_mail(reject_mail_message)
J
New.  
James Troup 已提交
703

704 705
        self.Logger.log(["rejected", pkg.changes_file])
        return 0
J
New.  
James Troup 已提交
706 707 708 709 710 711 712

    ################################################################################

    # Ensure that source exists somewhere in the archive for the binary
    # upload being processed.
    #
    # (1) exact match                      => 1.0-3
R
Ryan Murray 已提交
713
    # (2) Bin-only NMU                     => 1.0-3+b1 , 1.0-3.1+b1
J
New.  
James Troup 已提交
714

715 716 717
    def source_exists (self, package, source_version, suites = ["any"]):
	okay = 1
	for suite in suites:
718
	    if suite == "any":
719 720 721
	    	que = "SELECT s.version FROM source s WHERE s.source = '%s'" % \
		    (package)
	    else:
722 723 724 725 726 727
		# source must exist in suite X, or in some other suite that's
		# mapped to X, recursively... silent-maps are counted too,
		# unreleased-maps aren't.
		maps = self.Cnf.ValueList("SuiteMappings")[:]
		maps.reverse()
		maps = [ m.split() for m in maps ]
728
		maps = [ (x[1], x[2]) for x in maps
729 730 731 732 733
				if x[0] == "map" or x[0] == "silent-map" ]
		s = [suite]
		for x in maps:
			if x[1] in s and x[0] not in s:
				s.append(x[0])
734

735
		que = "SELECT s.version FROM source s JOIN src_associations sa ON (s.id = sa.source) JOIN suite su ON (sa.suite = su.id) WHERE s.source = '%s' AND (%s)" % (package, " OR ".join(["su.suite_name = '%s'" % a for a in s]))
736 737 738
            q = self.projectB.query(que)

            # Reduce the query results to a list of version numbers
739
            ql = [ i[0] for i in q.getresult() ]
740 741

            # Try (1)
742
            if source_version in ql:
743 744 745
                continue

            # Try (2)
746
            orig_source_version = re_bin_only_nmu.sub('', source_version)
747
            if orig_source_version in ql:
748 749 750 751
                continue

            # No source found...
            okay = 0
R
Ryan Murray 已提交
752
	    break
753
	return okay
J
New.  
James Troup 已提交
754 755

    ################################################################################
756
    
J
New.  
James Troup 已提交
757
    def in_override_p (self, package, component, suite, binary_type, file):
758
        files = self.pkg.files
J
New.  
James Troup 已提交
759 760

        if binary_type == "": # must be source
761
            type = "dsc"
J
New.  
James Troup 已提交
762
        else:
763
            type = binary_type
J
New.  
James Troup 已提交
764 765 766

        # Override suite name; used for example with proposed-updates
        if self.Cnf.Find("Suite::%s::OverrideSuite" % (suite)) != "":
767
            suite = self.Cnf["Suite::%s::OverrideSuite" % (suite)]
J
New.  
James Troup 已提交
768 769

        # Avoid <undef> on unknown distributions
770
        suite_id = database.get_suite_id(suite)
J
New.  
James Troup 已提交
771
        if suite_id == -1:
772
            return None
773 774
        component_id = database.get_component_id(component)
        type_id = database.get_override_type_id(type)
J
New.  
James Troup 已提交
775 776

        q = self.projectB.query("SELECT s.section, p.priority FROM override o, section s, priority p WHERE package = '%s' AND suite = %s AND component = %s AND type = %s AND o.section = s.id AND o.priority = p.id"
777 778
                           % (package, suite_id, component_id, type_id))
        result = q.getresult()
J
New.  
James Troup 已提交
779 780
        # If checking for a source package fall back on the binary override type
        if type == "dsc" and not result:
781 782
            deb_type_id = database.get_override_type_id("deb")
            udeb_type_id = database.get_override_type_id("udeb")
783
            q = self.projectB.query("SELECT s.section, p.priority FROM override o, section s, priority p WHERE package = '%s' AND suite = %s AND component = %s AND (type = %s OR type = %s) AND o.section = s.id AND o.priority = p.id"
784 785
                               % (package, suite_id, component_id, deb_type_id, udeb_type_id))
            result = q.getresult()
J
New.  
James Troup 已提交
786 787

        # Remember the section and priority so we can check them later if appropriate
788
        if result:
789 790
            files[file]["override section"] = result[0][0]
            files[file]["override priority"] = result[0][1]
J
New.  
James Troup 已提交
791

792
        return result
J
New.  
James Troup 已提交
793 794 795 796 797

    ################################################################################

    def reject (self, str, prefix="Rejected: "):
        if str:
798 799 800
            # Unlike other rejects we add new lines first to avoid trailing
            # new lines when this message is passed back up to a caller.
            if self.reject_message:
801 802
                self.reject_message += "\n"
            self.reject_message += prefix + str
J
New.  
James Troup 已提交
803

804 805
    ################################################################################

806 807 808 809
    def get_anyversion(self, query_result, suite):
        anyversion=None
        anysuite = [suite] + self.Cnf.ValueList("Suite::%s::VersionChecks::Enhances" % (suite))
        for (v, s) in query_result:
810
            if s in [ x.lower() for x in anysuite ]:
811 812 813 814 815 816
                if not anyversion or apt_pkg.VersionCompare(anyversion, v) <= 0:
                    anyversion=v
        return anyversion

    ################################################################################

817 818 819 820 821 822 823
    def cross_suite_version_check(self, query_result, file, new_version):
        """Ensure versions are newer than existing packages in target
        suites and that cross-suite version checking rules as
        set out in the conf file are satisfied."""

        # Check versions for each target suite
        for target_suite in self.pkg.changes["distribution"].keys():
824 825
            must_be_newer_than = [ i.lower for i in self.Cnf.ValueList("Suite::%s::VersionChecks::MustBeNewerThan" % (target_suite)) ]
            must_be_older_than = [ i.lower for i in self.Cnf.ValueList("Suite::%s::VersionChecks::MustBeOlderThan" % (target_suite)) ]
826 827
            # Enforce "must be newer than target suite" even if conffile omits it
            if target_suite not in must_be_newer_than:
828
                must_be_newer_than.append(target_suite)
829
            for entry in query_result:
830 831
                existent_version = entry[0]
                suite = entry[1]
832
                if suite in must_be_newer_than and \
833
                   apt_pkg.VersionCompare(new_version, existent_version) < 1:
834
                    self.reject("%s: old version (%s) in %s >= new version (%s) targeted at %s." % (file, existent_version, suite, new_version, target_suite))
835
                if suite in must_be_older_than and \
836
                   apt_pkg.VersionCompare(new_version, existent_version) > -1:
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
                    ch = self.pkg.changes
                    cansave = 0
                    if ch.get('distribution-version', {}).has_key(suite):
                        # we really use the other suite, ignoring the conflicting one ...
                        addsuite = ch["distribution-version"][suite]
                    
                        add_version = self.get_anyversion(query_result, addsuite)
                        target_version = self.get_anyversion(query_result, target_suite)
                    
                        if not add_version:
                            # not add_version can only happen if we map to a suite
                            # that doesn't enhance the suite we're propup'ing from.
                            # so "propup-ver x a b c; map a d" is a problem only if
                            # d doesn't enhance a.
                            #
                            # i think we could always propagate in this case, rather
                            # than complaining. either way, this isn't a REJECT issue
                            #
                            # And - we really should complain to the dorks who configured dak
                            self.reject("%s is mapped to, but not enhanced by %s - adding anyways" % (suite, addsuite), "Warning: ")
857 858
                            self.pkg.changes.setdefault("propdistribution", {})
                            self.pkg.changes["propdistribution"][addsuite] = 1
859 860 861 862 863 864 865 866
                            cansave = 1
                        elif not target_version:
                            # not targets_version is true when the package is NEW
                            # we could just stick with the "...old version..." REJECT
                            # for this, I think.
                            self.reject("Won't propogate NEW packages.")
                        elif apt_pkg.VersionCompare(new_version, add_version) < 0:
                            # propogation would be redundant. no need to reject though.
867
                            self.reject("ignoring versionconflict: %s: old version (%s) in %s <= new version (%s) targeted at %s." % (file, existent_version, suite, new_version, target_suite), "Warning: ")
868 869
                            cansave = 1
                        elif apt_pkg.VersionCompare(new_version, add_version) > 0 and \
870
                             apt_pkg.VersionCompare(add_version, target_version) >= 0:
871
                            # propogate!!
872 873 874
                            self.reject("Propogating upload to %s" % (addsuite), "Warning: ")
                            self.pkg.changes.setdefault("propdistribution", {})
                            self.pkg.changes["propdistribution"][addsuite] = 1
875 876 877
                            cansave = 1
                
                    if not cansave:
878
                        self.reject("%s: old version (%s) in %s <= new version (%s) targeted at %s." % (file, existent_version, suite, new_version, target_suite))
879 880 881 882

    ################################################################################

    def check_binary_against_db(self, file):
883 884
        self.reject_message = ""
        files = self.pkg.files
J
New.  
James Troup 已提交
885

886 887 888 889 890 891 892
        # Ensure version is sane
        q = self.projectB.query("""
SELECT b.version, su.suite_name FROM binaries b, bin_associations ba, suite su,
                                     architecture a
 WHERE b.package = '%s' AND (a.arch_string = '%s' OR a.arch_string = 'all')
   AND ba.bin = b.id AND ba.suite = su.id AND b.architecture = a.id"""
                                % (files[file]["package"],
893 894
                                   files[file]["architecture"]))
        self.cross_suite_version_check(q.getresult(), file, files[file]["version"])
895

J
New.  
James Troup 已提交
896
        # Check for any existing copies of the file
897 898 899 900 901 902 903 904
        q = self.projectB.query("""
SELECT b.id FROM binaries b, architecture a
 WHERE b.package = '%s' AND b.version = '%s' AND a.arch_string = '%s'
   AND a.id = b.architecture"""
                                % (files[file]["package"],
                                   files[file]["version"],
                                   files[file]["architecture"]))
        if q.getresult():
905
            self.reject("%s: can not overwrite existing copy already in the archive." % (file))
J
New.  
James Troup 已提交
906

907
        return self.reject_message
J
New.  
James Troup 已提交
908 909 910 911

    ################################################################################

    def check_source_against_db(self, file):
912 913
        self.reject_message = ""
        dsc = self.pkg.dsc
J
New.  
James Troup 已提交
914

915 916 917
        # Ensure version is sane
        q = self.projectB.query("""
SELECT s.version, su.suite_name FROM source s, src_associations sa, suite su
918 919
 WHERE s.source = '%s' AND sa.source = s.id AND sa.suite = su.id""" % (dsc.get("source")))
        self.cross_suite_version_check(q.getresult(), file, dsc.get("version"))
920

921
        return self.reject_message
J
New.  
James Troup 已提交
922 923 924

    ################################################################################

925 926 927 928 929
    # **WARNING**
    # NB: this function can remove entries from the 'files' index [if
    # the .orig.tar.gz is a duplicate of the one in the archive]; if
    # you're iterating over 'files' and call this function as part of
    # the loop, be sure to add a check to the top of the loop to
J
James Troup 已提交
930
    # ensure you haven't just tried to dereference the deleted entry.
931 932
    # **WARNING**

J
New.  
James Troup 已提交
933
    def check_dsc_against_db(self, file):
934 935 936 937 938
        self.reject_message = ""
        files = self.pkg.files
        dsc_files = self.pkg.dsc_files
        legacy_source_untouchable = self.pkg.legacy_source_untouchable
        self.pkg.orig_tar_gz = None
J
New.  
James Troup 已提交
939 940 941 942

        # Try and find all files mentioned in the .dsc.  This has
        # to work harder to cope with the multiple possible
        # locations of an .orig.tar.gz.
943 944
        # The ordering on the select is needed to pick the newest orig
        # when it exists in multiple places.
J
New.  
James Troup 已提交
945
        for dsc_file in dsc_files.keys():
946
            found = None
J
New.  
James Troup 已提交
947
            if files.has_key(dsc_file):
948 949
                actual_md5 = files[dsc_file]["md5sum"]
                actual_size = int(files[dsc_file]["size"])
J
New.  
James Troup 已提交
950 951
                found = "%s in incoming" % (dsc_file)
                # Check the file does not already exist in the archive
952
                q = self.projectB.query("SELECT f.size, f.md5sum, l.path, f.filename FROM files f, location l WHERE f.filename LIKE '%%%s%%' AND l.id = f.location ORDER BY f.id DESC" % (dsc_file))
953
                ql = q.getresult()
954 955
                # Strip out anything that isn't '%s' or '/%s$'
                for i in ql:
956
                    if i[3] != dsc_file and i[3][-(len(dsc_file)+1):] != '/'+dsc_file:
957
                        ql.remove(i)
958

959
                # "[dak] has not broken them.  [dak] has fixed a
J
New.  
James Troup 已提交
960 961 962 963 964 965 966 967
                # brokenness.  Your crappy hack exploited a bug in
                # the old dinstall.
                #
                # "(Come on!  I thought it was always obvious that
                # one just doesn't release different files with
                # the same name and version.)"
                #                        -- ajk@ on d-devel@l.d.o

968
                if ql:
969
                    # Ignore exact matches for .orig.tar.gz
970
                    match = 0
971
                    if dsc_file.endswith(".orig.tar.gz"):
972
                        for i in ql:
973 974
                            if files.has_key(dsc_file) and \
                               int(files[dsc_file]["size"]) == int(i[0]) and \
975
                               files[dsc_file]["md5sum"] == i[1]:
976 977 978 979
                                self.reject("ignoring %s, since it's already in the archive." % (dsc_file), "Warning: ")
                                del files[dsc_file]
                                self.pkg.orig_tar_gz = i[2] + i[3]
                                match = 1
980 981

                    if not match:
982
                        self.reject("can not overwrite existing copy of '%s' already in the archive." % (dsc_file))
983
            elif dsc_file.endswith(".orig.tar.gz"):
J
New.  
James Troup 已提交
984
                # Check in the pool
985 986
                q = self.projectB.query("SELECT l.path, f.filename, l.type, f.id, l.id FROM files f, location l WHERE f.filename LIKE '%%%s%%' AND l.id = f.location" % (dsc_file))
                ql = q.getresult()
987 988 989
                # Strip out anything that isn't '%s' or '/%s$'
                for i in ql:
                    if i[1] != dsc_file and i[1][-(len(dsc_file)+1):] != '/'+dsc_file:
990
                        ql.remove(i)
J
New.  
James Troup 已提交
991

992
                if ql:
993 994 995
                    # Unfortunately, we may get more than one match here if,
                    # for example, the package was in potato but had an -sa
                    # upload in woody.  So we need to choose the right one.
J
New.  
James Troup 已提交
996 997 998 999 1000

                    x = ql[0]; # default to something sane in case we don't match any or have only one

                    if len(ql) > 1:
                        for i in ql:
1001
                            old_file = i[0] + i[1]
1002
                            old_file_fh = utils.open_file(old_file)
1003
                            actual_md5 = apt_pkg.md5sum(old_file_fh)
1004
                            old_file_fh.close()
1005
                            actual_size = os.stat(old_file)[stat.ST_SIZE]
J
New.  
James Troup 已提交
1006
                            if actual_md5 == dsc_files[dsc_file]["md5sum"] and actual_size == int(dsc_files[dsc_file]["size"]):
1007
                                x = i
J
New.  
James Troup 已提交
1008
                            else:
1009
                                legacy_source_untouchable[i[3]] = ""
J
New.  
James Troup 已提交
1010

1011
                    old_file = x[0] + x[1]
1012
                    old_file_fh = utils.open_file(old_file)
1013
                    actual_md5 = apt_pkg.md5sum(old_file_fh)
1014
                    old_file_fh.close()
1015 1016 1017
                    actual_size = os.stat(old_file)[stat.ST_SIZE]
                    found = old_file
                    suite_type = x[2]
J
New.  
James Troup 已提交
1018
                    dsc_files[dsc_file]["files id"] = x[3]; # need this for updating dsc_files in install()
1019
                    # See install() in process-accepted...
1020 1021
                    self.pkg.orig_tar_id = x[3]
                    self.pkg.orig_tar_gz = old_file
J
New.  
James Troup 已提交
1022
                    if suite_type == "legacy" or suite_type == "legacy-mixed":
1023
                        self.pkg.orig_tar_location = "legacy"
J
New.  
James Troup 已提交
1024
                    else:
1025
                        self.pkg.orig_tar_location = x[4]
J
New.  
James Troup 已提交
1026
                else:
1027
                    # Not there? Check the queue directories...
J
New.  
James Troup 已提交
1028

1029
                    in_unchecked = os.path.join(self.Cnf["Dir::Queue::Unchecked"],dsc_file)
1030
                    # See process_it() in 'dak process-unchecked' for explanation of this
1031 1032 1033
		    # in_unchecked check dropped by ajt 2007-08-28, how did that
		    # ever make sense?
                    if os.path.exists(in_unchecked) and False:
1034
                        return (self.reject_message, in_unchecked)
J
New.  
James Troup 已提交
1035
                    else:
1036
                        for dir in [ "Accepted", "New", "Byhand", "ProposedUpdates", "OldProposedUpdates" ]:
1037
                            in_otherdir = os.path.join(self.Cnf["Dir::Queue::%s" % (dir)],dsc_file)
1038
                            if os.path.exists(in_otherdir):
1039
                                in_otherdir_fh = utils.open_file(in_otherdir)
1040
                                actual_md5 = apt_pkg.md5sum(in_otherdir_fh)
1041
                                in_otherdir_fh.close()
1042 1043 1044
                                actual_size = os.stat(in_otherdir)[stat.ST_SIZE]
                                found = in_otherdir
                                self.pkg.orig_tar_gz = in_otherdir
1045 1046

                    if not found:
1047 1048 1049
                        self.reject("%s refers to %s, but I can't find it in the queue or in the pool." % (file, dsc_file))
                        self.pkg.orig_tar_gz = -1
                        continue
J
New.  
James Troup 已提交
1050
            else:
1051 1052
                self.reject("%s refers to %s, but I can't find it in the queue." % (file, dsc_file))
                continue
J
New.  
James Troup 已提交
1053
            if actual_md5 != dsc_files[dsc_file]["md5sum"]:
1054
                self.reject("md5sum for %s doesn't match %s." % (found, file))
J
New.  
James Troup 已提交
1055
            if actual_size != int(dsc_files[dsc_file]["size"]):
1056
                self.reject("size for %s doesn't match %s." % (found, file))
J
New.  
James Troup 已提交
1057

1058
        return (self.reject_message, None)
J
James Troup 已提交
1059 1060

    def do_query(self, q):
1061 1062 1063 1064 1065 1066
        sys.stderr.write("query: \"%s\" ... " % (q))
        before = time.time()
        r = self.projectB.query(q)
        time_diff = time.time()-before
        sys.stderr.write("took %.3f seconds.\n" % (time_diff))
        return r