#!/usr/bin/python # Copyright 1999-2007 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id$ import errno, signal, sys, os def quickpkg_main(options, args, eout): from portage import dblink, dep_expand, catsplit, isvalidatom, xpak from portage.util import ensure_dirs from portage.exception import InvalidData from portage.dbapi.vartree import tar_contents import tarfile import portage root = portage.settings["ROOT"] trees = portage.db[root] vartree = trees["vartree"] vardb = vartree.dbapi bintree = trees["bintree"] if not os.access(bintree.pkgdir, os.W_OK): eout.eerror("No write access to '%s'" % bintree.pkgdir) return errno.EACCES successes = [] missing = [] for arg in args: try: atom = dep_expand(arg, mydb=vardb, settings=vartree.settings) except ValueError, e: # Multiple matches thrown from cpv_expand eout.eerror("Please use a more specific atom: %s" % \ " ".join(e.args[0])) del e missing.append(arg) continue except InvalidData, e: eout.eerror("Invalid atom: %s" % str(e)) del e missing.append(arg) continue if not isvalidatom(atom): eout.eerror("Invalid atom: %s" % atom) missing.append(arg) continue matches = vardb.match(atom) pkgs_for_arg = 0 for cpv in matches: bintree.prevent_collision(cpv) cat, pkg = catsplit(cpv) dblnk = dblink(cat, pkg, root, vartree.settings, treetype="vartree", vartree=vartree) dblnk.lockdb() try: if not dblnk.exists(): # unmerged by a concurrent process continue eout.ebegin("Building package for %s" % cpv) pkgs_for_arg += 1 contents = dblnk.getcontents() xpdata = xpak.xpak(dblnk.dbdir) binpkg_tmpfile = os.path.join(bintree.pkgdir, cpv + ".tbz2." + str(os.getpid())) ensure_dirs(os.path.dirname(binpkg_tmpfile)) tar = tarfile.open(binpkg_tmpfile, "w:bz2") tar_contents(contents, root, tar) tar.close() xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata) finally: dblnk.unlockdb() bintree.inject(cpv, filename=binpkg_tmpfile) binpkg_path = bintree.getname(cpv) try: s = os.stat(binpkg_path) except OSError, e: # Sanity check, shouldn't happen normally. eout.eend(1) eout.eerror(str(e)) del e eout.eerror("Failed to create package: '%s'" % binpkg_path) else: eout.eend(0) successes.append((cpv, s.st_size)) if not pkgs_for_arg: eout.eerror("Could not find anything " + \ "to match '%s'; skipping" % arg) missing.append(arg) if not successes: eout.eerror("No packages found") return 1 print eout.einfo("Packages now in '%s':" % bintree.pkgdir) import math units = {10:'K', 20:'M', 30:'G', 40:'T', 50:'P', 60:'E', 70:'Z', 80:'Y'} for cpv, size in successes: if not size: # avoid OverflowError in math.log() size_str = "0" else: power_of_2 = math.log(size, 2) power_of_2 = 10*int(power_of_2/10) unit = units.get(power_of_2) if unit: size = float(size)/(2**power_of_2) size_str = "%.1f" % size if len(size_str) > 4: # emulate `du -h`, don't show too many sig figs size_str = str(int(size)) size_str += unit else: size_str = str(size) eout.einfo("%s: %s" % (cpv, size_str)) if missing: print eout.ewarn("The following packages could not be found:") eout.ewarn(" ".join(missing)) return 2 return os.EX_OK if __name__ == "__main__": usage = "Usage: quickpkg [options] " from optparse import OptionParser parser = OptionParser(usage=usage) options, args = parser.parse_args(sys.argv[1:]) if not args: parser.error("no packages atoms given") # We need to ensure a sane umask for the packages that will be created. old_umask = os.umask(022) from portage.output import get_term_size, EOutput eout = EOutput() def sigwinch_handler(signum, frame): lines, eout.term_columns = get_term_size() signal.signal(signal.SIGWINCH, sigwinch_handler) try: retval = quickpkg_main(options, args, eout) finally: os.umask(old_umask) signal.signal(signal.SIGWINCH, signal.SIG_DFL) sys.exit(retval)