]> git.decadent.org.uk Git - dak.git/blob - daklib/binary.py
Merge branch 'master' into content_generation, make changes based on Joerg's review
[dak.git] / daklib / binary.py
1 #!/usr/bin/python
2
3 """
4 Functions related debian binary packages
5
6 @contact: Debian FTPMaster <ftpmaster@debian.org>
7 @copyright: 2009  Mike O'Connor <stew@debian.org>
8 @license: GNU General Public License version 2 or later
9 """
10
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25 ################################################################################
26
27 import os
28 import shutil
29 import tempfile
30 import tarfile
31 import commands
32 import traceback
33 from debian_bundle import deb822
34 from dbconn import DBConn
35
36 class Binary(object):
37     def __init__(self, filename):
38         self.filename = filename
39         self.tmpdir = None
40         self.chunks = None
41
42     def __del__(self):
43         # we need to remove the temporary directory, if we created one
44         if self.tmpdir and os.path.exists(self.tmpdir):
45             shutil.rmtree(self.tmpdir)
46
47     def __scan_ar(self):
48         # get a list of the ar contents
49         if not self.chunks:
50
51             cmd = "ar t %s" % (self.filename)
52
53             (result, output) = commands.getstatusoutput(cmd)
54             if result != 0:
55                 rejected = True
56                 reject("%s: 'ar t' invocation failed." % (self.filename))
57                 reject(utils.prefix_multi_line_string(output, " [ar output:] "), "")
58             self.chunks = output.split('\n')
59
60
61
62     def __unpack(self):
63         # Internal function which extracts the contents of the .ar to
64         # a temporary directory
65
66         if not self.tmpdir:
67             tmpdir = tempfile.mkdtemp()
68             cwd = os.getcwd()
69             try:
70                 os.chdir( tmpdir )
71                 cmd = "ar x %s %s %s" % (os.path.join(cwd,self.filename), self.chunks[1], self.chunks[2])
72                 (result, output) = commands.getstatusoutput(cmd)
73                 if result != 0:
74                     reject("%s: '%s' invocation failed." % (filename, cmd))
75                     reject(utils.prefix_multi_line_string(output, " [ar output:] "), "")
76                 else:
77                     self.tmpdir = tmpdir
78
79             finally:
80                 os.chdir( cwd )
81
82     def valid_deb(self):
83         """
84         Check deb contents making sure the .deb contains:
85           1. debian-binary
86           2. control.tar.gz
87           3. data.tar.gz or data.tar.bz2
88         in that order, and nothing else.
89         """
90         self.__scan_ar()
91         rejected = not self.chunks
92         if len(self.chunks) != 3:
93             rejected = True
94             reject("%s: found %d chunks, expected 3." % (self.filename, len(self.chunks)))
95         if self.chunks[0] != "debian-binary":
96             rejected = True
97             reject("%s: first chunk is '%s', expected 'debian-binary'." % (self.filename, self.chunks[0]))
98         if self.chunks[1] != "control.tar.gz":
99             rejected = True
100             reject("%s: second chunk is '%s', expected 'control.tar.gz'." % (self.filename, self.chunks[1]))
101         if self.chunks[2] not in [ "data.tar.bz2", "data.tar.gz" ]:
102             rejected = True
103             reject("%s: third chunk is '%s', expected 'data.tar.gz' or 'data.tar.bz2'." % (self.filename, self.chunks[2]))
104
105         return not rejected
106
107     def scan_package(self):
108         """
109         Unpack the .deb, do sanity checking, and gather info from it.
110
111         Currently information gathering consists of getting the contents list. In
112         the hopefully near future, it should also include gathering info from the
113         control file.
114
115         @return True if the deb is valid and contents were imported
116         """
117         rejected = not self.valid_deb()
118         self.__unpack()
119
120         if not rejected and self.tmpdir:
121             cwd = os.getcwd()
122             try:
123                 os.chdir(self.tmpdir)
124                 if self.chunks[1] == "control.tar.gz":
125                     control = tarfile.open(os.path.join(self.tmpdir, "control.tar.gz" ), "r:gz")
126                 elif self.chunks[1] == "control.tar.bz2":
127                     control = tarfile.open(os.path.join(self.tmpdir, "control.tar.bz2" ), "r:bz2")
128
129                 pkg = deb822.Packages.iter_paragraphs( control.extractfile('./control') ).next()
130
131                 if self.chunks[2] == "data.tar.gz":
132                     data = tarfile.open(os.path.join(self.tmpdir, "data.tar.gz"), "r:gz")
133                 elif self.chunks[2] == "data.tar.bz2":
134                     data = tarfile.open(os.path.join(self.tmpdir, "data.tar.bz2" ), "r:bz2")
135
136                 return DBConn().insert_content_paths(pkg, [ tarinfo.name for tarinfo in data if tarinfo.isdir()])
137
138             except:
139                 traceback.print_exc()
140
141                 return False
142
143             finally:
144                 os.chdir( cwd )
145
146
147
148
149 if __name__ == "__main__":
150     Binary( "/srv/ftp.debian.org/queue/accepted/halevt_0.1.3-2_amd64.deb" ).scan_package()
151