]>
git.ipfire.org Git - pakfire.git/blob - pakfire/packages/packager.py
16 from pakfire
.constants
import *
17 from pakfire
.i18n
import _
19 class Extractor(object):
20 def __init__(self
, pakfire
, pkg
):
21 self
.pakfire
= pakfire
24 self
.data
= pkg
.get_file("data.img")
29 if self
.pkg
.payload_compression
:
30 self
.uncompress_payload()
32 self
.archive
= tarfile
.open(fileobj
=self
.data
)
35 # XXX not called by anything
37 os
.unlink(self
._tempfile
)
39 def uncompress_payload(self
):
40 # XXX this function uncompresses the data.img file
41 # and saves the bare tarball to /tmp which takes a lot
44 # Create a temporary file to save the content in
45 f
, self
._tempfile
= tempfile
.mkstemp()
46 f
= open(self
._tempfile
, "w")
48 if self
.pkg
.payload_compression
== "xz":
49 decompressor
= lzma
.LZMADecompressor()
51 elif self
.pkg
.payload_compression
== "zlib":
52 decompressor
= zlib
.decompressobj()
54 buf
= self
.data
.read(BUFFER_SIZE
)
56 f
.write(decompressor
.decompress(buf
))
58 buf
= self
.data
.read(BUFFER_SIZE
)
60 f
.write(decompressor
.flush())
63 self
.archive
= tarfile
.open(self
._tempfile
)
67 return self
.archive
.getnames()
69 def extractall(self
, path
="/", callback
=None):
70 pbar
= self
._make
_progressbar
()
75 print " %s %-20s" % (_("Extracting"), self
.pkg
.name
)
78 for name
in self
.files
:
80 self
.extract(name
, path
, callback
=callback
)
87 #sys.stdout.write("\n")
89 def extract(self
, filename
, path
="/", callback
=None):
90 member
= self
.archive
.getmember(filename
)
91 target
= os
.path
.join(path
, filename
)
93 # If the member is a directory and if it already exists, we
94 # don't need to create it again.
95 if member
.isdir() and os
.path
.exists(target
):
98 #if self.pakfire.config.get("debug"):
99 # msg = "Creating file (%s:%03d:%03d) " % \
100 # (tarfile.filemode(member.mode), member.uid, member.gid)
102 # msg += "/%s -> %s" % (member.name, member.linkname)
103 # elif member.islnk():
104 # msg += "/%s link to /%s" % (member.name, member.linkname)
106 # msg += "/%s" % member.name
109 # Remove file if it has been existant
110 if not member
.isdir() and os
.path
.exists(target
):
113 self
.archive
.extract(member
, path
=path
)
115 # XXX implement setting of xattrs/acls here
117 if callback
and not member
.isdir():
118 callback(member
.name
, hash1
="XXX", size
=member
.size
)
120 def _make_progressbar(self
):
121 # Don't display a progressbar if we are running in debug mode.
122 if self
.pakfire
.config
.get("debug"):
125 if not sys
.stdout
.isatty():
130 "%s %-20s" % (_("Extracting:"), self
.pkg
.name
),
132 progressbar
.Bar(left
="[", right
="]"),
134 # progressbar.Percentage(),
140 # maxval must be > 0 and so we assume that
141 # empty packages have at least one file.
142 maxval
= len(self
.files
) or 1
144 return progressbar
.ProgressBar(
151 class InnerTarFile(tarfile
.TarFile
):
152 def __init__(self
, *args
, **kwargs
):
153 # Force the pax format
154 kwargs
["format"] = tarfile
.PAX_FORMAT
156 if kwargs
.has_key("env"):
157 self
.env
= kwargs
.pop("env")
159 tarfile
.TarFile
.__init
__(self
, *args
, **kwargs
)
161 def __filter_xattrs(self
, tarinfo
):
162 logging
.debug("Adding file: %s" % tarinfo
.name
)
164 filename
= self
.env
.chrootPath(self
.env
.buildroot
, tarinfo
.name
)
166 # xattrs do only exists for regular files. If we don't have one,
168 if os
.path
.isfile(filename
):
169 for attr
, value
in xattr
.get_all(filename
):
170 tarinfo
.pax_headers
[attr
] = value
172 logging
.debug(" xattr: %s=%s" % (attr
, value
))
176 def add(self
, *args
, **kwargs
):
177 # Add filter for xattrs if no other filter is set.
178 if not kwargs
.has_key("filter") and len(args
) < 5:
179 kwargs
["filter"] = self
.__filter
_xattrs
181 tarfile
.TarFile
.add(self
, *args
, **kwargs
)
184 # XXX this is totally ugly and needs to be done right!
186 class Packager(object):
187 ARCHIVE_FILES
= ("info", "filelist", "signature", "data.img")
189 def __init__(self
, pakfire
, pkg
, env
):
190 self
.pakfire
= pakfire
196 # Store meta information
198 "package_format" : PACKAGE_FORMAT
,
199 "package_uuid" : uuid
.uuid4(),
200 "payload_comp" : None,
202 self
.info
.update(self
.pkg
.info
)
203 self
.info
.update(self
.pakfire
.distro
.info
)
204 self
.info
.update(self
.env
.info
)
206 ### Create temporary files
207 # Create temp directory to where we extract all files again and
208 # gather some information about them like requirements and provides.
209 self
.tempdir
= self
.env
.chrootPath("tmp", "%s_data" % self
.pkg
.friendly_name
)
210 if not os
.path
.exists(self
.tempdir
):
211 os
.makedirs(self
.tempdir
)
213 # Create files that have the archive data
214 self
.archive_files
= {}
215 for i
in self
.ARCHIVE_FILES
:
216 self
.archive_files
[i
] = \
217 self
.env
.chrootPath("tmp", "%s_%s" % (self
.pkg
.friendly_name
, i
))
220 logging
.debug("Packaging %s" % self
.pkg
.friendly_name
)
222 # Create the tarball and add all data to it.
223 self
.create_tarball()
225 chroot_tempdir
= self
.tempdir
[len(self
.env
.chrootPath()):]
227 "requires" : self
.env
.do("/usr/lib/buildsystem-tools/dependency-tracker requires %s" % chroot_tempdir
,
228 returnOutput
=True, env
=self
.pkg
.env
).strip(),
229 "provides" : self
.env
.do("/usr/lib/buildsystem-tools/dependency-tracker provides %s" % chroot_tempdir
,
230 returnOutput
=True, env
=self
.pkg
.env
).strip(),
234 self
.create_signature()
236 # Create the outer tarball.
237 resultdir
= os
.path
.join(self
.env
.chrootPath("result", self
.pkg
.arch
))
238 if not os
.path
.exists(resultdir
):
239 os
.makedirs(resultdir
)
241 filename
= os
.path
.join(resultdir
, self
.pkg
.filename
)
243 tar
= tarfile
.TarFile(filename
, mode
="w", format
=tarfile
.PAX_FORMAT
)
245 for i
in self
.ARCHIVE_FILES
:
246 tar
.add(self
.archive_files
[i
], arcname
=i
)
250 def create_tarball(self
, compress
="xz"):
251 tar
= InnerTarFile(self
.archive_files
["data.img"], mode
="w", env
=self
.env
)
256 for pattern
in self
.pkg
.file_patterns
:
257 # Check if we are running in include or exclude mode.
258 if pattern
.startswith("!"):
261 # Strip the ! charater
262 pattern
= pattern
[1:]
267 if pattern
.startswith("/"):
268 pattern
= pattern
[1:]
269 pattern
= self
.env
.chrootPath(self
.env
.buildroot
, pattern
)
271 # Recognize the type of the pattern. Patterns could be a glob
272 # pattern that is expanded here or just a directory which will
273 # be included recursively.
274 if "*" in pattern
or "?" in pattern
:
275 files
+= glob
.glob(pattern
)
277 elif os
.path
.exists(pattern
):
278 # Add directories recursively...
279 if os
.path
.isdir(pattern
):
280 for dir, subdirs
, _files
in os
.walk(pattern
):
282 file = os
.path
.join(dir, file)
285 # all other files are just added.
287 files
.append(pattern
)
290 logging
.warning("Unrecognized pattern type: %s" % pattern
)
293 for file in includes
:
294 # Skip if file is already in the file set or
295 # marked to be excluded from this archive.
296 if file in excludes
or file in files
:
303 filelist
= open(self
.archive_files
["filelist"], mode
="w")
305 for file_real
in files
:
306 file_tar
= file_real
[len(self
.env
.chrootPath(self
.env
.buildroot
)) + 1:]
307 file_tmp
= os
.path
.join(self
.tempdir
, file_tar
)
309 tar
.add(file_real
, arcname
=file_tar
, recursive
=False)
311 # Record the packaged file to the filelist.
312 filelist
.write("/%s\n" % file_tar
)
314 # "Copy" the file to the tmp path for later investigation.
315 if os
.path
.isdir(file_real
):
318 file_dir
= os
.path
.dirname(file_tmp
)
320 if not os
.path
.exists(file_dir
):
321 os
.makedirs(file_dir
)
323 if os
.path
.isfile(file_real
):
324 os
.link(file_real
, file_tmp
)
326 elif os
.path
.islink(file_real
):
327 # Dead symlinks cannot be copied by shutil.
328 os
.symlink(os
.readlink(file_real
), file_tmp
)
330 elif os
.path
.isdir(file_real
):
331 if not os
.path
.exists(file_tmp
):
332 os
.makedirs(file_tmp
)
335 shutil
.copy2(file_real
, file_tmp
)
337 # Unlink the file and remove empty directories.
338 if not os
.path
.isdir(file_real
):
341 elif os
.path
.isdir(file_real
) and not os
.listdir(file_real
):
344 # Dump all files that are in the archive.
347 # Write all data to disk.
351 # compress the tarball here
353 # Save algorithm to metadata.
354 self
.info
["payload_comp"] = compress
356 logging
.debug("Compressing package with %s algorithm." % compress
or "no")
358 filename
= self
.archive_files
["data.img"]
362 o
= open(filename
, "w")
365 comp
= lzma
.LZMACompressor()
367 elif compress
== "zlib":
368 comp
= zlib
.compressobj(9)
370 buf
= i
.read(BUFFER_SIZE
)
372 o
.write(comp
.compress(buf
))
374 buf
= i
.read(BUFFER_SIZE
)
376 o
.write(comp
.flush())
381 def create_info(self
):
382 f
= open(self
.archive_files
["info"], "w")
383 f
.write(BINARY_PACKAGE_META
% self
.info
)
386 def create_signature(self
):
387 # Create an empty signature.
388 f
= open(self
.archive_files
["signature"], "w")