]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - pakfire/packages/file.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
29 import pakfire
.util
as util
30 import pakfire
.compress
as compress
31 from pakfire
.errors
import FileError
32 from pakfire
.constants
import *
34 from base
import Package
36 class InnerTarFile(tarfile
.TarFile
):
37 SUPPORTED_XATTRS
= ("security.capability",)
39 def __init__(self
, *args
, **kwargs
):
40 # Force the PAX format.
41 kwargs
["format"] = tarfile
.PAX_FORMAT
43 tarfile
.TarFile
.__init
__(self
, *args
, **kwargs
)
45 def add(self
, name
, arcname
=None, recursive
=None, exclude
=None, filter=None):
47 Emulate the add function with xattrs support.
49 tarinfo
= self
.gettarinfo(name
, arcname
)
54 # Use new modules code...
55 if hasattr(xattr
, "get_all"):
56 attrs
= xattr
.get_all(name
)
58 # ...or use the deprecated API.
60 for attr
in xattr
.listxattr(name
):
61 val
= xattr
.getxattr(name
, attr
)
62 attrs
.append((attr
, val
))
64 for attr
, val
in attrs
:
65 # Skip all attrs that are not supported (e.g. selinux).
66 if not attr
in self
.SUPPORTED_XATTRS
:
69 logging
.debug("Saving xattr %s=%s from %s" % (attr
, val
, name
))
71 tarinfo
.pax_headers
[attr
] = val
73 # Append the tar header and data to the archive.
74 f
= tarfile
.bltn_open(name
, "rb")
75 self
.addfile(tarinfo
, f
)
81 for f
in os
.listdir(name
):
82 self
.add(os
.path
.join(name
, f
), os
.path
.join(arcname
, f
),
83 recursive
, exclude
, filter)
88 def extract(self
, member
, path
=""):
89 # Extract file the normal way...
90 tarfile
.TarFile
.extract(self
, member
, path
)
92 # ...and then apply the extended attributes.
93 if member
.pax_headers
:
94 target
= os
.path
.join(path
, member
.name
)
96 for attr
, val
in member
.pax_headers
.items():
97 # Skip all attrs that are not supported (e.g. selinux).
98 if not attr
in self
.SUPPORTED_XATTRS
:
101 logging
.debug("Restoring xattr %s=%s to %s" % (attr
, val
, target
))
102 if hasattr(xattr
, "set"):
103 xattr
.set(target
, attr
, val
)
106 xattr
.setxattr(target
, attr
, val
)
109 class FilePackage(Package
):
111 This class is a wrapper that reads package data from the (outer)
112 tarball and should never be used solely.
114 def __init__(self
, pakfire
, repo
, filename
):
115 Package
.__init
__(self
, pakfire
, repo
)
116 self
.filename
= os
.path
.abspath(filename
)
118 # Place to cache the metadata
125 Initially check if the given file is of the correct type and
128 if not tarfile
.is_tarfile(self
.filename
):
129 raise FileError
, "Given file is not of correct format: %s" % self
.filename
132 return "<%s %s>" % (self
.__class
__.__name
__, self
.filename
)
136 # A file package is always local.
139 def open_archive(self
):
140 return tarfile
.open(self
.filename
)
142 def extract(self
, message
=None, prefix
=None):
143 logging
.debug("Extracting package %s" % self
.friendly_name
)
148 # A place to store temporary data.
151 # Open package data for read.
152 archive
= self
.open_archive()
154 # Get the package payload.
155 payload
= archive
.extractfile("data.img")
157 # Decompress the payload if needed.
158 logging
.debug("Compression: %s" % self
.payload_compression
)
160 # Create a temporary file to store the decompressed output.
161 garbage
, tempf
= tempfile
.mkstemp(prefix
="pakfire")
166 # Decompress the package payload.
167 if self
.payload_compression
:
168 compress
.decompressobj(i
, o
, algo
=self
.payload_compression
)
171 buf
= i
.read(BUFFER_SIZE
)
174 buf
= i
.read(BUFFER_SIZE
)
179 payload
= open(tempf
)
181 # Open the tarball in the package.
182 payload_archive
= InnerTarFile
.open(fileobj
=payload
)
184 members
= payload_archive
.getmembers()
189 message
= "%-10s : %s" % (message
, self
.friendly_name
)
190 pb
= util
.make_progress(message
, len(members
), eta
=False)
193 for member
in members
:
199 target
= os
.path
.join(prefix
, member
.name
)
201 # If the member is a directory and if it already exists, we
202 # don't need to create it again.
204 if os
.path
.exists(target
):
209 # Remove file if it has been existant
212 #if self.pakfire.config.get("debug"):
213 # msg = "Creating file (%s:%03d:%03d) " % \
214 # (tarfile.filemode(member.mode), member.uid, member.gid)
216 # msg += "/%s -> %s" % (member.name, member.linkname)
217 # elif member.islnk():
218 # msg += "/%s link to /%s" % (member.name, member.linkname)
220 # msg += "/%s" % member.name
223 payload_archive
.extract(member
, path
=prefix
)
225 # Close all open files.
226 payload_archive
.close()
237 def file_version(self
):
239 Returns the version of the package metadata.
241 return self
.metadata
.get("VERSION")
246 Read-in the metadata from the "info" file and cache it in _metadata.
248 if not self
._metadata
:
249 a
= self
.open_archive()
250 f
= a
.extractfile("info")
252 for line
in f
.readlines():
253 m
= re
.match(r
"^(\w+)=(.*)$", line
)
257 key
, val
= m
.groups()
258 self
._metadata
[key
] = val
.strip("\"")
263 return self
._metadata
268 Return the size of the package file.
270 return os
.path
.getsize(self
.filename
)
272 def __filelist_from_metadata(self
):
273 a
= self
.open_archive()
274 f
= a
.extractfile("filelist")
277 for line
in f
.readlines():
279 if not line
.startswith("/"):
289 def __filelist_from_payload(self
):
290 # XXX expect uncompressed payload for now
291 # this is very simple and very slow
293 a
= self
.open_archive()
294 f
= a
.extractfile("data.img")
295 t
= tarfile
.open(fileobj
=f
)
297 ret
= ["/%s" % n
for n
in t
.getnames()]
308 Return a list of the files that are contained in the package
311 At first, we try to get them from the metadata (which is the
313 If the file is not existant, we will open the payload and
314 read it instead. The latter is a very slow procedure and
315 should not be used anyway.
317 if not hasattr(self
, "__filelist"):
319 self
.__filelist
= self
.__filelist
_from
_metadata
()
321 self
.__filelist
= self
.__filelist
_from
_payload
()
323 return self
.__filelist
326 def configfiles(self
):
327 return [] # XXX to be done
330 def payload_compression(self
):
332 Return the compression type of the payload.
334 comp
= self
.metadata
.get("PKG_PAYLOAD_COMP", None)
344 Read the signature from the archive or return None if no
345 signature does exist.
349 a
= self
.open_archive()
350 f
= a
.extractfile("signature")
358 # signature file could not be found
366 Calculate the hash1 of this package.
368 return util
.calc_hash1(self
.filename
)
373 Read the scriptlet from the archive or return an empty string if no
374 scriptlet does exist.
378 a
= self
.open_archive()
379 f
= a
.extractfile("control")
387 # scriptlet file could not be found