19
19
'splitComponentAndSection',
24
from debian.deb822 import Deb822Dict
30
from debian.deb822 import Deb822Dict
31
31
from zope.component import getUtility
33
from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
34
from canonical.librarian.utils import filechunks
33
35
from lp.app.errors import NotFoundError
34
36
from lp.archiveuploader.utils import (
35
37
determine_source_file_type,
86
86
self.future_files = {}
87
87
self.ancient_files = {}
89
def callback(self, member, data):
90
"""Callback designed to cope with apt_inst.TarFile.go.
89
def callback(self, kind, name, link, mode, uid, gid, size, mtime,
91
"""Callback designed to cope with apt_inst.debExtract.
92
93
It check and store timestamp details of the extracted DEB.
94
self.check_cutoff(member.name, member.mtime)
95
self.check_cutoff(name, mtime)
96
97
def check_cutoff(self, name, mtime):
97
98
"""Check the timestamp details of the supplied file.
304
305
They need to satisfy at least the NEW queue constraints that includes
305
306
SourcePackageRelease creation, so component and section need to exist.
306
Even if they might be overridden in the future.
307
Even if they might be overriden in the future.
308
309
NascentUploadFile.__init__(
309
310
self, filepath, digest, size, component_and_section,
530
531
def extractAndParseControl(self):
531
"""Extract and parse control information."""
532
"""Extract and parse tcontrol information."""
533
deb_file = open(self.filepath, "r")
533
deb_file = apt_inst.DebFile(self.filepath)
534
control_file = deb_file.control.extractdata("control")
535
control_lines = apt_pkg.TagSection(control_file)
535
control_file = apt_inst.debExtractControl(deb_file)
536
control_lines = apt_pkg.ParseSection(control_file)
536
537
except (SystemExit, KeyboardInterrupt):
539
541
yield UploadError(
540
"%s: extracting control file raised %s, giving up."
542
"%s: debExtractControl() raised %s, giving up."
541
543
% (self.filename, sys.exc_type))
544
546
for mandatory_field in self.mandatory_fields:
545
if control_lines.find(mandatory_field) is None:
547
if control_lines.Find(mandatory_field) is None:
546
548
yield UploadError(
547
549
"%s: control file lacks mandatory field %r"
548
550
% (self.filename, mandatory_field))
550
552
for key in control_lines.keys():
551
control[key] = control_lines.find(key)
553
control[key] = control_lines.Find(key)
552
554
self.parseControl(control)
554
556
def parseControl(self, control):
704
706
yield UploadError(
705
707
"%s: second chunk is %s, expected control.tar.gz." % (
706
708
self.filename, control_tar))
707
if data_tar not in ("data.tar.gz", "data.tar.bz2", "data.tar.lzma",
709
if data_tar not in ("data.tar.gz", "data.tar.bz2", "data.tar.lzma"):
709
710
yield UploadError(
710
711
"%s: third chunk is %s, expected data.tar.gz, "
711
"data.tar.bz2, data.tar.lzma or data.tar.xz." %
712
(self.filename, data_tar))
714
# xz-compressed debs must pre-depend on dpkg >= 1.15.6~.
715
XZ_REQUIRED_DPKG_VER = '1.15.6~'
716
if data_tar == "data.tar.xz":
719
parsed_deps = apt_pkg.parse_depends(
720
self.control['Pre-Depends'])
721
except (ValueError, TypeError):
723
"Can't parse Pre-Depends in the control file.")
726
# Go past the for loop and yield the error below.
729
for token in parsed_deps:
731
name, version, relation = token[0]
733
yield("APT error processing token '%r' from Pre-Depends.")
737
# VersionCompare returns values similar to cmp;
738
# negative if first < second, zero if first ==
739
# second and positive if first > second.
740
if apt_pkg.version_compare(
741
version, XZ_REQUIRED_DPKG_VER) >= 0:
742
# Pre-Depends dpkg is fine.
746
"Pre-Depends dpkg version should be >= %s "
747
"when using xz compression." %
748
XZ_REQUIRED_DPKG_VER)
752
"Require Pre-Depends: dpkg (>= %s) when using xz "
753
"compression." % XZ_REQUIRED_DPKG_VER)
712
"data.tar.bz2 or data.tar.lzma." % (self.filename, data_tar))
755
714
def verifyDebTimestamp(self):
756
715
"""Check specific DEB format timestamp checks."""
763
722
tar_checker = TarFileDateChecker(future_cutoff, past_cutoff)
764
723
tar_checker.reset()
766
deb_file = apt_inst.DebFile(self.filepath)
767
except SystemError, error:
768
# We get an error from the constructor if the .deb does not
769
# contain all the expected top-level members (debian-binary,
770
# control.tar.gz, and data.tar.*).
771
yield UploadError(error)
773
deb_file.control.go(tar_checker.callback)
774
deb_file.data.go(tar_checker.callback)
775
future_files = tar_checker.future_files.keys()
777
first_file = future_files[0]
778
timestamp = time.ctime(tar_checker.future_files[first_file])
780
"%s: has %s file(s) with a time stamp too "
781
"far into the future (e.g. %s [%s])."
782
% (self.filename, len(future_files), first_file,
785
ancient_files = tar_checker.ancient_files.keys()
787
first_file = ancient_files[0]
788
timestamp = time.ctime(tar_checker.ancient_files[first_file])
790
"%s: has %s file(s) with a time stamp too "
791
"far in the past (e.g. %s [%s])."
792
% (self.filename, len(ancient_files), first_file,
725
deb_file = open(self.filepath, "rb")
726
apt_inst.debExtract(deb_file, tar_checker.callback,
728
# Only one of these files is present in the archive, so loop
729
# until we find one of them, otherwise fail.
730
data_files = ("data.tar.gz", "data.tar.bz2", "data.tar.lzma")
731
for file in data_files:
734
apt_inst.debExtract(deb_file, tar_checker.callback, file)
740
future_files = tar_checker.future_files.keys()
742
first_file = future_files[0]
743
timestamp = time.ctime(
744
tar_checker.future_files[first_file])
746
"%s: has %s file(s) with a time stamp too "
747
"far into the future (e.g. %s [%s])."
748
% (self.filename, len(future_files), first_file,
751
ancient_files = tar_checker.ancient_files.keys()
753
first_file = ancient_files[0]
754
timestamp = time.ctime(
755
tar_checker.ancient_files[first_file])
757
"%s: has %s file(s) with a time stamp too "
758
"far in the past (e.g. %s [%s])."
759
% (self.filename, len(ancient_files), first_file,
765
"Could not find data tarball in %s" % self.filename)
794
767
except (SystemExit, KeyboardInterrupt):
796
769
except Exception, error:
831
805
"Unable to find source package %s/%s in %s" % (
832
806
self.source_name, self.source_version, distroseries.name))
834
809
def verifySourcePackageRelease(self, sourcepackagerelease):
835
810
"""Check if the given ISourcePackageRelease matches the context."""
836
811
assert 'source' in self.changes.architectures, (