diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/archive-conf | 101 | ||||
-rwxr-xr-x | bin/chkcontents | 62 | ||||
-rwxr-xr-x | bin/clean_locks | 36 | ||||
-rwxr-xr-x | bin/dispatch-conf | 311 | ||||
-rwxr-xr-x | bin/dobin | 28 | ||||
-rwxr-xr-x | bin/doconfd | 15 | ||||
-rwxr-xr-x | bin/dodir | 8 | ||||
-rwxr-xr-x | bin/dodoc | 23 | ||||
-rwxr-xr-x | bin/doenvd | 15 | ||||
-rwxr-xr-x | bin/doexe | 26 | ||||
-rwxr-xr-x | bin/dohard | 13 | ||||
-rwxr-xr-x | bin/dohtml | 159 | ||||
-rwxr-xr-x | bin/doinfo | 21 | ||||
-rwxr-xr-x | bin/doinitd | 15 | ||||
-rwxr-xr-x | bin/doins | 53 | ||||
-rwxr-xr-x | bin/dojar | 54 | ||||
-rwxr-xr-x | bin/dolib | 41 | ||||
-rwxr-xr-x | bin/dolib.a | 7 | ||||
-rwxr-xr-x | bin/dolib.so | 7 | ||||
-rwxr-xr-x | bin/doman | 52 | ||||
-rwxr-xr-x | bin/domo | 26 | ||||
-rwxr-xr-x | bin/dopython | 23 | ||||
-rwxr-xr-x | bin/dosbin | 27 | ||||
-rwxr-xr-x | bin/dosed | 22 | ||||
-rwxr-xr-x | bin/dosym | 13 | ||||
-rwxr-xr-x | bin/ebuild | 61 | ||||
-rwxr-xr-x | bin/ebuild.sh | 1868 | ||||
-rwxr-xr-x | bin/emake | 14 | ||||
-rwxr-xr-x | bin/emerge | 3213 | ||||
-rwxr-xr-x | bin/emerge-webrsync | 141 | ||||
-rwxr-xr-x | bin/emerge.orig | 3227 | ||||
-rwxr-xr-x | bin/env-update | 11 | ||||
-rwxr-xr-x | bin/env-update.sh | 221 | ||||
-rwxr-xr-x | bin/etc-update | 407 | ||||
-rwxr-xr-x | bin/find-requires | 44 | ||||
-rwxr-xr-x | bin/fix-db.py | 175 | ||||
-rwxr-xr-x | bin/fixdbentries | 20 | ||||
-rwxr-xr-x | bin/fixpackages | 14 | ||||
-rwxr-xr-x | bin/fowners | 15 | ||||
-rwxr-xr-x | bin/fperms | 15 | ||||
-rwxr-xr-x | bin/md5check.py | 102 | ||||
-rwxr-xr-x | bin/md5check.sh | 31 | ||||
-rwxr-xr-x | bin/mirror.py | 167 | ||||
-rwxr-xr-x | bin/newbin | 13 | ||||
-rwxr-xr-x | bin/newconfd | 13 | ||||
-rwxr-xr-x | bin/newdoc | 13 | ||||
-rwxr-xr-x | bin/newenvd | 13 | ||||
-rwxr-xr-x | bin/newexe | 13 | ||||
-rwxr-xr-x | bin/newinitd | 13 | ||||
-rwxr-xr-x | bin/newins | 13 | ||||
-rwxr-xr-x | bin/newlib.a | 13 | ||||
-rwxr-xr-x | bin/newlib.so | 13 | ||||
-rwxr-xr-x | bin/newman | 13 | ||||
-rwxr-xr-x | bin/newsbin | 13 | ||||
-rwxr-xr-x | bin/pemerge.py | 44 | ||||
-rwxr-xr-x | bin/pkgmerge | 59 | ||||
-rwxr-xr-x | bin/pkgmerge.new | 84 | ||||
-rwxr-xr-x | bin/pkgname | 17 | ||||
-rwxr-xr-x | bin/portage_gpg_update.sh | 6 | ||||
-rwxr-xr-x | bin/portageq | 256 | ||||
-rwxr-xr-x | bin/prepall | 39 | ||||
-rwxr-xr-x | bin/prepalldocs | 33 | ||||
-rwxr-xr-x | bin/prepallinfo | 9 | ||||
-rwxr-xr-x | bin/prepallman | 12 | ||||
-rwxr-xr-x | bin/prepallstrip | 11 | ||||
-rwxr-xr-x | bin/prepinfo | 45 | ||||
-rwxr-xr-x | bin/preplib | 25 | ||||
-rwxr-xr-x | bin/preplib.so | 10 | ||||
-rwxr-xr-x | bin/prepman | 46 | ||||
-rwxr-xr-x | bin/prepstrip | 48 | ||||
-rwxr-xr-x | bin/quickpkg | 148 | ||||
-rwxr-xr-x | bin/regenworld | 93 | ||||
-rwxr-xr-x | bin/repoman | 1522 | ||||
-rwxr-xr-x | bin/xpak | 14 |
74 files changed, 13568 insertions, 0 deletions
diff --git a/bin/archive-conf b/bin/archive-conf new file mode 100755 index 000000000..6e198f49f --- /dev/null +++ b/bin/archive-conf @@ -0,0 +1,101 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/archive-conf,v 1.7 2004/10/04 13:57:36 vapier Exp $ + +# +# archive-conf -- save off a config file in the dispatch-conf archive dir +# +# Written by Wayne Davison <gentoo@blorf.net> with code snagged from +# Jeremy Wohl's dispatch-conf script and the portage chkcontents script. +# + +import os, sys, string +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage, dispatch_conf + +FIND_EXTANT_CONTENTS = "find %s -name CONTENTS" + +MANDATORY_OPTS = [ 'archive-dir' ] + +try: + import fchksum + def perform_checksum(filename): return fchksum.fmd5t(filename) +except ImportError: + import md5 + def md5_to_hex(md5sum): + hexform = "" + for ix in xrange(len(md5sum)): + hexform = hexform + "%02x" % ord(md5sum[ix]) + return string.lower(hexform) + + def perform_checksum(filename): + f = open(filename, 'rb') + blocksize=32768 + data = f.read(blocksize) + size = 0L + sum = md5.new() + while data: + sum.update(data) + size = size + len(data) + data = f.read(blocksize) + return (md5_to_hex(sum.digest()),size) + +def archive_conf(): + args = [] + content_files = [] + md5_match_hash = {} + + options = dispatch_conf.read_config(MANDATORY_OPTS) + + for conf in sys.argv[1:]: + if not os.path.isabs(conf): + conf = os.path.abspath(conf) + args += [ conf ] + md5_match_hash[conf] = '' + + # Find all the CONTENT files in VDB_PATH. + content_files += os.popen(FIND_EXTANT_CONTENTS % (portage.root+portage.VDB_PATH)).readlines() + + # Search for the saved md5 checksum of all the specified config files + # and see if the current file is unmodified or not. + try: + todo_cnt = len(args) + for file in content_files: + file = file.rstrip() + try: + contents = open(file, "r") + except IOError, e: + print >> sys.stderr, 'archive-conf: Unable to open %s: %s' % (file, e) + sys.exit(1) + lines = contents.readlines() + for line in lines: + items = string.split(line) + if items[0] == 'obj': + for conf in args: + if items[1] == conf: + stored = string.lower(items[2]) + real = string.lower(perform_checksum(conf)[0]) + if stored == real: + md5_match_hash[conf] = conf + todo_cnt -= 1 + if todo_cnt == 0: + raise "Break" + except "Break": + pass + + for conf in args: + archive = os.path.join(options['archive-dir'], conf.lstrip('/')) + if options['use-rcs'] == 'yes': + dispatch_conf.rcs_archive(archive, conf, md5_match_hash[conf], '') + dispatch_conf.rcs_archive_post_process(archive) + else: + dispatch_conf.file_archive(archive, conf, md5_match_hash[conf], '') + dispatch_conf.file_archive_post_process(archive) + +# run +if len(sys.argv) > 1: + archive_conf() +else: + print >> sys.stderr, 'Usage: archive-conf /CONFIG/FILE [/CONFIG/FILE...]' diff --git a/bin/chkcontents b/bin/chkcontents new file mode 100755 index 000000000..eebf868cd --- /dev/null +++ b/bin/chkcontents @@ -0,0 +1,62 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/chkcontents,v 1.11 2004/10/04 13:56:50 vapier Exp $ + +# Very simple program to compare the md5sums of a package as listed +# in VDB_PATH/category/package/CONTENTS with the md5sums of the +# actual programs on the system (and makes sure that symlinks point to +# the right files). + +import string, os.path, os, sys +sys.path = ["/usr/lib/portage/pym"]+sys.path +import portage + +def CONTENTScheck(path): + try: + contents = open(path, "r") + except IOError, e: + print "Unable to open %s: %s" % (path, e) + sys.exit(1) + lines = contents.readlines() + for line in lines: + items = string.split(line) + # items is a list w/ size depending on the type of item listed in item[0] + # if items[0] = 'dir' then items[1] is the path of a directory + # if items[0] = 'obj' then items[1] is the path of a file, + # items[2] is the file's md5sum, + # items[3] is the file's size + # if items[0] = 'sym' then items[1] is the path of a symbolic link, + # items[2] is '->' + # items[3] is the file the symlink should point to + # items[4] is the symlink mtime + if (items[0] == 'obj'): + md5stored = string.lower(items[2]) + # fchksum.fmdft(file) returns the file's md5sum and the file's size + md5real = string.lower(portage.perform_checksum(items[1])[0]) + if (md5stored != md5real): + if md5real: + print "%s has md5sum of %s instead of %s" % (items[1], md5real, md5stored) + else: + print "%s is missing!" % items[1] + elif (items[0] == 'sym'): + link = items[1] + target = items[3] + if (not os.path.islink(link)): + print "%s is not a symbolic link" % link + continue + actualtarget = os.readlink(link) + if (os.path.normpath(actualtarget) != os.path.normpath(target)): + print "%s points to %s, not %s" % (link, actualtarget, target) + + +if __name__ == '__main__': + import sys + if (len(sys.argv) != 2 or sys.argv[1] == "--help"): + print "This program compares md5sums in the file VDB_PATH/category/package/CONTENTS" + print "with the md5sums of the actual files on the filesystem" + print "(and makes sure that symlinks point to the right files)." + print "\nUsage: chkcontents path/to/CONTENTS" + sys.exit(1) + CONTENTScheck(sys.argv[1]) + diff --git a/bin/clean_locks b/bin/clean_locks new file mode 100755 index 000000000..aa6669c16 --- /dev/null +++ b/bin/clean_locks @@ -0,0 +1,36 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/clean_locks,v 1.1 2004/09/26 10:44:31 carpaski Exp $ + +import os,sys +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage_locks + +if not sys.argv[1:] or "--help" in sys.argv or "-h" in sys.argv: + print + print "You must specify directories with hardlink-locks to clean." + print "You may optionally specify --force, which will remove all" + print "of the locks, even if we can't establish if they are in use." + print "Please attempt cleaning without force first." + print + print sys.argv[0]+" /usr/portage/distfiles/.locks" + print sys.argv[0]+" --force /usr/portage/distfiles/.locks" + print + sys.exit(1) + +force = False +if "--force" in sys.argv[1:]: + force=True + +for x in sys.argv[1:]: + if x == "--force": + continue + for y in portage_locks.hardlock_cleanup(x, remove_all_locks=force): + print y + print + + + +
\ No newline at end of file diff --git a/bin/dispatch-conf b/bin/dispatch-conf new file mode 100755 index 000000000..2db6a329a --- /dev/null +++ b/bin/dispatch-conf @@ -0,0 +1,311 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dispatch-conf,v 1.7.2.10 2005/05/12 15:20:22 jstubbs Exp $ + +# +# dispatch-conf -- Integrate modified configs, post-emerge +# +# Jeremy Wohl (http://igmus.org) +# +# TODO +# dialog menus +# + +from stat import * +from random import * +import os, shutil, sys, string, re, commands, atexit +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage, dispatch_conf + +FIND_EXTANT_CONFIGS = "find %s/ -iname '._cfg????_*' | sed -e 's://:/:g'" +DIFF_CONTENTS = 'diff -Nu %s %s' +DIFF_CVS_INTERP = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"' +DIFF_WSCOMMENTS = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"' + +# We need a secure scratch dir and python does silly verbose errors on the use of tempnam +oldmask = os.umask(0077) +SCRATCH_DIR = None +while SCRATCH_DIR is None: + try: + mydir = "/tmp/dispatch-conf." + for x in range(0,8): + if int(random() * 3) == 0: + mydir += chr(int(65+random()*26.0)) + elif int(random() * 2) == 0: + mydir += chr(int(97+random()*26.0)) + else: + mydir += chr(int(48+random()*10.0)) + if os.path.exists(mydir): + continue + os.mkdir(mydir) + SCRATCH_DIR = mydir + except OSError, e: + if e.errno != 17: + raise +os.umask(oldmask) + +# Ensure the scratch dir is deleted +def cleanup(mydir=SCRATCH_DIR): + shutil.rmtree(SCRATCH_DIR) +atexit.register(cleanup) + +MANDATORY_OPTS = [ 'archive-dir', 'diff', 'replace-cvs', 'replace-wscomments', 'merge' ] + +class dispatch: + options = {} + + def grind (self, config_paths): + confs = [] + count = 0 + + + self.options = dispatch_conf.read_config(MANDATORY_OPTS) + + if self.options.has_key("log-file"): + if os.path.exists(self.options["log-file"]): + shutil.copyfile(self.options["log-file"], self.options["log-file"] + '.old') + os.remove(self.options["log-file"]) + else: + self.options["log-file"] = "/dev/null" + + # + # Build list of extant configs + # + + for path in config_paths.split (): + if not os.path.exists (path): + continue + + confs += self.massage (os.popen (FIND_EXTANT_CONFIGS % (path,)).readlines ()) + + if self.options['use-rcs'] == 'yes' and ((os.system( "which rcs >/dev/null 2>&1" ) == 256) + or (os.system( "which ci >/dev/null 2>&1" ) == 256) + or (os.system( "which co >/dev/null 2>&1" ) == 256) + or (os.system( "which rcsmerge >/dev/null 2>&1" ) == 256)): + print >> sys.stderr, 'dispatch-conf: Error finding all RCS utils and use-rcs=yes in config; fatal' + return False + + + # + # Remove new configs identical to current + # and + # Auto-replace configs a) whose differences are simply CVS interpolations, + # or b) whose differences are simply ws or comments, + # or c) in paths now unprotected by CONFIG_PROTECT_MASK, + # + + def f (conf): + mrgconf = re.sub(r'\._cfg', '._mrg', conf['new']) + archive = os.path.join(self.options['archive-dir'], conf['current'].lstrip('/')) + if self.options['use-rcs'] == 'yes': + mrgfail = dispatch_conf.rcs_archive(archive, conf['current'], conf['new'], mrgconf) + else: + mrgfail = dispatch_conf.file_archive(archive, conf['current'], conf['new'], mrgconf) + if os.path.exists(archive + '.dist'): + unmodified = len(commands.getoutput(DIFF_CONTENTS % (conf['current'], archive + '.dist'))) == 0 + else: + unmodified = 0 + if os.path.exists(mrgconf): + if mrgfail or len(commands.getoutput(DIFF_CONTENTS % (conf['new'], mrgconf))) == 0: + os.unlink(mrgconf) + newconf = conf['new'] + else: + newconf = mrgconf + else: + newconf = conf['new'] + + same_file = len(commands.getoutput (DIFF_CONTENTS % (conf ['current'], newconf))) == 0 + same_cvs = len(commands.getoutput (DIFF_CVS_INTERP % (conf ['current'], newconf))) == 0 + same_wsc = len(commands.getoutput (DIFF_WSCOMMENTS % (conf ['current'], newconf))) == 0 + + # Do options permit? + same_cvs = same_cvs and self.options['replace-cvs'] == 'yes' + same_wsc = same_wsc and self.options['replace-wscomments'] == 'yes' + unmodified = unmodified and self.options['replace-unmodified'] == 'yes' + + if same_file: + os.unlink (conf ['new']) + self.post_process(conf['current']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + return False + elif unmodified or same_cvs or same_wsc or conf ['dir'] in portage.settings ['CONFIG_PROTECT_MASK'].split (): + self.replace(newconf, conf['current']) + self.post_process(conf['current']) + if newconf == mrgconf: + os.unlink(conf['new']) + elif os.path.exists(mrgconf): + os.unlink(mrgconf) + return False + else: + return True + + confs = filter (f, confs) + + # + # Interactively process remaining + # + + for conf in confs: + count = count + 1 + + newconf = conf['new'] + mrgconf = re.sub(r'\._cfg', '._mrg', newconf) + if os.path.exists(mrgconf): + newconf = mrgconf + show_new_diff = 0 + + while 1: + if show_new_diff: + os.system((self.options['diff']) % (conf['new'], mrgconf)) + show_new_diff = 0 + else: + os.system((self.options['diff']) % (conf['current'], newconf)) + + print + print '>> (%i of %i) -- %s' % (count, len(confs), conf ['current']) + print '>> q quit, h help, n next, e edit-new, z zap-new, u use-new\n m merge, t toggle-merge, l look-merge: ', + + c = getch () + + if c == 'q': + sys.exit (0) + if c == 'h': + self.do_help () + continue + elif c == 't': + if newconf == mrgconf: + newconf = conf['new'] + elif os.path.exists(mrgconf): + newconf = mrgconf + continue + elif c == 'n': + break + elif c == 'm': + merged = SCRATCH_DIR+"/"+os.path.basename(conf['current']) + print + os.system (self.options['merge'] % (merged, conf ['current'], newconf)) + shutil.copyfile(merged, mrgconf) + os.remove(merged) + mystat = os.lstat(conf['new']) + os.chmod(mrgconf, mystat[ST_MODE]) + os.chown(mrgconf, mystat[ST_UID], mystat[ST_GID]) + newconf = mrgconf + continue + elif c == 'l': + show_new_diff = 1 + continue + elif c == 'e': + os.system(os.environ['EDITOR'] + ' ' + newconf) + continue + elif c == 'z': + os.unlink(conf['new']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + break + elif c == 'u': + self.replace(newconf, conf ['current']) + self.post_process(conf['current']) + if newconf == mrgconf: + os.unlink(conf['new']) + elif os.path.exists(mrgconf): + os.unlink(mrgconf) + break + else: + continue + + + def replace (self, newconf, curconf): + """Replace current config with the new/merged version. Also logs + the diff of what changed into the configured log file.""" + os.system((DIFF_CONTENTS % (curconf, newconf)) + '>>' + self.options["log-file"]) + try: + shutil.copyfile(newconf, curconf) + os.remove(newconf) + except (IOError, os.error), why: + print >> sys.stderr, 'dispatch-conf: Error renaming %s to %s: %s; fatal' % \ + (newconf, curconf, str(why)) + + + def post_process(self, curconf): + archive = os.path.join(self.options['archive-dir'], curconf.lstrip('/')) + if self.options['use-rcs'] == 'yes': + dispatch_conf.rcs_archive_post_process(archive) + else: + dispatch_conf.file_archive_post_process(archive) + + + def massage (self, newconfigs): + """Sort, rstrip, remove old versions, break into triad hash. + + Triad is dictionary of current (/etc/make.conf), new (/etc/._cfg0003_make.conf) + and dir (/etc). + + We keep ._cfg0002_conf over ._cfg0001_conf and ._cfg0000_conf. + """ + h = {} + + newconfigs.sort () + + for nconf in newconfigs: + nconf = nconf.rstrip () + conf = re.sub (r'\._cfg\d+_', '', nconf) + dir = re.match (r'^(.+)/', nconf).group (1) + + if h.has_key (conf): + mrgconf = re.sub(r'\._cfg', '._mrg', h[conf]['new']) + if os.path.exists(mrgconf): + os.unlink(mrgconf) + os.unlink(h[conf]['new']) + + h [conf] = { 'current' : conf, 'dir' : dir, 'new' : nconf } + + configs = h.values () + configs.sort (lambda a, b: cmp(a ['current'], b ['current'])) + + return configs + + + def do_help (self): + print; print + + print ' u -- update current config with new config and continue' + print ' z -- zap (delete) new config and continue' + print ' n -- skip to next config, leave all intact' + print ' e -- edit new config' + print ' m -- interactively merge current and new configs' + print ' l -- look at diff between pre-merged and merged configs' + print ' t -- toggle new config between merged and pre-merged state' + print ' h -- this screen' + print ' q -- quit' + + print; print 'press any key to return to diff...', + + getch () + + +def getch (): + # from ASPN - Danny Yoo + # + import sys, tty, termios + + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + +# run +d = dispatch () + +if len(sys.argv) > 1: + # for testing + d.grind (string.join (sys.argv [1:])) +else: + d.grind (portage.settings ['CONFIG_PROTECT']) diff --git a/bin/dobin b/bin/dobin new file mode 100755 index 000000000..4c070d95b --- /dev/null +++ b/bin/dobin @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dobin,v 1.13 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "${0}: at least one argument needed" + exit 1 +fi + +if [ ! -d "${D}${DESTTREE}/bin" ] ; then + install -d "${D}${DESTTREE}/bin" || exit 2 +fi + +for x in "$@" ; do + if [ -x "${x}" ] ; then + #if executable, use existing perms + install "${x}" "${D}${DESTTREE}/bin" || exit 3 + else + #otherwise, use reasonable defaults + echo ">>> dobin: making ${x} executable..." + if [ "$USERLAND" == "GNU" ]; then + install -m0755 -o root -g root "${x}" "${D}${DESTTREE}/bin" || exit 4 + else + install -m0755 -o root -g wheel "${x}" "${D}${DESTTREE}/bin" || exit 4 + fi + fi +done diff --git a/bin/doconfd b/bin/doconfd new file mode 100755 index 000000000..73d5cedcf --- /dev/null +++ b/bin/doconfd @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doconfd,v 1.2.2.1 2005/01/13 04:51:56 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "doconfd: at least one argument needed" + exit 1 +fi + +tmp_INSDESTTREE="${INSDESTTREE}" +INSDESTTREE=/etc/conf.d/ +doins "$@" +INSDESTTREE="${tmp_INSDESTTREE}" +unset tmp_INSDESTTREE diff --git a/bin/dodir b/bin/dodir new file mode 100755 index 000000000..6df8f4031 --- /dev/null +++ b/bin/dodir @@ -0,0 +1,8 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dodir,v 1.5 2004/10/04 13:56:50 vapier Exp $ + +for x in "$@" ; do + install -d ${DIROPTIONS} "${D}${x}" +done diff --git a/bin/dodoc b/bin/dodoc new file mode 100755 index 000000000..a25aeddb9 --- /dev/null +++ b/bin/dodoc @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dodoc,v 1.6.2.2 2005/05/15 11:04:21 jstubbs Exp $ + +if [ $# -lt 1 ] ; then + echo "$0: at least one argument needed" 1>&2 + exit 1 +fi + +dir="${D}usr/share/doc/${PF}/${DOCDESTTREE}" +if [ ! -d "${dir}" ] ; then + install -d "${dir}" +fi + +for x in "$@" ; do + if [ -s "${x}" ] ; then + install -m0644 "${x}" "${dir}" + gzip -f -9 "${dir}/${x##*/}" + elif [ ! -e "${x}" ] ; then + echo "dodoc: ${x} does not exist" 1>&2 + fi +done diff --git a/bin/doenvd b/bin/doenvd new file mode 100755 index 000000000..8a794d7f6 --- /dev/null +++ b/bin/doenvd @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doenvd,v 1.2.2.1 2005/01/13 04:51:56 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "doenvd: at least one argument needed" + exit 1 +fi + +tmp_INSDESTTREE="${INSDESTTREE}" +INSDESTTREE=/etc/env.d/ +doins "$@" +INSDESTTREE="${tmp_INSDESTTREE}" +unset tmp_INSDESTTREE diff --git a/bin/doexe b/bin/doexe new file mode 100755 index 000000000..9c2f41093 --- /dev/null +++ b/bin/doexe @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doexe,v 1.10.2.1 2004/12/06 03:01:43 carpaski Exp $ + +mynum=${#} +if [ ${mynum} -lt 1 ] ; then + echo "doexe: at least one argument needed" + exit 1 +fi +if [ ! -d "${D}${EXEDESTTREE}" ] ; then + install -d "${D}${EXEDESTTREE}" +fi + +for x in "$@" ; do + if [ -L "${x}" ] ; then + cp "${x}" "${T}" + mysrc="${T}"/`/usr/bin/basename "${x}"` + elif [ -d "${x}" ] ; then + echo "doexe: warning, skipping directory ${x}" + continue + else + mysrc="${x}" + fi + install ${EXEOPTIONS} "${mysrc}" "${D}${EXEDESTTREE}" +done diff --git a/bin/dohard b/bin/dohard new file mode 100755 index 000000000..7313e2f24 --- /dev/null +++ b/bin/dohard @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dohard,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -ne 2 ] ; then + echo "${0}: two arguments needed" + exit 1 +fi + +mysrc="${1}" +mydest="${2}" +ln -f "${D}${mysrc}" "${D}${mydest}" diff --git a/bin/dohtml b/bin/dohtml new file mode 100755 index 000000000..50e13924a --- /dev/null +++ b/bin/dohtml @@ -0,0 +1,159 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dohtml,v 1.14.2.1 2004/10/27 14:39:29 jstubbs Exp $ + +# +# Typical usage: +# dohtml -r docs/* +# - put all files and directories in docs into /usr/share/doc/${PF}/html +# dohtml foo.html +# - put foo.html into /usr/share/doc/${PF}/html +# +# +# Detailed usage: +# dohtml <list-of-files> +# - will install the files in the list of files (space-separated list) into +# /usr/share/doc/${PF}/html, provided the file ends in .html, .png, .jpg +# or .css +# dohtml -r <list-of-files-and-directories> +# - will do as 'dohtml', but recurse into all directories, as long as the +# directory name is not CVS +# dohtml -A jpe,java [-r] <list-of-files[-and-directories]> +# - will do as 'dohtml' but add .jpe,.java (default filter list is +# added to your list) +# dohtml -a png,gif,html,htm [-r] <list-of-files[-and-directories]> +# - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter +# list is ignored) +# dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories> +# - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS +# + +import os +import string +import sys +import types + +def dodir(path): + os.system("install -d '%s'" % path) + +def dofile(src,dst): + + os.system("install -m0644 '%s' '%s'" % (src, dst)) + +def install(basename, dirname, options, prefix=""): + + fullpath = basename + if prefix: fullpath = prefix + "/" + fullpath + if dirname: fullpath = dirname + "/" + fullpath + + if options.DOCDESTTREE: + destdir = options.D + "usr/share/doc/" + options.PF + "/" + options.DOCDESTTREE + "/" + options.doc_prefix + "/" + prefix + else: + destdir = options.D + "usr/share/doc/" + options.PF + "/html/" + options.doc_prefix + "/" + prefix + + if os.path.isfile(fullpath): + ext = os.path.splitext(basename)[1] + if (len(ext) and ext[1:] in options.allowed_exts) or basename in options.allowed_files: + dodir(destdir) + dofile(fullpath, destdir + "/" + basename) + elif options.recurse and os.path.isdir(fullpath) and \ + basename not in options.disallowed_dirs: + for i in os.listdir(fullpath): + pfx = basename + if prefix: pfx = prefix + "/" + pfx + install(i, dirname, options, pfx) + +class OptionsClass: + def __init__(self): + self.PF = "" + self.D = "" + self.DOCDESTTREE = "" + + if os.environ.has_key("PF"): + self.PF = os.environ["PF"] + if os.environ.has_key("D"): + self.D = os.environ["D"] + if os.environ.has_key("DOCDESTTREE"): + self.DOCDESTTREE = os.environ["DOCDESTTREE"] + + self.allowed_exts = [ 'png', 'gif', 'html', 'htm', 'jpg', 'css', 'js' ] + self.allowed_files = [] + self.disallowed_dirs = [ 'CVS' ] + self.recurse = False + self.verbose = False + self.doc_prefix = "" + +def print_help(): + opts = OptionsClass() + + print "dohtml [-a .foo,.bar] [-A .foo,.bar] [-f foo,bar] [-x foo,bar]" + print " [-r] [-V] <file> [file ...]" + print + print " -a Set the list of allowed to those that are specified." + print " Default:", string.join(opts.allowed_exts, ",") + print " -A Extend the list of allowed file types." + print " -f Set list of allowed extensionless file names." + print " -x Set directories to be excluded from recursion." + print " Default:", string.join(opts.disallowed_dirs, ",") + print " -r Install files and directories recursively." + print " -V Be verbose." + print + +def parse_args(): + options = OptionsClass() + args = [] + + x = 1 + while x < len(sys.argv): + arg = sys.argv[x] + if arg in ["-h","-r","-V"]: + if arg == "-h": + print_help() + sys.exit(0) + elif arg == "-r": + options.recurse = True + elif arg == "-V": + options.verbose = True + elif sys.argv[x] in ["-A","-a","-f","-x","-p"]: + x += 1 + if x == len(sys.argv): + print_help() + sys.exit(0) + elif arg == "-p": + options.doc_prefix = sys.argv[x] + else: + values = string.split(sys.argv[x], ",") + if arg == "-A": + options.allowed_exts.extend(values) + elif arg == "-a": + options.allowed_exts = values + elif arg == "-f": + options.allowed_files = values + elif arg == "-x": + options.disallowed_dirs = values + else: + args.append(sys.argv[x]) + x += 1 + + return (options, args) + +def main(): + + (options, args) = parse_args() + + if type(options.allowed_exts) == types.StringType: + options.allowed_exts = options.allowed_exts.split(",") + + if options.verbose: + print "Allowed extensions:", options.allowed_exts + print "Document prefix : '" + options.doc_prefix + "'" + print "Allowed files :", options.allowed_files + + for x in args: + basename = os.path.basename(x) + dirname = os.path.dirname(x) + install(basename, dirname, options) + +if __name__ == "__main__": + main() diff --git a/bin/doinfo b/bin/doinfo new file mode 100755 index 000000000..a8d7f4d7e --- /dev/null +++ b/bin/doinfo @@ -0,0 +1,21 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doinfo,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "doinfo: at least one argument needed" + exit 1 +fi +if [ ! -d "${D}usr/share/info" ] ; then + install -d "${D}usr/share/info" +fi + +for x in "$@" ; do + if [ -e "${x}" ] ; then + install -m0644 "${x}" "${D}usr/share/info" + gzip -f -9 "${D}usr/share/info/${x##*/}" + else + echo "doinfo: ${x} does not exist" + fi +done diff --git a/bin/doinitd b/bin/doinitd new file mode 100755 index 000000000..d4f725ab4 --- /dev/null +++ b/bin/doinitd @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doinitd,v 1.2.2.1 2005/01/13 04:51:56 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "doinitd: at least one argument needed" + exit 1 +fi + +tmp_EXEDESTTREE="${EXEDESTTREE}" +EXEDESTTREE=/etc/init.d/ +doexe "$@" +EXEDESTTREE="${tmp_EXEDESTTREE}" +unset tmp_EXEDESTTREE diff --git a/bin/doins b/bin/doins new file mode 100755 index 000000000..551905e93 --- /dev/null +++ b/bin/doins @@ -0,0 +1,53 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doins,v 1.7.2.2 2004/12/17 22:25:13 carpaski Exp $ + +if [ $# -lt 1 ] ; then + echo "${0}: at least one argument needed" + exit 1 +fi + +if [ "${1}" == "-r" ] ; then + DOINSRECUR=y + shift +else + DOINSRECUR=n +fi +[ -z "${INSDEPTH}" ] && declare -i INSDEPTH=0 +if [ ${INSDEPTH} -gt 30 ] ; then + echo "${0}: sanity check ... 30 directories is too much :(" + exit 1 +fi + +if [ "${INSDESTTREE%${D}*}" == "" ]; then + echo "-------------------------------------------------------" 1>&2 + echo "You should not use \${D} with helpers." 1>&2 + echo " --> ${INSDESTTREE}" 1>&2 + echo "-------------------------------------------------------" 1>&2 + #exit 1 +fi + +[ ! -d "${D}${INSDESTTREE}" ] && dodir "${INSDESTTREE}" + +for x in "$@" ; do + if [ -L "$x" ] ; then + cp "$x" "${T}" + mysrc="${T}/$(/usr/bin/basename "${x}")" + elif [ -d "$x" ] ; then + if [ "${DOINSRECUR}" == "n" ] ; then + continue + fi + + mydir="${INSDESTTREE}/$(basename "${x}")" + find "${x}" -mindepth 1 -maxdepth 1 -exec \ + env \ + INSDESTTREE="${mydir}" \ + INSDEPTH=$((INSDEPTH+1)) \ + doins -r {} \; + continue + else + mysrc="${x}" + fi + install ${INSOPTIONS} "${mysrc}" "${D}${INSDESTTREE}" +done diff --git a/bin/dojar b/bin/dojar new file mode 100755 index 000000000..77dadfee0 --- /dev/null +++ b/bin/dojar @@ -0,0 +1,54 @@ +#!/bin/sh +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dojar,v 1.8 2004/10/04 13:56:50 vapier Exp $ +# Author Karl Trygve Kalleberg <karltk@gentoo.org> + +# +# Typical usage: +# dojar foo.jar bar.jar +# - installs foo.jar and bar.jar into /usr/share/${PN}/lib, and adds them +# both to /usr/share/${PN}/classpath.env +# +# Detailed usage +# dojar <list-of-jars> +# - installs <list-of-jars> into /usr/share/${PN}/lib and adds each to +# /usr/share/${PN}/classpath.env. +# +# The classpath.env file is currently merely a convenience for the user as +# it allows him to: +# export CLASSPATH=${CLASSPATH}:`cat /usr/share/foo/classpath.env` +# +# For many packages that set FOO_HOME, placing the jar files into +# lib will allow the user to set FOO_HOME=/usr/share/foo and have the +# scripts work as expected. +# +# Possibly a jarinto will be needed in the future. +# + +if [ -z "$JARDESTTREE" ] ; then + JARDESTTREE="lib" +fi + +jarroot="${DESTTREE}/share/${PN}/" +jardest="${DESTTREE}/share/${PN}/${JARDESTTREE}/" +pf="${D}${jarroot}/package.env" + +dodir "${jardest}" + +for i in $* ; do + bn="$(basename $i)" + + if [ -f "$pf" ] ; then + oldcp=`grep "CLASSPATH=" "$pf" | sed "s/CLASSPATH=//"` + grep -v "CLASSPATH=" "$pf" > "${pf}.new" + echo "CLASSPATH=${oldcp}:${jardest}${bn}" >> "${pf}.new" + mv "${pf}.new" "$pf" + else + echo "DESCRIPTION=\"${DESCRIPTION}\"" > "$pf" + echo "CLASSPATH=${jardest}${bn}" >> "$pf" + fi + + cp "$i" "${D}${jardest}/" + chmod 0444 "${D}${jardest}/${bn}" +done diff --git a/bin/dolib b/bin/dolib new file mode 100755 index 000000000..51b2327d3 --- /dev/null +++ b/bin/dolib @@ -0,0 +1,41 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dolib,v 1.8.2.2 2005/01/12 02:07:15 carpaski Exp $ + +LIBDIR_VAR="LIBDIR_${ABI}" +if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then + CONF_LIBDIR="${!LIBDIR_VAR}" +fi +unset LIBDIR_VAR + +if [ -z "${CONF_LIBDIR}" ]; then + # we need this to default to lib so that things dont break + CONF_LIBDIR="lib" +fi +libdir="${D}${DESTTREE}/${CONF_LIBDIR}" +for X in 1 2 3; do + # The escaping is weird. It will break if you escape the last one. + libdir="${libdir//\/\///}" +done + + +if [ ${#} -lt 1 ] ; then + echo "${0}: at least one argument needed" + exit 1 +fi +if [ ! -d "${libdir}" ] ; then + install -d "${libdir}" +fi + +for x in "$@" ; do + if [ -e "${x}" ] ; then + if [ ! -L "${x}" ] ; then + install ${LIBOPTIONS} "${x}" "${libdir}" + else + ln -s "$(readlink "${x}")" "${libdir}/${x}" + fi + else + echo "${0}: ${x} does not exist" + fi +done diff --git a/bin/dolib.a b/bin/dolib.a new file mode 100755 index 000000000..f7cced1c6 --- /dev/null +++ b/bin/dolib.a @@ -0,0 +1,7 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dolib.a,v 1.8 2004/10/10 10:07:20 carpaski Exp $ + +exec env LIBOPTIONS="-m0644" \ + dolib "$@" diff --git a/bin/dolib.so b/bin/dolib.so new file mode 100755 index 000000000..aa6df7db8 --- /dev/null +++ b/bin/dolib.so @@ -0,0 +1,7 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dolib.so,v 1.12 2004/10/10 10:07:20 carpaski Exp $ + +exec env LIBOPTIONS="-m0755" \ + dolib "$@" diff --git a/bin/doman b/bin/doman new file mode 100755 index 000000000..5c23ea0d2 --- /dev/null +++ b/bin/doman @@ -0,0 +1,52 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/doman,v 1.13.2.2 2005/07/29 05:55:34 vapier Exp $ + +if [ $# -lt 1 ] ; then + echo "$0: at least one argument needed" 1>&2 + exit 1 +fi + +BASE="/usr/share" +i18n="" + +for x in "$@" ; do + if [ "${x:0:6}" == "-i18n=" ] ; then + i18n="${x:6}/" + fi + if [ "${x}" == ".keep" ] ; then + continue + fi + + suffix=${x##*.} + + if [ "$suffix" == "gz" ] ; then + compressed="gz" + realname="${x%.*}" + suffix="${realname##*.}" + else + realname="$x" + compressed="" + fi + + mandir=${i18n}man${suffix:0:1} + + if echo ${mandir} | egrep -q 'man[0-9n](|f|p|pm)$' -; then + if [ -s "${x}" ] ; then + if [ ! -d "${D}${BASE}/man/${mandir}" ] ; then + install -d "${D}${BASE}/man/${mandir}" + fi + + install -m0644 "${x}" "${D}${BASE}/man/${mandir}" + + if [ -z "${compressed}" ] ; then + gzip -f -9 "${D}${BASE}/man/${mandir}/${x##*/}" + fi + else + echo "doman: ${x} does not exist" 1>&2 + fi + else + echo "doman: '${x}' is probably not a man page; skipping" 1>&2 + fi +done diff --git a/bin/domo b/bin/domo new file mode 100755 index 000000000..ca3cf4b4e --- /dev/null +++ b/bin/domo @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/domo,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +mynum=${#} +if [ ${mynum} -lt 1 ] ; then + echo "${0}: at least one argument needed" + exit 1 +fi +if [ ! -d "${D}${DESTTREE}/share/locale" ] ; then + install -d "${D}${DESTTREE}/share/locale/" +fi + +for x in "$@" ; do + if [ -e "${x}" ] ; then + mytiny="${x##*/}" + mydir="${D}${DESTTREE}/share/locale/${mytiny%.*}/LC_MESSAGES" + if [ ! -d "${mydir}" ] ; then + install -d "${mydir}" + fi + install -m0644 "${x}" "${mydir}/${MOPREFIX}.mo" + else + echo "${0}: ${x} does not exist" + fi +done diff --git a/bin/dopython b/bin/dopython new file mode 100755 index 000000000..a3ffab968 --- /dev/null +++ b/bin/dopython @@ -0,0 +1,23 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dopython,v 1.8 2004/10/04 13:56:50 vapier Exp $ + +import sys +sys.path = ["/usr/lib/portage/pym"]+sys.path + +from sys import * +import portage +import types +mycommand=argv[1]+"(" +x=2 +while (x<len(argv)): + if x==(len(argv)-1): + mycommand=mycommand+'"'+argv[x]+'"' + else: + mycommand=mycommand+'"'+argv[x]+'",' + x=x+1 +mycommand=mycommand+")" +exec("myresult="+mycommand) +if type(myresult)==types.IntType: + exit(myresult) diff --git a/bin/dosbin b/bin/dosbin new file mode 100755 index 000000000..960d38758 --- /dev/null +++ b/bin/dosbin @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dosbin,v 1.11 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -lt 1 ] ; then + echo "${0}: at least one argument needed" + exit 1 +fi +if [ ! -d "${D}${DESTTREE}/sbin" ] ; then + install -d "${D}${DESTTREE}/sbin" || exit 2 +fi + +for x in "$@" ; do + if [ -x "${x}" ] ; then + #if executable, use existing perms + install -m0755 "${x}" "${D}${DESTTREE}/sbin" || exit 3 + else + #otherwise, use reasonable defaults + echo ">>> dosbin: making ${x} executable..." + if [ "$USERLAND" == "GNU" ]; then + install -m0755 -o root -g root "${x}" "${D}${DESTTREE}/sbin" || exit 4 + else + install -m0755 -o root -g wheel "${x}" "${D}${DESTTREE}/sbin" || exit 4 + fi + fi +done diff --git a/bin/dosed b/bin/dosed new file mode 100755 index 000000000..2c53b22d3 --- /dev/null +++ b/bin/dosed @@ -0,0 +1,22 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dosed,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +mysed="s:${D}::g" + +for x in "$@" ; do + y="${D}${x}" + if [ -a "${y}" ] ; then + if [ -f "${y}" ] ; then + mysrc="${T}/${y##*/}" + cp "${y}" "${mysrc}" + sed -e "${mysed}" "${mysrc}" > "${y}" + else + echo "${y} is not a regular file!" + exit 1 + fi + else + mysed="${x}" + fi +done diff --git a/bin/dosym b/bin/dosym new file mode 100755 index 000000000..ca8cb713f --- /dev/null +++ b/bin/dosym @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/dosym,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -ne 2 ] ; then + echo "${0}: two arguments needed" + exit 1 +fi + +target="${1}" +linkname="${2}" +ln -snf "${target}" "${D}${linkname}" diff --git a/bin/ebuild b/bin/ebuild new file mode 100755 index 000000000..2c4ed713d --- /dev/null +++ b/bin/ebuild @@ -0,0 +1,61 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/ebuild,v 1.18.2.3 2005/05/07 04:32:59 ferringb Exp $ + +import os,sys +sys.path = ["/usr/lib/portage/pym"]+sys.path +import portage_util + +def getroot(): + try: + a=os.environ["ROOT"] + if a == '/': + return '/' + except SystemExit, e: + raise # Needed else we can't exit. + except: + return '/' + return os.path.normpath(a)+'/' + +os.environ["PORTAGE_CALLER"]="ebuild" + +if len(sys.argv)<=2: + print "expecting two arguments." + sys.exit(1) + +import getopt + +debug=0 + +opts,pargs=getopt.getopt(sys.argv[1:],'',['debug']) +for opt in opts: + if opt[0]=='--debug': + debug=1 + +if "merge" in pargs: + print "Disabling noauto in features... merge disables it. (qmerge doesn't)" + os.environ["FEATURES"] = os.environ.get("FEATURES", "") + " -noauto" + +import portage + +for x in pargs[1:]: + try: + tmpsettings = portage.config(clone=portage.settings) + + if x in ['clean','config']: + cleanup=1 + else: + cleanup=0 + a=portage.doebuild(pargs[0],x,getroot(),tmpsettings,debug=debug,cleanup=cleanup) + except KeyboardInterrupt: + print "(interrupted by user -- ctrl-C?)" + a=1 + except IOError: + a=1 + print "ebuild: this ebuild generated output during the depend phase (bad)" + if a == None: + portage_util.writemsg("Could not run the required binary?\n") + sys.exit(127) + if a: + sys.exit(a) diff --git a/bin/ebuild.sh b/bin/ebuild.sh new file mode 100755 index 000000000..3271859ea --- /dev/null +++ b/bin/ebuild.sh @@ -0,0 +1,1868 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/ebuild.sh,v 1.201.2.42 2005/08/20 17:24:30 jstubbs Exp $ + +export SANDBOX_PREDICT="${SANDBOX_PREDICT}:/proc/self/maps:/dev/console:/usr/lib/portage/pym:/dev/random" +export SANDBOX_WRITE="${SANDBOX_WRITE}:/dev/shm:${PORTAGE_TMPDIR}" +export SANDBOX_READ="${SANDBOX_READ}:/dev/shm:${PORTAGE_TMPDIR}" + +if [ ! -z "${PORTAGE_GPG_DIR}" ]; then + SANDBOX_PREDICT="${SANDBOX_PREDICT}:${PORTAGE_GPG_DIR}" +fi + +if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "nofetch" ]; then + if [ -f "${T}/environment" ]; then + source "${T}/environment" &>/dev/null + fi +fi + +if [ -n "$#" ]; then + ARGS="${*}" +fi + +declare -rx EBUILD_PHASE="$*" + +# Prevent aliases from causing portage to act inappropriately. +# Make sure it's before everything so we don't mess aliases that follow. +unalias -a + +# Unset some variables that break things. +unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE + +# We need this next line for "die" and "assert". It expands +# It _must_ preceed all the calls to die and assert. +shopt -s expand_aliases +alias die='diefunc "$FUNCNAME" "$LINENO" "$?"' +alias assert='_pipestatus="${PIPESTATUS[*]}"; [[ "${_pipestatus// /}" -eq 0 ]] || diefunc "$FUNCNAME" "$LINENO" "$_pipestatus"' +alias save_IFS='[ "${IFS:-unset}" != "unset" ] && old_IFS="${IFS}"' +alias restore_IFS='if [ "${old_IFS:-unset}" != "unset" ]; then IFS="${old_IFS}"; unset old_IFS; else unset IFS; fi' + +OCC="$CC" +OCXX="$CXX" +source /etc/profile.env &>/dev/null +if [ -f "${PORTAGE_BASHRC}" ]; then + source "${PORTAGE_BASHRC}" +fi +[ ! -z "$OCC" ] && export CC="$OCC" +[ ! -z "$OCXX" ] && export CXX="$OCXX" + +export PATH="/sbin:/usr/sbin:/usr/lib/portage/bin:/bin:/usr/bin:${ROOTPATH}" +[ ! -z "$PREROOTPATH" ] && export PATH="${PREROOTPATH%%:}:$PATH" + +if [ -e /etc/init.d/functions.sh ]; then + source /etc/init.d/functions.sh &>/dev/null +elif [ -e /etc/rc.d/config/functions ]; then + source /etc/rc.d/config/functions &>/dev/null +else + #Mac OS X + source /usr/lib/portage/bin/functions.sh &>/dev/null +fi + +# the sandbox is disabled by default except when overridden in the relevant stages +export SANDBOX_ON="0" + +# sandbox support functions; defined prior to profile.bashrc srcing, since the profile might need to add a default exception (/usr/lib64/conftest fex, bug #60147) +addread() +{ + export SANDBOX_READ="$SANDBOX_READ:$1" +} + +addwrite() +{ + export SANDBOX_WRITE="$SANDBOX_WRITE:$1" +} + +adddeny() +{ + export SANDBOX_DENY="$SANDBOX_DENY:$1" +} + +addpredict() +{ + export SANDBOX_PREDICT="$SANDBOX_PREDICT:$1" +} + + +# source the existing profile.bashrc's. +save_IFS +IFS=$'\n' +for dir in ${PROFILE_PATHS}; do + # Must unset it so that it doesn't mess up assumptions in the RCs. + unset IFS + if [ -f "${dir}/profile.bashrc" ]; then + source "${dir}/profile.bashrc" + fi +done +restore_IFS + + +esyslog() { + # Custom version of esyslog() to take care of the "Red Star" bug. + # MUST follow functions.sh to override the "" parameter problem. + return 0 +} + + +use() { + if useq ${1}; then + return 0 + fi + return 1 +} + +usev() { + if useq ${1}; then + echo "${1}" + return 0 + fi + return 1 +} + +useq() { + local u="${1}" + local neg=0 + if [ "${u:0:1}" == "!" ]; then + u="${u:1}" + neg=1 + fi + local x + + # Make sure we have this USE flag in IUSE + if ! hasq "${u}" ${IUSE} ${E_IUSE} && ! hasq "${u}" ${PORTAGE_ARCHLIST} selinux; then + echo "QA Notice: USE Flag '${u}' not in IUSE for ${CATEGORY}/${PF}" >&2 + fi + + for x in ${USE}; do + if [ "${x}" == "${u}" ]; then + if [ ${neg} -eq 1 ]; then + return 1 + else + return 0 + fi + fi + done + if [ ${neg} -eq 1 ]; then + return 0 + else + return 1 + fi +} + +has() { + if hasq "$@"; then + return 0 + fi + return 1 +} + +hasv() { + if hasq "$@"; then + echo "${1}" + return 0 + fi + return 1 +} + +hasq() { + local x + + local me=$1 + shift + + # All the TTY checks really only help out depend. Which is nice. + # Logging kills all this anyway. Everything becomes a pipe. --NJ + for x in "$@"; do + if [ "${x}" == "${me}" ]; then + return 0 + fi + done + return 1 +} + +has_version() { + if [ "${EBUILD_PHASE}" == "depend" ]; then + echo -n "QA Notice: has_version() in global scope: " >&2 + if [ ${ECLASS_DEPTH} -gt 0 ]; then + echo "eclass ${ECLASS}" >&2 + else + echo "${CATEGORY}/${PF}" >&2 + fi + fi + # return shell-true/shell-false if exists. + # Takes single depend-type atoms. + if /usr/lib/portage/bin/portageq 'has_version' "${ROOT}" "$1"; then + return 0 + else + return 1 + fi +} + +portageq() { + if [ "${EBUILD_PHASE}" == "depend" ]; then + echo -n "QA Notice: portageq in global scope: " >&2 + if [ ${ECLASS_DEPTH} -gt 0 ]; then + echo "eclass ${ECLASS}" >&2 + else + echo "${CATEGORY}/${PF}" >&2 + fi + fi + /usr/lib/portage/bin/portageq "$@" +} + + +# ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- + + +best_version() { + if [ "${EBUILD_PHASE}" == "depend" ]; then + echo -n "QA Notice: best_version() in global scope: " >&2 + if [ ${ECLASS_DEPTH} -gt 0 ]; then + echo "eclass ${ECLASS}" >&2 + else + echo "${CATEGORY}/${PF}" >&2 + fi + fi + # returns the best/most-current match. + # Takes single depend-type atoms. + /usr/lib/portage/bin/portageq 'best_version' "${ROOT}" "$1" +} + +use_with() { + if [ -z "$1" ]; then + echo "!!! use_with() called without a parameter." >&2 + echo "!!! use_with <USEFLAG> [<flagname> [value]]" >&2 + return 1 + fi + + local UW_SUFFIX="" + if [ ! -z "${3}" ]; then + UW_SUFFIX="=${3}" + fi + + local UWORD="$2" + if [ -z "${UWORD}" ]; then + UWORD="$1" + fi + + if useq $1; then + echo "--with-${UWORD}${UW_SUFFIX}" + else + echo "--without-${UWORD}" + fi + return 0 +} + +use_enable() { + if [ -z "$1" ]; then + echo "!!! use_enable() called without a parameter." >&2 + echo "!!! use_enable <USEFLAG> [<flagname> [value]]" >&2 + return 1 + fi + + local UE_SUFFIX="" + if [ ! -z "${3}" ]; then + UE_SUFFIX="=${3}" + fi + + local UWORD="$2" + if [ -z "${UWORD}" ]; then + UWORD="$1" + fi + + if useq $1; then + echo "--enable-${UWORD}${UE_SUFFIX}" + else + echo "--disable-${UWORD}" + fi + return 0 +} + +diefunc() { + local funcname="$1" lineno="$2" exitcode="$3" + shift 3 + echo >&2 + echo "!!! ERROR: $CATEGORY/$PF failed." >&2 + echo "!!! Function $funcname, Line $lineno, Exitcode $exitcode" >&2 + echo "!!! ${*:-(no error message)}" >&2 + echo "!!! If you need support, post the topmost build error, NOT this status message." >&2 + echo >&2 + exit 1 +} + +#if no perms are specified, dirs/files will have decent defaults +#(not secretive, but not stupid) +umask 022 +export DESTTREE=/usr +export INSDESTTREE="" +export EXEDESTTREE="" +export DOCDESTTREE="" +export INSOPTIONS="-m0644" +export EXEOPTIONS="-m0755" +export LIBOPTIONS="-m0644" +export DIROPTIONS="-m0755" +export MOPREFIX=${PN} + +check_KV() +{ + if [ -z "${KV}" ]; then + eerror "" + eerror "Could not determine your kernel version." + eerror "Make sure that you have /usr/src/linux symlink." + eerror "And that said kernel has been configured." + eerror "You can also simply run the following command" + eerror "in the kernel referenced by /usr/src/linux:" + eerror " make include/linux/version.h" + eerror "" + die + fi +} + +# adds ".keep" files so that dirs aren't auto-cleaned +keepdir() +{ + dodir "$@" + local x + if [ "$1" == "-R" ] || [ "$1" == "-r" ]; then + shift + find "$@" -type d -printf "${D}/%p/.keep\n" | tr "\n" "\0" | $XARGS -0 -n100 touch || die "Failed to recursive create .keep files" + else + for x in "$@"; do + touch "${D}/${x}/.keep" || die "Failed to create .keep in ${D}/${x}" + done + fi +} + +strip_duplicate_slashes () { + if [ -n "${1}" ]; then + local removed="${1/\/\///}" + [ "${removed}" != "${removed/\/\///}" ] && removed=$(strip_duplicate_slashes "${removed}") + echo ${removed} + fi +} + +econf() { + local LOCAL_EXTRA_ECONF="${EXTRA_ECONF}" + + if [ -z "${ECONF_SOURCE}" ]; then + ECONF_SOURCE="." + fi + if [ -x "${ECONF_SOURCE}/configure" ]; then + if [ -e /usr/share/gnuconfig/ ]; then + local x + for x in $(find "${WORKDIR}" -type f '(' -name config.guess -o -name config.sub ')') ; do + echo " * econf: updating ${x/${WORKDIR}\/} with /usr/share/gnuconfig/${x##*/}" + cp -f /usr/share/gnuconfig/${x##*/} ${x} + done + fi + + if [ ! -z "${CBUILD}" ]; then + LOCAL_EXTRA_ECONF="--build=${CBUILD} ${LOCAL_EXTRA_ECONF}" + fi + + if [ ! -z "${CTARGET}" ]; then + LOCAL_EXTRA_ECONF="--target=${CTARGET} ${LOCAL_EXTRA_ECONF}" + fi + + # if the profile defines a location to install libs to aside from default, pass it on. + # if the ebuild passes in --libdir, they're responsible for the conf_libdir fun. + LIBDIR_VAR="LIBDIR_${ABI}" + if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then + CONF_LIBDIR="${!LIBDIR_VAR}" + fi + unset LIBDIR_VAR + if [ -n "${CONF_LIBDIR}" ] && [ "${*/--libdir}" == "$*" ]; then + if [ "${*/--exec-prefix}" != "$*" ]; then + local args="$(echo $*)" + local -a pref=($(echo ${args/*--exec-prefix[= ]})) + CONF_PREFIX=${pref} + [ "${CONF_PREFIX:0:1}" != "/" ] && CONF_PREFIX="/${CONF_PREFIX}" + elif [ "${*/--prefix}" != "$*" ]; then + local args="$(echo $*)" + local -a pref=($(echo ${args/*--prefix[= ]})) + CONF_PREFIX=${pref} + [ "${CONF_PREFIX:0:1}" != "/" ] && CONF_PREFIX="/${CONF_PREFIX}" + else + CONF_PREFIX="/usr" + fi + export CONF_PREFIX + [ "${CONF_LIBDIR:0:1}" != "/" ] && CONF_LIBDIR="/${CONF_LIBDIR}" + + CONF_LIBDIR_RESULT="${CONF_PREFIX}${CONF_LIBDIR}" + for X in 1 2 3; do + # The escaping is weird. It will break if you escape the last one. + CONF_LIBDIR_RESULT="${CONF_LIBDIR_RESULT//\/\///}" + done + + LOCAL_EXTRA_ECONF="--libdir=${CONF_LIBDIR_RESULT} ${LOCAL_EXTRA_ECONF}" + fi + + echo "${ECONF_SOURCE}/configure" \ + --prefix=/usr \ + --host=${CHOST} \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --datadir=/usr/share \ + --sysconfdir=/etc \ + --localstatedir=/var/lib \ + "$@" \ + ${LOCAL_EXTRA_ECONF} + + if ! "${ECONF_SOURCE}/configure" \ + --prefix=/usr \ + --host=${CHOST} \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --datadir=/usr/share \ + --sysconfdir=/etc \ + --localstatedir=/var/lib \ + "$@" \ + ${LOCAL_EXTRA_ECONF}; then + + if [ -s config.log ]; then + echo + echo "!!! Please attach the config.log to your bug report:" + echo "!!! ${PWD}/config.log" + fi + die "econf failed" + fi + else + die "no configure script found" + fi +} + +einstall() { + # CONF_PREFIX is only set if they didn't pass in libdir above. + LIBDIR_VAR="LIBDIR_${ABI}" + if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then + CONF_LIBDIR="${!LIBDIR_VAR}" + fi + unset LIBDIR_VAR + if [ -n "${CONF_LIBDIR}" ] && [ "${CONF_PREFIX:-unset}" != "unset" ]; then + EI_DESTLIBDIR="${D}/${CONF_PREFIX}/${CONF_LIBDIR}" + EI_DESTLIBDIR="$(strip_duplicate_slashes ${EI_DESTLIBDIR})" + EXTRA_EINSTALL="libdir=${EI_DESTLIBDIR} ${EXTRA_EINSTALL}" + unset EI_DESTLIBDIR + fi + + if [ -f ./[mM]akefile -o -f ./GNUmakefile ] ; then + if [ ! -z "${PORTAGE_DEBUG}" ]; then + make -n prefix=${D}/usr \ + datadir=${D}/usr/share \ + infodir=${D}/usr/share/info \ + localstatedir=${D}/var/lib \ + mandir=${D}/usr/share/man \ + sysconfdir=${D}/etc \ + ${EXTRA_EINSTALL} \ + "$@" install + fi + make prefix=${D}/usr \ + datadir=${D}/usr/share \ + infodir=${D}/usr/share/info \ + localstatedir=${D}/var/lib \ + mandir=${D}/usr/share/man \ + sysconfdir=${D}/etc \ + ${EXTRA_EINSTALL} \ + "$@" install || die "einstall failed" + else + die "no Makefile found" + fi +} + +pkg_setup() +{ + return +} + +pkg_nofetch() +{ + [ -z "${SRC_URI}" ] && return + + echo "!!! The following are listed in SRC_URI for ${PN}:" + for MYFILE in `echo ${SRC_URI}`; do + echo "!!! $MYFILE" + done +} + +src_unpack() { + if [ "${A}" != "" ]; then + unpack ${A} + fi +} + +src_compile() { + if [ -x ./configure ]; then + econf + fi + if [ -f Makefile ] || [ -f GNUmakefile ] || [ -f makefile ]; then + emake || die "emake failed" + fi +} + +src_test() +{ + addpredict / + if make check -n &> /dev/null; then + echo ">>> Test phase [check]: ${CATEGORY}/${PF}" + if ! make check; then + hasq test $FEATURES && die "Make check failed. See above for details." + hasq test $FEATURES || eerror "Make check failed. See above for details." + fi + elif make test -n &> /dev/null; then + echo ">>> Test phase [test]: ${CATEGORY}/${PF}" + if ! make test; then + hasq test $FEATURES && die "Make test failed. See above for details." + hasq test $FEATURES || eerror "Make test failed. See above for details." + fi + else + echo ">>> Test phase [none]: ${CATEGORY}/${PF}" + fi + SANDBOX_PREDICT="${SANDBOX_PREDICT%:/}" +} + +src_install() +{ + return +} + +pkg_preinst() +{ + return +} + +pkg_postinst() +{ + return +} + +pkg_prerm() +{ + return +} + +pkg_postrm() +{ + return +} + +pkg_config() +{ + eerror "This ebuild does not have a config function." +} + +# Used to generate the /lib/cpp and /usr/bin/cc wrappers +gen_wrapper() { + cat > $1 << END +#!/bin/sh + +$2 "\$@" +END + + chmod 0755 $1 +} + +dyn_setup() +{ + pkg_setup +} + +dyn_unpack() { + trap "abort_unpack" SIGINT SIGQUIT + local newstuff="no" + if [ -e "${WORKDIR}" ]; then + local x + local checkme + for x in ${AA}; do + echo ">>> Checking ${x}'s mtime..." + if [ "${DISTDIR}/${x}" -nt "${WORKDIR}" ]; then + echo ">>> ${x} has been updated; recreating WORKDIR..." + newstuff="yes" + rm -rf "${WORKDIR}" + break + fi + done + if [ "${EBUILD}" -nt "${WORKDIR}" ]; then + echo ">>> ${EBUILD} has been updated; recreating WORKDIR..." + newstuff="yes" + rm -rf "${WORKDIR}" + elif [ ! -f "${BUILDDIR}/.unpacked" ]; then + echo ">>> Not marked as unpacked; recreating WORKDIR..." + newstuff="yes" + rm -rf "${WORKDIR}" + fi + fi + if [ -e "${WORKDIR}" ]; then + if [ "$newstuff" == "no" ]; then + echo ">>> WORKDIR is up-to-date, keeping..." + return 0 + fi + fi + + install -m0700 -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'" + [ -d "$WORKDIR" ] && cd "${WORKDIR}" + echo ">>> Unpacking source..." + src_unpack + touch "${BUILDDIR}/.unpacked" || die "IO Failure -- Failed 'touch .unpacked' in BUILDIR" + echo ">>> Source unpacked." + cd "$BUILDDIR" + trap SIGINT SIGQUIT +} + +dyn_clean() { + if [ "$USERLAND" == "BSD" ] && type -p chflags &>/dev/null; then + chflags -R noschg,nouchg,nosappnd,nouappnd,nosunlnk,nouunlnk \ + "${BUILDDIR}" + fi + + if [ "$USERLAND" == "Darwin" ] && type -p chflags &>/dev/null; then + chflags -R noschg,nouchg,nosappnd,nouappnd "${BUILDDIR}" + fi + + rm -rf "${BUILDDIR}/image" + + if ! hasq keeptemp $FEATURES; then + rm -rf "${T}" + else + mv "${T}/environment" "${T}/environment.keeptemp" + fi + + if ! hasq keepwork $FEATURES; then + rm -rf "${BUILDDIR}/.unpacked" + rm -rf "${BUILDDIR}/.compiled" + rm -rf "${BUILDDIR}/.tested" + rm -rf "${BUILDDIR}/.installed" + rm -rf "${BUILDDIR}/.packaged" + rm -rf "${BUILDDIR}/build-info" + rm -rf "${WORKDIR}" + fi + + if [ -f "${BUILDDIR}/.unpacked" ]; then + find "${BUILDDIR}" -type d ! -regex "^${WORKDIR}" | sort -r | tr "\n" "\0" | $XARGS -0 rmdir &>/dev/null + fi + + if [ -z "$(find "${BUILDDIR}" -mindepth 1 -maxdepth 1)" ]; then + rmdir "${BUILDDIR}" + fi + true +} + +into() { + if [ $1 == "/" ]; then + export DESTTREE="" + else + export DESTTREE=$1 + if [ ! -d "${D}${DESTTREE}" ]; then + install -d "${D}${DESTTREE}" + fi + fi +} + +insinto() { + if [ "$1" == "/" ]; then + export INSDESTTREE="" + else + export INSDESTTREE=$1 + if [ ! -d "${D}${INSDESTTREE}" ]; then + install -d "${D}${INSDESTTREE}" + fi + fi +} + +exeinto() { + if [ "$1" == "/" ]; then + export EXEDESTTREE="" + else + export EXEDESTTREE="$1" + if [ ! -d "${D}${EXEDESTTREE}" ]; then + install -d "${D}${EXEDESTTREE}" + fi + fi +} + +docinto() { + if [ "$1" == "/" ]; then + export DOCDESTTREE="" + else + export DOCDESTTREE="$1" + if [ ! -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}" ]; then + install -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}" + fi + fi +} + +insopts() { + INSOPTIONS="" + for x in $*; do + #if we have a debug build, let's not strip anything + if hasq nostrip $FEATURES $RESTRICT && [ "$x" == "-s" ]; then + continue + else + INSOPTIONS="$INSOPTIONS $x" + fi + done + export INSOPTIONS +} + +diropts() { + DIROPTIONS="" + for x in $*; do + DIROPTIONS="${DIROPTIONS} $x" + done + export DIROPTIONS +} + +exeopts() { + EXEOPTIONS="" + for x in $*; do + #if we have a debug build, let's not strip anything + if hasq nostrip $FEATURES $RESTRICT && [ "$x" == "-s" ]; then + continue + else + EXEOPTIONS="$EXEOPTIONS $x" + fi + done + export EXEOPTIONS +} + +libopts() { + LIBOPTIONS="" + for x in $*; do + #if we have a debug build, let's not strip anything + if hasq nostrip $FEATURES $RESTRICT && [ "$x" == "-s" ]; then + continue + else + LIBOPTIONS="$LIBOPTIONS $x" + fi + done + export LIBOPTIONS +} + +abort_handler() { + local msg + if [ "$2" != "fail" ]; then + msg="${EBUILD}: ${1} aborted; exiting." + else + msg="${EBUILD}: ${1} failed; exiting." + fi + echo + echo "$msg" + echo + eval ${3} + #unset signal handler + trap SIGINT SIGQUIT +} + +abort_compile() { + abort_handler "src_compile" $1 + rm -f "${BUILDDIR}/.compiled" + exit 1 +} + +abort_unpack() { + abort_handler "src_unpack" $1 + rm -f "${BUILDDIR}/.unpacked" + rm -rf "${BUILDDIR}/work" + exit 1 +} + +abort_package() { + abort_handler "dyn_package" $1 + rm -f "${BUILDDIR}/.packaged" + rm -f "${PKGDIR}"/All/${PF}.t* + exit 1 +} + +abort_test() { + abort_handler "dyn_test" $1 + rm -f "${BUILDDIR}/.tested" + exit 1 +} + +abort_install() { + abort_handler "src_install" $1 + rm -rf "${BUILDDIR}/image" + exit 1 +} + +dyn_compile() { + trap "abort_compile" SIGINT SIGQUIT + [ "${CFLAGS-unset}" != "unset" ] && export CFLAGS + [ "${CXXFLAGS-unset}" != "unset" ] && export CXXFLAGS + [ "${LIBCFLAGS-unset}" != "unset" ] && export LIBCFLAGS + [ "${LIBCXXFLAGS-unset}" != "unset" ] && export LIBCXXFLAGS + [ "${LDFLAGS-unset}" != "unset" ] && export LDFLAGS + [ "${ASFLAGS-unset}" != "unset" ] && export ASFLAGS + + [ "${CCACHE_DIR-unset}" != "unset" ] && export CCACHE_DIR + [ "${CCACHE_SIZE-unset}" != "unset" ] && export CCACHE_SIZE + + [ "${DISTCC_DIR-unset}" == "unset" ] && export DISTCC_DIR="${PORTAGE_TMPDIR}/.distcc" + [ ! -z "${DISTCC_DIR}" ] && addwrite "${DISTCC_DIR}" + + if hasq noauto $FEATURES &>/dev/null && [ ! -f ${BUILDDIR}/.unpacked ]; then + echo + echo "!!! We apparently haven't unpacked... This is probably not what you" + echo "!!! want to be doing... You are using FEATURES=noauto so I'll assume" + echo "!!! that you know what you are doing... You have 5 seconds to abort..." + echo + + echo -ne "\a"; sleep 0.25 &>/dev/null; echo -ne "\a"; sleep 0.25 &>/dev/null + echo -ne "\a"; sleep 0.25 &>/dev/null; echo -ne "\a"; sleep 0.25 &>/dev/null + echo -ne "\a"; sleep 0.25 &>/dev/null; echo -ne "\a"; sleep 0.25 &>/dev/null + echo -ne "\a"; sleep 0.25 &>/dev/null; echo -ne "\a"; sleep 0.25 &>/dev/null + + echo -ne "\a"; sleep 0,25 &>/dev/null; echo -ne "\a"; sleep 0,25 &>/dev/null + echo -ne "\a"; sleep 0,25 &>/dev/null; echo -ne "\a"; sleep 0,25 &>/dev/null + echo -ne "\a"; sleep 0,25 &>/dev/null; echo -ne "\a"; sleep 0,25 &>/dev/null + echo -ne "\a"; sleep 0,25 &>/dev/null; echo -ne "\a"; sleep 0,25 &>/dev/null + sleep 3 + fi + + cd "${BUILDDIR}" + if [ ! -e "build-info" ]; then + mkdir build-info + fi + cp "${EBUILD}" "build-info/${PF}.ebuild" + + if [ ${BUILDDIR}/.compiled -nt "${WORKDIR}" ]; then + echo ">>> It appears that ${PN} is already compiled; skipping." + echo ">>> (clean to force compilation)" + trap SIGINT SIGQUIT + return + fi + if [ -d "${S}" ]; then + cd "${S}" + fi + #our custom version of libtool uses $S and $D to fix + #invalid paths in .la files + export S D + #some packages use an alternative to $S to build in, cause + #our libtool to create problematic .la files + export PWORKDIR="$WORKDIR" + src_compile + #|| abort_compile "fail" + cd "${BUILDDIR}" + touch .compiled + cd build-info + + echo "$ASFLAGS" > ASFLAGS + echo "$CATEGORY" > CATEGORY + echo "$CBUILD" > CBUILD + echo "$CC" > CC + echo "$CDEPEND" > CDEPEND + echo "$CFLAGS" > CFLAGS + echo "$CHOST" > CHOST + echo "$CTARGET" > CTARGET + echo "$CXX" > CXX + echo "$CXXFLAGS" > CXXFLAGS + echo "$DEPEND" > DEPEND + echo "$EXTRA_ECONF" > EXTRA_ECONF + echo "$EXTRA_EINSTALL" > EXTRA_EINSTALL + echo "$EXTRA_EMAKE" > EXTRA_MAKE + echo "$FEATURES" > FEATURES + echo "$INHERITED" > INHERITED + echo "$IUSE" > IUSE + echo "$PKGUSE" > PKGUSE + echo "$LDFLAGS" > LDFLAGS + echo "$LIBCFLAGS" > LIBCFLAGS + echo "$LIBCXXFLAGS" > LIBCXXFLAGS + echo "$LICENSE" > LICENSE + echo "$PDEPEND" > PDEPEND + echo "$PF" > PF + echo "$PROVIDE" > PROVIDE + echo "$RDEPEND" > RDEPEND + echo "$RESTRICT" > RESTRICT + echo "$SLOT" > SLOT + echo "$USE" > USE + + set > environment + export -p | sed 's:declare -rx:declare -x:' >> environment + bzip2 -9 environment + + cp "${EBUILD}" "${PF}.ebuild" + if hasq nostrip $FEATURES $RESTRICT; then + touch DEBUGBUILD + fi + trap SIGINT SIGQUIT +} + +dyn_package() { + trap "abort_package" SIGINT SIGQUIT + cd "${BUILDDIR}/image" + tar cpvf - ./ | bzip2 -f > ../bin.tar.bz2 || die "Failed to create tarball" + cd .. + xpak build-info inf.xpak + tbz2tool join bin.tar.bz2 inf.xpak "${PF}.tbz2" + mv "${PF}.tbz2" "${PKGDIR}/All" || die "Failed to move tbz2 to ${PKGDIR}/All" + rm -f inf.xpak bin.tar.bz2 + if [ ! -d "${PKGDIR}/${CATEGORY}" ]; then + install -d "${PKGDIR}/${CATEGORY}" + fi + ln -sf "../All/${PF}.tbz2" "${PKGDIR}/${CATEGORY}/${PF}.tbz2" || die "Failed to create symlink in ${PKGDIR}/${CATEGORY}" + echo ">>> Done." + cd "${BUILDDIR}" + touch .packaged || die "Failed to 'touch .packaged' in ${BUILDDIR}" + trap SIGINT SIGQUIT +} + + +dyn_test() { + if [ ${BUILDDIR}/.tested -nt "${WORKDIR}" ]; then + echo ">>> It appears that ${PN} has already been tested; skipping." + return + fi + trap "abort_test" SIGINT SIGQUIT + if [ -d "${S}" ]; then + cd "${S}" + fi + if hasq maketest $RESTRICT || hasq test $RESTRICT; then + ewarn "Skipping make test/check due to ebuild restriction." + echo ">>> Test phase [explicitly disabled]: ${CATEGORY}/${PF}" + elif ! hasq test $FEATURES; then + echo ">>> Test phase [not enabled]: ${CATEGORY}/${PF}" + else + echo ">>> Test phase [enabled]: ${CATEGORY}/${PF}" + src_test + fi + + cd "${BUILDDIR}" + touch .tested || die "Failed to 'touch .tested' in ${BUILDDIR}" + trap SIGINT SIGQUIT +} + + + +dyn_install() { + trap "abort_install" SIGINT SIGQUIT + rm -rf "${BUILDDIR}/image" + mkdir "${BUILDDIR}/image" + if [ -d "${S}" ]; then + cd "${S}" + fi + echo + echo ">>> Install ${PF} into ${D} category ${CATEGORY}" + #our custom version of libtool uses $S and $D to fix + #invalid paths in .la files + export S D + #some packages uses an alternative to $S to build in, cause + #our libtool to create problematic .la files + export PWORKDIR="$WORKDIR" + src_install + #|| abort_install "fail" + prepall + cd "${D}" + + declare -i UNSAFE=0 + for i in $(find "${D}/" -type f -perm -2002); do + ((UNSAFE++)) + echo "UNSAFE SetGID: $i" + done + for i in $(find "${D}/" -type f -perm -4002); do + ((UNSAFE++)) + echo "UNSAFE SetUID: $i" + done + + if type -p scanelf > /dev/null ; then + # Make sure we disallow insecure RUNPATH/RPATH's + # Don't want paths that point to the tree where the package was built + # (older, broken libtools would do this). Also check for null paths + # because the loader will search $PWD when it finds null paths. + f=$(scanelf -qyRF '%r %p' "${D}" | grep -E "(${BUILDDIR}|: |::|^ )") + if [[ -n ${f} ]] ; then + echo -ne '\a\n' + echo "QA Notice: the following files contain insecure RUNPATH's" + echo " Please file a bug about this at http://bugs.gentoo.org/" + echo " For more information on this issue, kindly review:" + echo " http://bugs.gentoo.org/81745" + echo "${f}" + echo -ne '\a\n' + die "Insecure binaries detected" + fi + + # Check for setid binaries but are not built with BIND_NOW + f=$(scanelf -qyRF '%b %p' "${D}") + if [[ -n ${f} ]] ; then + echo -ne '\a\n' + echo "QA Notice: the following files are setXid, dyn linked, and using lazy bindings" + echo " This combination is generally discouraged. Try re-emerging the package:" + echo " LDFLAGS='-Wl,-z,now' emerge ${PN}" + echo "${f}" + echo -ne '\a\n' + [[ ${FEATURES/stricter} != "${FEATURES}" ]] \ + && die "Aborting due to lazy bindings" + sleep 1 + fi + + # TEXTREL's are baaaaaaaad + f=$(scanelf -qyRF '%t %p' "${D}") + if [[ -n ${f} ]] ; then + echo -ne '\a\n' + echo "QA Notice: the following files contain runtime text relocations" + echo " Text relocations require a lot of extra work to be preformed by the" + echo " dynamic linker which will cause serious performance impact on IA-32" + echo " and might not function properly on other architectures hppa for example." + echo " If you are a programmer please take a closer look at this package and" + echo " consider writing a patch which addresses this problem." + echo "${f}" + echo -ne '\a\n' + [[ ${FEATURES/stricter} != "${FEATURES}" ]] \ + && die "Aborting due to textrels" + sleep 1 + fi + + # Check for files with executable stacks + f=$(scanelf -qyRF '%e %p' "${D}") + if [[ -n ${f} ]] ; then + echo -ne '\a\n' + echo "QA Notice: the following files contain executable stacks" + echo " Files with executable stacks will not work properly (or at all!)" + echo " on some architectures/operating systems. A bug should be filed" + echo " at http://bugs.gentoo.org/ to make sure the file is fixed." + echo "${f}" + echo -ne '\a\n' + [[ ${FEATURES/stricter} != "${FEATURES}" ]] \ + && die "Aborting due to +x stack" + sleep 1 + fi + + # Save NEEDED information + scanelf -qyRF '%p %n' "${D}" | sed -e 's:^:/:' > "${BUILDDIR}"/build-info/NEEDED + fi + + if [[ ${UNSAFE} > 0 ]] ; then + die "There are ${UNSAFE} unsafe files. Portage will not install them." + fi + + # dumps perms to stdout. if error, no perms dumped. + function stat_perms() { + local f + # only define do_stat if it hasn't been already + if ! type -p do_stat &> /dev/null; then + if ! type -p stat &>/dev/null; then + do_stat() { + # Generic version -- Octal result + python -c "import os,stat; print '%o' % os.stat('$1')[stat.ST_MODE]" + } + else + if [ "${USERLAND}" == "BSD" ] || [ "${USERLAND}" == "Darwin" ]; then + do_stat() { + # BSD version -- Octal result + $(type -p stat) -f '%p' "$1" + } + else + do_stat() { + # Linux version -- Hex result converted to Octal + f=$($(type -p stat) -c '%f' "$1") || return $? + printf '%o' "0x$f" + } + fi + fi + fi + + f=$(do_stat "$@") || return + f="${f:2:4}" + echo $f + } + + local file s + local count=0 + find "${D}/" -user portage | while read file; do + count=$(( $count + 1 )) + [[ ! -L "${file}" ]] && s=$(stat_perms "$file") + if [ -z "${s}" ]; then + ewarn "failed stat_perm'ing $file. User intervention during install isn't wise..." + continue + fi + chown root "$file" + [[ ! -L "${file}" ]] && chmod "$s" "$file" + done + if (( $count > 0 )); then + ewarn "$count files were installed with user portage!" + fi + + count=0 + find "${D}/" -group portage | while read file; do + count=$(( $count + 1 )) + [[ ! -L "${file}" ]] && s=$(stat_perms "$file") + if [ -z "${s}" ]; then + echo "failed stat_perm'ing '$file' . User intervention during install isn't wise..." + continue + fi + chgrp 0 "${file}" + [[ ! -L "${file}" ]] && chmod "$s" "$file" + done + if (( $count > 0 )); then + ewarn "$count files were installed with group portage!" + fi + + unset -f stat_perms + + # Portage regenerates this on the installed system. + if [ -f "${D}/usr/share/info/dir.gz" ]; then + rm -f "${D}/usr/share/info/dir.gz" + fi + + if hasq multilib-strict ${FEATURES} && [ -x /usr/bin/file -a -x /usr/bin/find -a \ + -n "${MULTILIB_STRICT_DIRS}" -a -n "${MULTILIB_STRICT_DENY}" ]; then + MULTILIB_STRICT_EXEMPT=${MULTILIB_STRICT_EXEMPT:-"(perl5|gcc|gcc-lib)"} + for dir in ${MULTILIB_STRICT_DIRS}; do + [ -d "${D}/${dir}" ] || continue + for file in $(find ${D}/${dir} -type f | egrep -v "^${D}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do + file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" && die "File ${file} matches a file type that is not allowed in ${dir}" + done + done + fi + + touch "${BUILDDIR}/.installed" + echo ">>> Completed installing ${PF} into ${D}" + echo + cd ${BUILDDIR} + trap SIGINT SIGQUIT +} + +dyn_preinst() { + # set IMAGE depending if this is a binary or compile merge + [ "${EMERGE_FROM}" == "binary" ] && IMAGE=${PKG_TMPDIR}/${PF}/bin \ + || IMAGE=${D} + + pkg_preinst + + # hopefully this will someday allow us to get rid of the no* feature flags + # we don't want globbing for initial expansion, but afterwards, we do + local shopts=$- + set -o noglob + for no_inst in ${INSTALL_MASK}; do + set +o noglob + einfo "Removing ${no_inst}" + # normal stuff + rm -Rf ${IMAGE}/${no_inst} >&/dev/null + + # we also need to handle globs (*.a, *.h, etc) + find "${IMAGE}" -name ${no_inst} -exec rm -fR {} \; >&/dev/null + done + # set everything back the way we found it + set +o noglob + set -${shopts} + + # remove man pages + if hasq noman $FEATURES; then + rm -fR "${IMAGE}/usr/share/man" + fi + + # remove info pages + if hasq noinfo $FEATURES; then + rm -fR "${IMAGE}/usr/share/info" + fi + + # remove docs + if hasq nodoc $FEATURES; then + rm -fR "${IMAGE}/usr/share/doc" + fi + + # remove share dir if unnessesary + if hasq nodoc $FEATURES -o hasq noman $FEATURES -o hasq noinfo $FEATURES; then + rmdir "${IMAGE}/usr/share" &> /dev/null + fi + + # Smart FileSystem Permissions + if hasq sfperms $FEATURES; then + for i in $(find ${IMAGE}/ -type f -perm -4000); do + ebegin ">>> SetUID: [chmod go-r] $i " + chmod go-r "$i" + eend $? + done + for i in $(find ${IMAGE}/ -type f -perm -2000); do + ebegin ">>> SetGID: [chmod o-r] $i " + chmod o-r "$i" + eend $? + done + fi + + # total suid control. + if hasq suidctl $FEATURES > /dev/null ; then + sfconf=/etc/portage/suidctl.conf + echo ">>> Preforming suid scan in ${IMAGE}" + for i in $(find ${IMAGE}/ -type f \( -perm -4000 -o -perm -2000 \) ); do + if [ -s "${sfconf}" ]; then + suid="`grep ^${i/${IMAGE}/}$ ${sfconf}`" + if [ "${suid}" = "${i/${IMAGE}/}" ]; then + echo "- ${i/${IMAGE}/} is an approved suid file" + else + echo ">>> Removing sbit on non registered ${i/${IMAGE}/}" + for x in 5 4 3 2 1 0; do echo -ne "\a"; sleep 0.25 ; done + echo -ne "\a" + chmod ugo-s "${i}" + grep ^#${i/${IMAGE}/}$ ${sfconf} > /dev/null || { + # sandbox prevents us from writing directly + # to files outside of the sandbox, but this + # can easly be bypassed using the addwrite() function + addwrite "${sfconf}" + echo ">>> Appending commented out entry to ${sfconf} for ${PF}" + ls_ret=`ls -ldh "${i}"` + echo "## ${ls_ret%${IMAGE}*}${ls_ret#*${IMAGE}}" >> ${sfconf} + echo "#${i/${IMAGE}/}" >> ${sfconf} + # no delwrite() eh? + # delwrite ${sconf} + } + fi + else + echo "suidctl feature set but you are lacking a ${sfconf}" + fi + done + fi + + # SELinux file labeling (needs to always be last in dyn_preinst) + if useq selinux; then + # only attempt to label if setfiles is executable + # and 'context' is available on selinuxfs. + if [ -f /selinux/context -a -x /usr/sbin/setfiles ]; then + echo ">>> Setting SELinux security labels" + if [ -f ${POLICYDIR}/file_contexts/file_contexts ]; then + cp -f "${POLICYDIR}/file_contexts/file_contexts" "${T}" + else + make -C "${POLICYDIR}" FC=${T}/file_contexts "${T}/file_contexts" + fi + + addwrite /selinux/context + /usr/sbin/setfiles -r "${IMAGE}" "${T}/file_contexts" "${IMAGE}" \ + || die "Failed to set SELinux security labels." + else + # nonfatal, since merging can happen outside a SE kernel + # like during a recovery situation + echo "!!! Unable to set SELinux security labels" + fi + fi + trap SIGINT SIGQUIT +} + +dyn_spec() { + tar czf "/usr/src/redhat/SOURCES/${PF}.tar.gz" "${O}/${PF}.ebuild" "${O}/files" || die "Failed to create base rpm tarball." + + cat <<__END1__ > ${PF}.spec +Summary: ${DESCRIPTION} +Name: ${PN} +Version: ${PV} +Release: ${PR} +Copyright: GPL +Group: portage/${CATEGORY} +Source: ${PF}.tar.gz +Buildroot: ${D} +%description +${DESCRIPTION} + +${HOMEPAGE} + +%prep +%setup -c + +%build + +%install + +%clean + +%files +/ +__END1__ + +} + +dyn_rpm() { + dyn_spec + rpmbuild -bb "${PF}.spec" || die "Failed to integrate rpm spec file" + install -D "/usr/src/redhat/RPMS/i386/${PN}-${PV}-${PR}.i386.rpm" "${RPMDIR}/${CATEGORY}/${PN}-${PV}-${PR}.rpm" || die "Failed to move rpm" +} + +dyn_help() { + echo + echo "Portage" + echo "Copyright 1999-2004 Gentoo Foundation" + echo + echo "How to use the ebuild command:" + echo + echo "The first argument to ebuild should be an existing .ebuild file." + echo + echo "One or more of the following options can then be specified. If more" + echo "than one option is specified, each will be executed in order." + echo + echo " help : show this help screen" + echo " setup : execute package specific setup actions" + echo " fetch : download source archive(s) and patches" + echo " digest : creates a digest and a manifest file for the package" + echo " manifest : creates a manifest file for the package" + echo " unpack : unpack/patch sources (auto-fetch if needed)" + echo " compile : compile sources (auto-fetch/unpack if needed)" + echo " test : test package (auto-fetch/unpack/compile if needed)" + echo " preinst : execute pre-install instructions" + echo " postinst : execute post-install instructions" + echo " install : installs the package to the temporary install directory" + echo " qmerge : merge image into live filesystem, recording files in db" + echo " merge : does fetch, unpack, compile, install and qmerge" + echo " prerm : execute pre-removal instructions" + echo " postrm : execute post-removal instructions" + echo " unmerge : remove package from live filesystem" + echo " config : execute package specific configuration actions" + echo " package : create tarball package in ${PKGDIR}/All" + echo " rpm : builds a RedHat RPM package" + echo " clean : clean up all source and temporary files" + echo + echo "The following settings will be used for the ebuild process:" + echo + echo " package : ${PF}" + echo " slot : ${SLOT}" + echo " category : ${CATEGORY}" + echo " description : ${DESCRIPTION}" + echo " system : ${CHOST}" + echo " c flags : ${CFLAGS}" + echo " c++ flags : ${CXXFLAGS}" + echo " make flags : ${MAKEOPTS}" + echo -n " build mode : " + if hasq nostrip $FEATURES $RESTRICT; then + echo "debug (large)" + else + echo "production (stripped)" + fi + echo " merge to : ${ROOT}" + echo + if [ -n "$USE" ]; then + echo "Additionally, support for the following optional features will be enabled:" + echo + echo " ${USE}" + fi + echo +} + +# debug-print() gets called from many places with verbose status information useful +# for tracking down problems. The output is in $T/eclass-debug.log. +# You can set ECLASS_DEBUG_OUTPUT to redirect the output somewhere else as well. +# The special "on" setting echoes the information, mixing it with the rest of the +# emerge output. +# You can override the setting by exporting a new one from the console, or you can +# set a new default in make.*. Here the default is "" or unset. + +# in the future might use e* from /etc/init.d/functions.sh if i feel like it +debug-print() { + # if $T isn't defined, we're in dep calculation mode and + # shouldn't do anything + [ -z "$T" ] && return 0 + + while [ "$1" ]; do + + # extra user-configurable targets + if [ "$ECLASS_DEBUG_OUTPUT" == "on" ]; then + echo "debug: $1" + elif [ -n "$ECLASS_DEBUG_OUTPUT" ]; then + echo "debug: $1" >> $ECLASS_DEBUG_OUTPUT + fi + + # default target + echo "$1" >> "${T}/eclass-debug.log" + # let the portage user own/write to this file + chmod g+w "${T}/eclass-debug.log" &>/dev/null + + shift + done +} + +# The following 2 functions are debug-print() wrappers + +debug-print-function() { + str="$1: entering function" + shift + debug-print "$str, parameters: $*" +} + +debug-print-section() { + debug-print "now in section $*" +} + +# Sources all eclasses in parameters +declare -ix ECLASS_DEPTH=0 +inherit() { + ECLASS_DEPTH=$(($ECLASS_DEPTH + 1)) + if [[ $ECLASS_DEPTH > 1 ]]; then + debug-print "*** Multiple Inheritence (Level: ${ECLASS_DEPTH})" + fi + + local location + local PECLASS + + local B_IUSE + local B_DEPEND + local B_RDEPEND + local B_CDEPEND + local B_PDEPEND + while [ "$1" ]; do + location="${ECLASSDIR}/${1}.eclass" + + # PECLASS is used to restore the ECLASS var after recursion. + PECLASS="$ECLASS" + export ECLASS="$1" + + if [ "$EBUILD_PHASE" != "depend" ]; then + if ! hasq $ECLASS $INHERITED; then + echo + echo "QA Notice: ECLASS '$ECLASS' inherited illegally in $CATEGORY/$PF" >&2 + echo + fi + fi + + # any future resolution code goes here + if [ -n "$PORTDIR_OVERLAY" ]; then + local overlay + for overlay in ${PORTDIR_OVERLAY}; do + olocation="${overlay}/eclass/${1}.eclass" + if [ -e "$olocation" ]; then + location="${olocation}" + debug-print " eclass exists: ${location}" + fi + done + fi + debug-print "inherit: $1 -> $location" + + #We need to back up the value of DEPEND and RDEPEND to B_DEPEND and B_RDEPEND + #(if set).. and then restore them after the inherit call. + + #turn off glob expansion + set -f + + # Retain the old data and restore it later. + unset B_IUSE B_DEPEND B_RDEPEND B_CDEPEND B_PDEPEND + [ "${IUSE-unset}" != "unset" ] && B_IUSE="${IUSE}" + [ "${DEPEND-unset}" != "unset" ] && B_DEPEND="${DEPEND}" + [ "${RDEPEND-unset}" != "unset" ] && B_RDEPEND="${RDEPEND}" + [ "${CDEPEND-unset}" != "unset" ] && B_CDEPEND="${CDEPEND}" + [ "${PDEPEND-unset}" != "unset" ] && B_PDEPEND="${PDEPEND}" + unset IUSE DEPEND RDEPEND CDEPEND PDEPEND + #turn on glob expansion + set +f + + source "$location" || export ERRORMSG="died sourcing $location in inherit()" + [ -z "${ERRORMSG}" ] || die "${ERRORMSG}" + + #turn off glob expansion + set -f + + # If each var has a value, append it to the global variable E_* to + # be applied after everything is finished. New incremental behavior. + [ "${IUSE-unset}" != "unset" ] && export E_IUSE="${E_IUSE} ${IUSE}" + [ "${DEPEND-unset}" != "unset" ] && export E_DEPEND="${E_DEPEND} ${DEPEND}" + [ "${RDEPEND-unset}" != "unset" ] && export E_RDEPEND="${E_RDEPEND} ${RDEPEND}" + [ "${CDEPEND-unset}" != "unset" ] && export E_CDEPEND="${E_CDEPEND} ${CDEPEND}" + [ "${PDEPEND-unset}" != "unset" ] && export E_PDEPEND="${E_PDEPEND} ${PDEPEND}" + + [ "${B_IUSE-unset}" != "unset" ] && IUSE="${B_IUSE}" + [ "${B_IUSE-unset}" != "unset" ] || unset IUSE + + [ "${B_DEPEND-unset}" != "unset" ] && DEPEND="${B_DEPEND}" + [ "${B_DEPEND-unset}" != "unset" ] || unset DEPEND + + [ "${B_RDEPEND-unset}" != "unset" ] && RDEPEND="${B_RDEPEND}" + [ "${B_RDEPEND-unset}" != "unset" ] || unset RDEPEND + + [ "${B_CDEPEND-unset}" != "unset" ] && CDEPEND="${B_CDEPEND}" + [ "${B_CDEPEND-unset}" != "unset" ] || unset CDEPEND + + [ "${B_PDEPEND-unset}" != "unset" ] && PDEPEND="${B_PDEPEND}" + [ "${B_PDEPEND-unset}" != "unset" ] || unset PDEPEND + + #turn on glob expansion + set +f + + hasq $1 $INHERITED || export INHERITED="$INHERITED $1" + + export ECLASS="$PECLASS" + + shift + done + ECLASS_DEPTH=$(($ECLASS_DEPTH - 1)) +} + +# Exports stub functions that call the eclass's functions, thereby making them default. +# For example, if ECLASS="base" and you call "EXPORT_FUNCTIONS src_unpack", the following +# code will be eval'd: +# src_unpack() { base_src_unpack; } +EXPORT_FUNCTIONS() { + if [ -z "$ECLASS" ]; then + echo "EXPORT_FUNCTIONS without a defined ECLASS" >&2 + exit 1 + fi + while [ "$1" ]; do + debug-print "EXPORT_FUNCTIONS: ${1} -> ${ECLASS}_${1}" + eval "$1() { ${ECLASS}_$1 "\$@" ; }" > /dev/null + shift + done +} + +# adds all parameters to E_DEPEND and E_RDEPEND, which get added to DEPEND +# and RDEPEND after the ebuild has been processed. This is important to +# allow users to use DEPEND="foo" without frying dependencies added by an +# earlier inherit. It also allows RDEPEND to work properly, since a lot +# of ebuilds assume that an unset RDEPEND gets its value from DEPEND. +# Without eclasses, this is true. But with them, the eclass may set +# RDEPEND itself (or at least used to) which would prevent RDEPEND from +# getting its value from DEPEND. This is a side-effect that made eclasses +# have unreliable dependencies. + +newdepend() { + debug-print-function newdepend $* + debug-print "newdepend: E_DEPEND=$E_DEPEND E_RDEPEND=$E_RDEPEND" + + while [ -n "$1" ]; do + case $1 in + "/autotools") + do_newdepend DEPEND sys-devel/autoconf sys-devel/automake sys-devel/make + ;; + "/c") + do_newdepend DEPEND sys-devel/gcc virtual/libc + do_newdepend RDEPEND virtual/libc + ;; + *) + do_newdepend DEPEND $1 + ;; + esac + shift + done +} + +newrdepend() { + debug-print-function newrdepend $* + do_newdepend RDEPEND $1 +} + +newcdepend() { + debug-print-function newcdepend $* + do_newdepend CDEPEND $1 +} + +newpdepend() { + debug-print-function newpdepend $* + do_newdepend PDEPEND $1 +} + +do_newdepend() { + # This function does a generic change determining whether we're in an + # eclass or not. If we are, we change the E_* variables for deps. + debug-print-function do_newdepend $* + [ -z "$1" ] && die "do_newdepend without arguments" + + # Grab what we're affecting... Figure out if we're affecting eclasses. + [[ ${ECLASS_DEPTH} > 0 ]] && TARGET="E_$1" + [[ ${ECLASS_DEPTH} > 0 ]] || TARGET="$1" + shift # $1 was a variable name. + + while [ -n "$1" ]; do + # This bit of evil takes TARGET and uses it to evaluate down to a + # variable. This is a sneaky way to make this infinately expandable. + # The normal translation of this would look something like this: + # E_DEPEND="${E_DEPEND} $1" :::::: Cool, huh? :) + eval export ${TARGET}=\"\${${TARGET}} \$1\" + shift + done +} + +# this is a function for removing any directory matching a passed in pattern from +# PATH +remove_path_entry() { + save_IFS + IFS=":" + stripped_path="${PATH}" + while [ -n "$1" ]; do + cur_path="" + for p in ${stripped_path}; do + if [ "${p/${1}}" == "${p}" ]; then + cur_path="${cur_path}:${p}" + fi + done + stripped_path="${cur_path#:*}" + shift + done + restore_IFS + PATH="${stripped_path}" +} + +# === === === === === === === === === === === === === === === === === === +# === === === === === functions end, main part begins === === === === === +# === === === === === functions end, main part begins === === === === === +# === === === === === functions end, main part begins === === === === === +# === === === === === === === === === === === === === === === === === === + +if [ "$*" != "depend" ] && [ "$*" != "clean" ]; then + cd ${PORTAGE_TMPDIR} &> /dev/null + cd ${BUILD_PREFIX} &> /dev/null + + if [ "$(id -nu)" == "portage" ] ; then + export USER=portage + fi + + if hasq distcc ${FEATURES} &>/dev/null; then + if [ -d /usr/lib/distcc/bin ]; then + #We can enable distributed compile support + if [ -z "${PATH/*distcc*/}" ]; then + # Remove the other reference. + remove_path_entry "distcc" + fi + export PATH="/usr/lib/distcc/bin:${PATH}" + [ ! -z "${DISTCC_LOG}" ] && addwrite "$(dirname ${DISTCC_LOG})" + elif which distcc &>/dev/null; then + export CC="distcc $CC" + export CXX="distcc $CXX" + fi + fi + + if hasq ccache ${FEATURES} &>/dev/null; then + #We can enable compiler cache support + if [ -z "${PATH/*ccache*/}" ]; then + # Remove the other reference. + remove_path_entry "ccache" + fi + + if [ -d /usr/lib/ccache/bin ]; then + export PATH="/usr/lib/ccache/bin:${PATH}" + elif [ -d /usr/bin/ccache ]; then + export PATH="/usr/bin/ccache:${PATH}" + fi + + [ -z "${CCACHE_DIR}" ] && export CCACHE_DIR="/root/.ccache" + + addread "${CCACHE_DIR}" + addwrite "${CCACHE_DIR}" + + [ -n "${CCACHE_SIZE}" ] && ccache -M ${CCACHE_SIZE} &> /dev/null + fi + + # XXX: Load up the helper functions. +# for X in /usr/lib/portage/bin/functions/*.sh; do +# source ${X} || die "Failed to source ${X}" +# done + +else + +killparent() { + trap INT + kill ${PORTAGE_MASTER_PID} +} +trap "killparent" INT + +fi # "$*"!="depend" && "$*"!="clean" + +export SANDBOX_ON="1" +export S=${WORKDIR}/${P} + +unset E_IUSE E_DEPEND E_RDEPEND E_CDEPEND E_PDEPEND + +declare -r T P PN PV PVR PR A D EBUILD EMERGE_FROM O PPID FILESDIR +declare -r PORTAGE_TMPDIR + +# Turn of extended glob matching so that g++ doesn't get incorrectly matched. +shopt -u extglob + +QA_INTERCEPTORS="javac java-config python python-config perl grep egrep fgrep sed gcc g++ cc bash awk nawk gawk pkg-config" +# level the QA interceptors if we're in depend +if hasq "depend" "$@"; then + for BIN in ${QA_INTERCEPTORS}; do + BIN_PATH=`type -pf ${BIN}` + if [ "$?" != "0" ]; then + BODY="echo \"*** missing command: ${BIN}\" >&2; return 127" + else + BODY="${BIN_PATH} \"\$@\"; return \$?" + fi + FUNC_SRC="${BIN}() { + echo -n \"QA Notice: ${BIN} in global scope: \" >&2 + if [ \$ECLASS_DEPTH -gt 0 ]; then + echo \"eclass \${ECLASS}\" >&2 + else + echo \"\${CATEGORY}/\${PF}\" >&2 + fi + ${BODY} + }"; + eval "$FUNC_SRC" || echo "error creating QA interceptor ${BIN}" >&2 + done + unset src bin_path body +fi +source ${EBUILD} || die "error sourcing ebuild" +if ! hasq depend $EBUILD_PHASE; then + RESTRICT="${PORTAGE_RESTRICT}" + unset PORTAGE_RESTRICT +fi +[ -z "${ERRORMSG}" ] || die "${ERRORMSG}" + +# Expand KEYWORDS +# We need to turn off pathname expansion for -* in KEYWORDS and +# we need to escape ~ to avoid tilde expansion +set -f +KEYWORDS="`eval echo ${KEYWORDS//~/\\~}`" +set +f + +hasq nostrip ${RESTRICT} && export DEBUGBUILD=1 + +#a reasonable default for $S +if [ "$S" = "" ]; then + export S=${WORKDIR}/${P} +fi + +#wipe the interceptors. we don't want saved. +if hasq "depend" "$@"; then + unset -f $QA_INTERCEPTORS + unset QA_INTERCEPTORS +fi + +#some users have $TMP/$TMPDIR to a custom dir in their home ... +#this will cause sandbox errors with some ./configure +#scripts, so set it to $T. +export TMP="${T}" +export TMPDIR="${T}" + +# Note: this next line is not the same as export RDEPEND=${RDEPEND:-${DEPEND}} +# That will test for unset *or* NULL (""). We want just to set for unset... + +#turn off glob expansion from here on in to prevent *'s and ? in the DEPEND +#syntax from getting expanded :) Fixes bug #1473 +#check eclass rdepends also. bug #58819 +set -f +if [ "${RDEPEND-unset}" == "unset" ] && [ "${E_RDEPEND-unset}" == "unset" ] ; then + export RDEPEND="${DEPEND} ${E_DEPEND}" + debug-print "RDEPEND: not set... Setting to: ${DEPEND}" +fi + +#add in dependency info from eclasses +IUSE="$IUSE $E_IUSE" +DEPEND="$DEPEND $E_DEPEND" +RDEPEND="$RDEPEND $E_RDEPEND" +CDEPEND="$CDEPEND $E_CDEPEND" +PDEPEND="$PDEPEND $E_PDEPEND" + +unset E_IUSE E_DEPEND E_RDEPEND E_CDEPEND E_PDEPEND + +if [ "${EBUILD_PHASE}" != "depend" ]; then + # Lock the dbkey variables after the global phase + declare -r DEPEND RDEPEND SLOT SRC_URI RESTRICT HOMEPAGE LICENSE DESCRIPTION + declare -r KEYWORDS INHERITED IUSE CDEPEND PDEPEND PROVIDE +fi + +set +f + +for myarg in $*; do + case $myarg in + nofetch) + pkg_nofetch + exit 1 + ;; + prerm|postrm|postinst|config) + export SANDBOX_ON="0" + if [ "$PORTAGE_DEBUG" != "1" ]; then + pkg_${myarg} + #Allow non-zero return codes since they can be caused by && + else + set -x + pkg_${myarg} + #Allow non-zero return codes since they can be caused by && + set +x + fi + ;; + unpack|compile|test|clean|install) + if [ "${SANDBOX_DISABLED="0"}" == "0" ]; then + export SANDBOX_ON="1" + else + export SANDBOX_ON="0" + fi + if [ "$PORTAGE_DEBUG" != "1" ]; then + dyn_${myarg} + #Allow non-zero return codes since they can be caused by && + else + set -x + dyn_${myarg} + #Allow non-zero return codes since they can be caused by && + set +x + fi + export SANDBOX_ON="0" + ;; + help|clean|setup|preinst) + #pkg_setup needs to be out of the sandbox for tmp file creation; + #for example, awking and piping a file in /tmp requires a temp file to be created + #in /etc. If pkg_setup is in the sandbox, both our lilo and apache ebuilds break. + export SANDBOX_ON="0" + if [ "$PORTAGE_DEBUG" != "1" ]; then + dyn_${myarg} + else + set -x + dyn_${myarg} + set +x + fi + ;; + package|rpm) + export SANDBOX_ON="0" + if [ "$PORTAGE_DEBUG" != "1" ]; then + dyn_${myarg} + else + set -x + dyn_${myarg} + set +x + fi + ;; + depend) + export SANDBOX_ON="0" + set -f + + # Handled in portage.py now + #dbkey=${PORTAGE_CACHEDIR}/${CATEGORY}/${PF} + + if [ ! -d "${dbkey%/*}" ]; then + install -d -g ${PORTAGE_GID} -m2775 "${dbkey%/*}" + fi + + # Make it group writable. 666&~002==664 + umask 002 + + #the extra `echo` commands remove newlines + echo `echo "$DEPEND"` > $dbkey + echo `echo "$RDEPEND"` >> $dbkey + echo `echo "$SLOT"` >> $dbkey + echo `echo "$SRC_URI"` >> $dbkey + echo `echo "$RESTRICT"` >> $dbkey + echo `echo "$HOMEPAGE"` >> $dbkey + echo `echo "$LICENSE"` >> $dbkey + echo `echo "$DESCRIPTION"` >> $dbkey + echo `echo "$KEYWORDS"` >> $dbkey + echo `echo "$INHERITED"` >> $dbkey + echo `echo "$IUSE"` >> $dbkey + echo `echo "$CDEPEND"` >> $dbkey + echo `echo "$PDEPEND"` >> $dbkey + echo `echo "$PROVIDE"` >> $dbkey + echo `echo "$UNUSED_01"` >> $dbkey + echo `echo "$UNUSED_02"` >> $dbkey + echo `echo "$UNUSED_03"` >> $dbkey + echo `echo "$UNUSED_04"` >> $dbkey + echo `echo "$UNUSED_05"` >> $dbkey + echo `echo "$UNUSED_06"` >> $dbkey + echo `echo "$UNUSED_07"` >> $dbkey + echo `echo "$UNUSED_08"` >> $dbkey + set +f + #make sure it is writable by our group: + exit 0 + ;; + *) + export SANDBOX_ON="1" + echo "Please specify a valid command." + echo + dyn_help + exit 1 + ;; + esac + + #if [ $? -ne 0 ]; then + # exit 1 + #fi +done + +if [ "$myarg" != "clean" ]; then + # Save current environment and touch a success file. (echo for success) + umask 002 + set | egrep -v "^SANDBOX_" > "${T}/environment" 2>/dev/null + chown portage:portage "${T}/environment" &>/dev/null + chmod g+w "${T}/environment" &>/dev/null +fi + +exit 0 diff --git a/bin/emake b/bin/emake new file mode 100755 index 000000000..44fe83402 --- /dev/null +++ b/bin/emake @@ -0,0 +1,14 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/emake,v 1.9.2.1 2005/05/18 15:19:52 jstubbs Exp $ +# +# emake: Supplies some default parameters to GNU make. At the moment the +# only parameter supplied is -jN, where N is a number of +# parallel processes that should be ideal for the running host +# (e.g. on a single-CPU machine, N=2). The MAKEOPTS variable +# is set in /etc/make.globals. We don't source +# /etc/make.globals here because emake is only called from an +# ebuild. + +${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@" diff --git a/bin/emerge b/bin/emerge new file mode 100755 index 000000000..5ae171963 --- /dev/null +++ b/bin/emerge @@ -0,0 +1,3213 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/emerge,v 1.345.2.38 2005/08/13 17:25:26 ferringb Exp $ + +import os,sys +os.environ["PORTAGE_CALLER"]="emerge" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage + +import emergehelp,xpak,string,re,commands,time,shutil,traceback,atexit,signal,socket,types +from stat import * +from output import * + +import portage_util +import portage_locks +import portage_exception + + +spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")", + "Thank you for using Gentoo. :)", + "Are you actually trying to read this?", + "How many times have you stared at this?", + "We are generating the cache right now", + "You are paying too much attention.", + "A theory is better than its explanation.", + "Phasers locked on target, Captain.", + "Thrashing is just virtual crashing.", + "To be is to program.", + "Real Users hate Real Programmers.", + "When all else fails, read the instructions.", + "Functionality breeds Contempt.", + "The future lies ahead.", + "3.1415926535897932384626433832795028841971694", + "Sometimes insanity is the only alternative.", + "Inaccuracy saves a world of explanation.", + ] + + +def update_basic_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % 500 + if (spinpos % 100) == 0: + if spinpos == 0: + sys.stdout.write(". ") + else: + sys.stdout.write(".") + sys.stdout.flush() + +def update_scroll_spinner(): + global spinner, spinpos + if(spinpos >= len(spinner)): + sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))])) + else: + sys.stdout.write(green("\b "+spinner[spinpos])) + sys.stdout.flush() + spinpos = (spinpos+1) % (2*len(spinner)) + +def update_twirl_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % len(spinner) + sys.stdout.write("\b\b "+spinner[spinpos]) + sys.stdout.flush() + +spinpos = 0 +spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" +update_spinner = update_twirl_spinner +if "candy" in portage.settings.features: + spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)] + update_spinner = update_scroll_spinner +if not sys.stdout.isatty() or ("--nospinner" in sys.argv): + update_spinner = update_basic_spinner + + +if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]): + nocolor() + +def normpath(mystr): + if mystr and (mystr[0]=='/'): + return os.path.normpath("///"+mystr) + else: + return os.path.normpath(mystr) + +def userquery(prompt, responses=None, colours=None): + """Displays a prompt and a set of responses, then waits for a response + which is checked against the responses and the first to match is + returned. + + prompt: a String. + responses: a List of Strings. + colours: a List of Functions taking and returning a String, used to + process the responses for display. Typically these will be functions + like red() but could be e.g. lambda x: "DisplayString". + If responses is omitted, defaults to ["Yes", "No"], [green, red]. + If only colours is omitted, defaults to [bold, ...]. + + Returns a member of the List responses. (If called without optional + arguments, returns "Yes" or "No".) + KeyboardInterrupt is converted to SystemExit to avoid tracebacks being + printed.""" + if responses is None: + responses, colours = ["Yes", "No"], [green, red] + elif colours is None: + colours=[bold] + colours=(colours*len(responses))[:len(responses)] + print bold(prompt), + try: + while True: + response=raw_input("["+string.join([colours[i](responses[i]) for i in range(len(responses))],"/")+"] ") + for key in responses: + if response.upper()==key[:len(response)].upper(): + return key + print "Sorry, response '%s' not understood." % response, + except (EOFError, KeyboardInterrupt): + print "Interrupted." + sys.exit(1) + +def sorted_versions(verlist): + ret = [] + for ver in verlist: + verparts = ver.split("-") + if len(verparts) == 2: + verrev = int(verparts[1][1:]) + else: + verrev = 0 + x = 0 + while x < len(ret): + retparts = ret[x].split("-") + verdiff = portage.vercmp(retparts[0], verparts[0]) + if verdiff > 0: + break + elif verdiff == 0: + if len(retparts) == 2: + retrev = int(retparts[1][1:]) + else: + retrev = 0 + if retrev >= verrev: + break + x += 1 + ret.insert(x, ver) + return ret + +if portage.settings.has_key("PORTAGE_NICENESS"): + try: + os.nice(int(portage.settings["PORTAGE_NICENESS"])) + except SystemExit, e: + raise # Needed else can't exit + except Exception,e: + print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'" + print "!!!",e + +#Freeze the portdbapi for enhanced performance: +portage.portdb.freeze() + +# Kill noauto as it will break merges otherwise. +while 'noauto' in portage.features: + del portage.features[portage.features.index('noauto')] + +#number of ebuilds merged +merged=0 +params=["selective", "deep", "self", "recurse", "empty"] +actions=[ +"clean", "config", "depclean", +"info", "inject", "metadata", +"prune", "regen", "rsync", "search", +"sync", "system", "unmerge", "world", +] +options=[ +"--ask", +"--buildpkg", "--buildpkgonly", +"--changelog", "--columns", +"--debug", "--deep", +"--digest", +"--emptytree", +"--fetchonly", "--fetch-all-uri", +"--getbinpkg", "--getbinpkgonly", +"--help", "--noconfmem", +"--newuse", "--nocolor", +"--nodeps", "--noreplace", +"--nospinner", "--oneshot", +"--onlydeps", "--pretend", +"--quiet", "--resume", +"--searchdesc", "--selective", +"--skipfirst", +"--tree", +"--update", "--upgradeonly", +"--usepkg", "--usepkgonly", +"--verbose", "--version" +] + +shortmapping={ +"1":"--oneshot", +"a":"--ask", +"b":"--buildpkg", "B":"--buildpkgonly", +"c":"--clean", "C":"--unmerge", +"d":"--debug", "D":"--deep", +"e":"--emptytree", +"f":"--fetchonly", "F":"--fetch-all-uri", +"g":"--getbinpkg", "G":"--getbinpkgonly", +"h":"--help", +"i":"--inject", +"k":"--usepkg", "K":"--usepkgonly", +"l":"--changelog", +"n":"--noreplace", "N":"--newuse", +"o":"--onlydeps", "O":"--nodeps", +"p":"--pretend", "P":"--prune", +"q":"--quiet", +"s":"--search", "S":"--searchdesc", +'t':"--tree", +"u":"--update", "U":"--upgradeonly", +"v":"--verbose", "V":"--version" +} + +myaction=None +myopts=[] +myfiles=[] +edebug=0 + +# process short actions +tmpcmdline=sys.argv[1:] +#tmpcmdline.extend(portage.settings["EMERGE_OPTS"].split()) +cmdline=[] +for x in tmpcmdline: + if x[0:1]=="-"and x[1:2]!="-": + for y in x[1:]: + if shortmapping.has_key(y): + if shortmapping[y] in cmdline: + print + print "*** Warning: Redundant use of",shortmapping[y] + else: + cmdline.append(shortmapping[y]) + else: + print "!!! Error: -"+y+" is an invalid short action or option." + sys.exit(1) + else: + cmdline.append(x) + +# process the options and command arguments +for x in cmdline: + if not x: + continue + if len(x)>=2 and x[0:2]=="--": + if x in options: + myopts.append(x) + elif x[2:] in actions: + if x[2:]=="rsync" or x=="rsync": + # "emerge --rsync" + print + print red("*** '--rsync' has been deprecated.") + print red("*** Please use '--sync' instead.") + print + x="--sync" + if myaction: + if myaction not in ["system", "world"]: + myaction="--"+myaction + print + print red("!!!")+green(" Multiple actions requested... Please choose one only.") + print red("!!!")+" '"+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" + print + sys.exit(1) + myaction=x[2:] + else: + print "!!! Error:",x,"is an invalid option." + sys.exit(1) + elif (not myaction) and (x in actions): + if x not in ["system", "world"]: + #print red("*** Deprecated use of action '"+x+"'") + if x=="rsync": + # "emerge rsync" + print + print red("*** 'rsync' will now install the package rsync.") + print red("*** To sync the tree, please use '--sync' instead.") + print + myfiles.append(x) + continue + if myaction: + print + print red("!!!")+green(" Multiple actions requested... Please choose one only.") + print red("!!! '")+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" + print + sys.exit(1) + myaction=x + elif x[-1]=="/": + # this little conditional helps tab completion + myfiles.append(x[:-1]) + else: + myfiles.append(x) + + +if "moo" in myfiles: + print """ + + Gentoo (""" + os.uname()[0] + """) + + _______________________ +< Have you mooed today? > + ----------------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + +""" + +if (myaction in ["world", "system"]) and myfiles: + print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both." + sys.exit(1) + +for x in myfiles: + if (x[-7:] == ".ebuild" or x[-5:] == ".tbz2") and os.path.exists(os.path.abspath(x)): + print "emerging by path implies --oneshot... adding --oneshot to options." + print red("\n*** emerging by path is broken and may not always work!!!\n") + break + +if ("--tree" in myopts) and ("--columns" in myopts): + print "emerge: can't specify both of \"--tree\" and \"--columns\"." + sys.exit(1) + +# Always create packages if FEATURES=buildpkg +# Imply --buildpkg if --buildpkgonly +if ("buildpkg" in portage.features) or ("--buildpkgonly" in myopts): + if "--buildpkg" not in myopts: + myopts.append("--buildpkg") + +# --tree only makes sense with --pretend +if "--tree" in myopts and not (("--pretend" in myopts) or ("--ask" in myopts)): + print ">>> --tree implies --pretend... adding --pretend to options." + myopts.append("--pretend") + +# Also allow -S to invoke search action (-sS) +if ("--searchdesc" in myopts): + if myaction and myaction != "search": + myfiles.append(myaction) + if "--search" not in myopts: + myopts.append("--search") + myaction = "search" + +# Always try and fetch binary packages if FEATURES=getbinpkg +if ("getbinpkg" in portage.features): + myopts.append("--getbinpkg") + +if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): + myopts.append("--usepkgonly") + +if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): + myopts.append("--getbinpkg") + +if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): + myopts.append("--usepkg") + +# Also allow -K to apply --usepkg/-k +if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): + myopts.append("--usepkg") + +# Print deprecation warning for -U +if ("--upgradeonly" in myopts): + print + print red("*** Warning: --upgradeonly is a deprecated option in portage-"+portage.VERSION) + print red("*** and will likely be removed in a future version.") + print + # Also allow -U to apply --update/-u + if not ("--update" in myopts): + print ">>> --upgradeonly implies --update... adding --update to options." + myopts.append("--update") + +# Also allow -l to apply --pretend/-p, but if already in --ask mode +if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)): + print ">>> --changelog implies --pretend... adding --pretend to options." + myopts.append("--pretend") + +# Allow -p to remove --ask +if ("--pretend" in myopts) and ("--ask" in myopts): + print ">>> --pretend disables --ask... removing --ask from options." + myopts.remove("--ask") + +# forbid --ask when not in a terminal +# note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. +if ("--ask" in myopts) and (not sys.stdin.isatty()): + portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n") + sys.exit(1) + +# Set so that configs will be merged regardless of remembered status +if ("--noconfmem" in myopts): + portage.settings.unlock() + portage.settings["NOCONFMEM"]="1" + portage.settings.backup_changes("NOCONFMEM") + portage.settings.lock() + +# Set various debug markers... They should be merged somehow. +if ("--debug" in myopts): + portage.settings.unlock() + portage.settings["PORTAGE_DEBUG"]="1" + portage.settings.backup_changes("PORTAGE_DEBUG") + portage.debug=1 + portage.settings.lock() + +if ("--resume" in myopts): + if "--verbose" in myopts: + print "* --verbose is currently broken with --resume. Disabling..." + myopts.remove("--verbose") + if "--tree" in myopts: + print "* --tree is currently broken with --resume. Disabling..." + myopts.remove("--tree") + +# Set color output +if ("--nocolor" in myopts) and (sys.stdout.isatty()): + nocolor() + +CLEAN_DELAY = 5 +EMERGE_WARNING_DELAY = 10 +if portage.settings["CLEAN_DELAY"]: + CLEAN_DELAY = string.atoi("0"+portage.settings["CLEAN_DELAY"]) +if portage.settings["EMERGE_WARNING_DELAY"]: + EMERGE_WARNING_DELAY = string.atoi("0"+portage.settings["EMERGE_WARNING_DELAY"]) + +if "inject" == myaction: + print + print red("*** --inject has been deprecated.") + print red("*** If you manage a piece of software yourself, add it's name and") + print red("*** version (eg foo/bar-1.0) to /etc/portage/profile/package.provided.") + print red("*** If you want to prevent portage from upgrading a package, add it to") + print red("*** /etc/portage/package.mask prepending it with '>' (eg >foo/bar-1.0)") + print red("*** For more information on fine-grained portage control, please see") + print red("*** the portage man page.") + print + +def emergelog(mystr,short_msg=None): + if "notitles" not in portage.features: + if short_msg: + xtermTitle(short_msg) + else: + xtermTitle(mystr) + try: + #seems odd opening a file each write... + if not os.path.exists("/var/log/emerge.log"): + mylogfile=open("/var/log/emerge.log", "w") + os.chmod("/var/log/emerge.log", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) + os.chown("/var/log/emerge.log", portage.portage_uid, portage.portage_gid) + else: + mylogfile=open("/var/log/emerge.log", "a") + + l=portage_locks.lockfile(mylogfile) + # seek because we may have gotten held up by the lock. + # if so, we may not be positioned at the end of the file. + mylogfile.seek(0,2) + mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") + mylogfile.flush() + portage_locks.unlockfile(l) + mylogfile.close() + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if edebug: + print "emergelog():",e + pass + +def emergeexit(): + """This gets out final log message in before we quit.""" + if "--pretend" not in myopts: + emergelog(" *** terminating.") + if "notitles" not in portage.features: + xtermTitleReset() +atexit.register(emergeexit) + +def emergeexitsig(signum, frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + portage.portageexit() + portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) + sys.exit(100+signum) +signal.signal(signal.SIGINT, emergeexitsig) + +def countdown(secs=5, doing="Starting"): + if secs: + print ">>> Waiting",secs,"seconds before starting..." + print ">>> (Control-C to abort)...\n"+doing+" in: ", + ticks=range(secs) + ticks.reverse() + for sec in ticks: + sys.stdout.write(red(str(sec+1)+" ")) + sys.stdout.flush() + time.sleep(1) + print + +# formats a size given in bytes nicely +def format_size(mysize): + if type(mysize) not in [types.IntType,types.LongType]: + return str(mysize) + mystr=str(mysize/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + return mystr+" kB" + + +def getgccversion(): + """ + rtype: C{str} + return: the current in-use gcc version + """ + + gcc_env_dir = os.path.join('/', 'etc', 'env.d', 'gcc') + gcc_config_config = os.path.join(gcc_env_dir, 'config') + gcc_ver_command = 'gcc -dumpversion' + gcc_ver_prefix = 'gcc-' + + gcc_not_found_error = red( + "!!! No gcc found. You probably need to 'source /etc/profile'\n" + + "!!! to update the environment of this terminal and possibly\n" + + "!!! other terminals also." + ) + + gcc_distcc_broken_error = green( + '!!! Relying on the shell to locate gcc, this may break\n' + + '!!! DISTCC, installing gcc-config and setting your current gcc\n' + + '!!! profile will fix this' + ) + + def fallback(): + + print >>sys.stderr, gcc_distcc_broken_error + + gccout = commands.getstatusoutput(gcc_ver_command) + + if gccout[0] != 0: + print >>sys.stderr, gcc_not_found_error + gccver = "[unavailable]" + else: + gccver = gcc_ver_prefix + gccout[1] + + return gccver + + if os.path.isfile(gcc_config_config): + try: + gccver_str = open(gcc_config_config).read().strip() + gccver = gcc_ver_prefix + string.join(gccver_str.split('-')[4:], '-') + except IndexError: + gccver = fallback() + + else: + import glob + dir_l = glob.glob(os.path.join(gcc_env_dir, '*-*')) + + if len(dir_l) == 1: + try: + gccver = gcc_ver_prefix + dir_l[0].split('-')[-1] + except IndexError: + gccver = fallback() + + else: + # There was no "config" file in /etc/env.d/gcc and there was more + # than one profile in /etc/env.d/gcc so we can't actively + # determine what version of gcc we are using so we fall back on the + # old way that breaks distcc + + gccver = fallback() + + return gccver + +def getportageversion(): + try: + import re + profilever = os.path.normpath("///"+os.readlink("/etc/make.profile")) + basepath = os.path.normpath("///"+portage.settings["PORTDIR"]+"/profiles") + if re.match(basepath,profilever): + profilever = profilever[len(basepath)+1:] + else: + profilever = "!"+profilever + del basepath + except SystemExit, e: + raise # Needed else can't exit + except: + profilever="unavailable" + libcver=[] + libclist = portage.vardbapi(portage.root).match("virtual/libc") + libclist += portage.vardbapi(portage.root).match("virtual/glibc") + libclist = portage_util.unique_array(libclist) + for x in libclist: + xs=portage.catpkgsplit(x) + if libcver: + libcver+=","+string.join(xs[1:], "-") + else: + libcver=string.join(xs[1:], "-") + if libcver==[]: + libcver="unavailable" + + gccver = getgccversion() + unameout=os.uname()[2]+" "+os.uname()[4] + + return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")" + +def help(): + # Move all the help stuff out of this file. + emergehelp.help(myaction,myopts,havecolor) + +# check if root user is the current user for the actions where emerge needs this +if ("--pretend" in myopts) or ("--fetchonly" in myopts or "--fetch-all-uri" in myopts) or (myaction=="search"): + if not portage.secpass: + if portage.wheelgid==portage.portage_gid: + print "emerge: wheel group membership required for \"--pretend\" and search." + print "emerge: wheel group use is being deprecated. Please update group and passwd to" + print " include the portage user as noted above, and then use group portage." + else: + print "emerge: portage group membership required for \"--pretend\" and search." + sys.exit(1) +elif "--version" in myopts: + print getportageversion() + sys.exit(0) +elif "--help" in myopts: + help() + sys.exit(0) +elif portage.secpass!=2: + if myaction in ["search", "info", "regen"]: + pass + elif (not myaction) and (not myfiles): + pass + elif ("--pretend" in myopts) and (myaction in ["world","system","clean","prune","unmerge"]): + pass + else: + if "--debug" in myopts: + print "myaction",myaction + print "myopts",myopts + print "emerge: root access required." + sys.exit(1) + +if not "--pretend" in myopts: + emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) + myelogstr="" + if myopts: + myelogstr=string.join(myopts, " ") + if myaction: + myelogstr+=" "+myaction + if myfiles: + myelogstr+=" "+string.join(myfiles, " ") + emergelog(" *** emerge "+myelogstr) + +#configure emerge engine parameters +# +# self: include _this_ package regardless of if it is merged. +# selective: exclude the package if it is merged +# recurse: go into the dependencies +# empty: pretend nothing is merged +myparams=["self","recurse"] +add=[] +sub=[] +if "--update" in myopts: + add.extend(["selective","empty"]) +if "--emptytree" in myopts: + add.extend(["empty"]) + sub.extend(["selective"]) +if "--nodeps" in myopts: + sub.extend(["recurse"]) +if "--noreplace" in myopts: + add.extend(["selective"]) +if "--deep" in myopts: + add.extend(["deep"]) +if "--selective" in myopts: + add.extend(["selective"]) +if myaction in ["world","system"]: + add.extend(["selective"]) +elif myaction in ["depclean"]: + add.extend(["empty"]) + sub.extend(["selective"]) +for x in add: + if (x not in myparams) and (x not in sub): + myparams.append(x) +for x in sub: + if x in myparams: + myparams.remove(x) + +# search functionality +class search: + + # + # class constants + # + VERSION_SHORT=1 + VERSION_RELEASE=2 + + # + # public interface + # + def __init__(self): + """Searches the available and installed packages for the supplied search key. + The list of available and installed packages is created at object instantiation. + This makes successive searches faster.""" + self.installcache = portage.db["/"]["vartree"] + + def execute(self,searchkey): + """Performs the search for the supplied search key""" + global myopts + match_category = 0 + self.searchkey=searchkey + self.packagematches = [] + if "--searchdesc" in myopts: + self.searchdesc=1 + self.matches = {"pkg":[], "desc":[]} + else: + self.searchdesc=0 + self.matches = {"pkg":[]} + print "Searching... ", + + if self.searchkey[0] == '@': + match_category = 1 + self.searchkey = self.searchkey[1:] + if self.searchkey=="*": + #hack for people who aren't regular expression gurus + self.searchkey==".*" + if re.search("\+\+", self.searchkey): + #hack for people who aren't regular expression gurus + self.searchkey=re.sub("\+\+","\+\+",self.searchkey) + self.searchre=re.compile(self.searchkey.lower(),re.I) + for package in portage.portdb.cp_all(): + update_spinner() + + if match_category: + match_string = package[:] + else: + match_string = package.split("/")[-1] + + masked=0 + if self.searchre.search(match_string): + if not portage.portdb.xmatch("match-visible",package): + masked=1 + self.matches["pkg"].append([package,masked]) + elif self.searchdesc: # DESCRIPTION searching + full_package = portage.portdb.xmatch("bestmatch-visible",package) + if not full_package: + #no match found; we don't want to query description + full_package=portage.best(portage.portdb.xmatch("match-all",package)) + if not full_package: + continue + else: + masked=1 + try: + full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0] + except KeyError: + print "emerge: search: aux_get() failed, skipping" + continue + if self.searchre.search(full_desc): + self.matches["desc"].append([full_package,masked]) + self.mlen=0 + for mtype in self.matches.keys(): + self.matches[mtype].sort() + self.mlen += len(self.matches[mtype]) + + def output(self): + """Outputs the results of the search.""" + print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]" + print "[ Applications found : "+white(str(self.mlen))+" ]" + print " " + for mtype in self.matches.keys(): + for match,masked in self.matches[mtype]: + if mtype=="pkg": + catpack=match + full_package = portage.portdb.xmatch("bestmatch-visible",match) + if not full_package: + #no match found; we don't want to query description + masked=1 + full_package=portage.best(portage.portdb.xmatch("match-all",match)) + else: + full_package = match + match = portage.pkgsplit(match)[0] + + if full_package: + try: + desc, homepage, license = portage.portdb.aux_get(full_package,["DESCRIPTION","HOMEPAGE","LICENSE"]) + except KeyError: + print "emerge: search: aux_get() failed, skipping" + continue + if masked: + print green("*")+" "+white(match)+" "+red("[ Masked ]") + else: + print green("*")+" "+white(match) + myversion = self.getVersion(full_package, search.VERSION_RELEASE) + + mysum = [0,0] + mycat = match.split("/")[0] + mypkg = match.split("/")[1] + + mydigest = portage.db["/"]["porttree"].dbapi.finddigest(mycat+"/"+mypkg + "-" + myversion) + + try: + myfile = open(mydigest,"r") + for line in myfile.readlines(): + mysum[0] += int(line.split(" ")[3]) + myfile.close() + mystr = str(mysum[0]/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + mysum[0]=mystr+" kB" + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if edebug: + print "!!! Exception:",e + mysum[0]=" [no/bad digest]" + + if "--quiet" not in myopts: + print " ", darkgreen("Latest version available:"),myversion + print " ", self.getInstallationStatus(mycat+'/'+mypkg) + print " ", darkgreen("Size of downloaded files:"),mysum[0] + print " ", darkgreen("Homepage:")+" ",homepage + print " ", darkgreen("Description:"),desc + print " ", darkgreen("License:")+" ",license + print + print + # + # private interface + # + def getInstallationStatus(self,package): + installed_package = self.installcache.dep_bestmatch(package) + result = "" + version = self.getVersion(installed_package,search.VERSION_RELEASE) + if len(version) > 0: + result = darkgreen("Latest version installed:")+" "+version + else: + result = darkgreen("Latest version installed:")+" [ Not Installed ]" + return result + + def getVersion(self,full_package,detail): + if len(full_package) > 1: + package_parts = portage.catpkgsplit(full_package) + if detail == search.VERSION_RELEASE and package_parts[3] != 'r0': + result = package_parts[2]+ "-" + package_parts[3] + else: + result = package_parts[2] + else: + result = "" + return result + + +#build our package digraph +def getlist(mode): + if mode=="system": + mylines=portage.settings.packages + elif mode=="world": + try: + myfile=open(portage.root+portage.WORLD_FILE,"r") + mylines=myfile.readlines() + myfile.close() + except OSError: + print "!!! Couldn't open "+pfile+"; exiting." + sys.exit(1) + except IOError: + #world file doesn't exist + mylines=[] + mynewlines=[] + for x in mylines: + myline=string.join(string.split(x)) + if not len(myline): + continue + elif myline[0]=="#": + continue + elif mode=="system": + if myline[0]!="*": + continue + myline=myline[1:] + mynewlines.append(myline.strip()) + return mynewlines + +def genericdict(mylist): + mynewdict={} + for x in mylist: + mynewdict[portage.dep_getkey(x)]=x + return mynewdict + +olddbapi=None +class depgraph: + + def __init__(self,myaction,myopts): + global olddbapi + self.pkgsettings = portage.config(clone=portage.settings) + if not self.pkgsettings["ARCH"]: + portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n")) + portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n")) + sys.exit(9) + self.applied_useflags = {} + + self.missingbins=[] + self.myaction=myaction + self.digraph=portage.digraph() + self.orderedkeys=[] + self.outdatedpackages=[] + self.mydbapi={} + self.mydbapi["/"] = portage.fakedbapi() + if "empty" not in myparams: + for pkg in portage.db["/"]["vartree"].getallcpv(): + self.mydbapi["/"].cpv_inject(pkg) + if portage.root != "/": + self.mydbapi[portage.root] = portage.fakedbapi() + if "empty" not in myparams: + for pkg in portage.db[portage.root]["vartree"].getallcpv(): + self.mydbapi[portage.root].cpv_inject(pkg) + + if "--usepkg" in myopts: + portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts)) + + def create(self,mybigkey,myparent=None,addme=1,myuse=None): + """creates the actual digraph of packages to merge. return 1 on success, 0 on failure + mybigkey = specification of package to merge; myparent = parent package (one depending on me); + addme = should I be added to the tree? (for the --onlydeps mode)""" + #stuff to add: + #SLOT-aware emerge + #IUSE-aware emerge + #"no downgrade" emerge + #print "mybigkey:",mybigkey + + jbigkey=string.join(mybigkey) + if self.digraph.hasnode(jbigkey+" merge") or self.digraph.hasnode(jbigkey+" nomerge"): + #this conditional is needed to prevent infinite recursion on already-processed deps + return 1 + + update_spinner() + + mytype,myroot,mykey=mybigkey + # select the correct /var database that we'll be checking against + vardbapi=portage.db[myroot]["vartree"].dbapi + + if addme: + # if the package is already on the system, we add a "nomerge" + # directive, otherwise we add a "merge" directive. + if mytype=="blocks": + # we've encountered a "blocks" node. We will totally ignore this + # node and not add it to our digraph if it doesn't apply to us. + if "--buildpkgonly" not in myopts and myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)): + mybigkey.append(myparent.split()[2]) + self.digraph.addnode(string.join(mybigkey),myparent) + return 1 + + if myuse == None: + self.pkgsettings.setcpv(mykey) + myuse=string.split(self.pkgsettings["USE"], " ") + + self.applied_useflags[mykey] = myuse + + merging=1 + if addme: + # this is where we add the node to the list of packages to merge + if not myparent: + # command-line specified or part of a world list... + if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)): + # the package is on the system, so don't merge it. + merging=0 + elif ("selective" in myparams) and vardbapi.cpv_exists(mykey): + merging=0 + + if (merging==0 and mytype=="ebuild" and "--newuse" in myopts and vardbapi.cpv_exists(mykey)): + iuses=string.split(portage.portdb.aux_get(mykey, ["IUSE"])[0]) + old_use=string.split(vardbapi.aux_get(mykey, ["USE"])[0]) + now_use=string.split(self.pkgsettings["USE"]) + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + merging=1 + break + else: + #onlydeps mode; don't merge + merging=2 + if merging==1: + mybigkey.append("merge") + else: + mybigkey.append("nomerge") + + # whatever the case, we need to add the node to our digraph so + # that children can depend upon it. + self.digraph.addnode(string.join(mybigkey),myparent) + if ("deep" not in myparams) and (not merging): + return 1 + elif "recurse" not in myparams: + return 1 + + edepend={} + if mytype=="binary": + mypkgparts=portage.catpkgsplit(mykey) + tbz2name = string.split(mykey, "/")[1]+".tbz2" + if tbz2name in portage.db[portage.root]["bintree"].invalids: + sys.stderr.write("\nINVALID PACKAGE (is required to continue): "+str(mykey)+"\n") + sys.exit(1) + if portage.db[portage.root]["bintree"].isremote(mykey): + edepend = portage.db[portage.root]["bintree"].remotepkgs[tbz2name] + edepend["DEPEND"] ="" + edepend["RDEPEND"]=string.join(string.split(edepend["RDEPEND"])," ") + edepend["PDEPEND"]=string.join(string.split(edepend["PDEPEND"])," ") + edepend["CDEPEND"]=string.join(string.split(edepend["CDEPEND"])," ") + edepend["SLOT"] =string.strip(edepend["SLOT"]) + #portage.db[portage.root]["bintree"].gettbz2(mykey) + else: # It's local. + mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey)) + edepend["DEPEND"] ="" + edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ") + edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ") + edepend["CDEPEND"]=string.join(mytbz2.getelements("CDEPEND")," ") + edepend["SLOT"] =mytbz2.getfile("SLOT",mypkgparts[2]) + elif mytype=="ebuild": + try: + mymeta = ["DEPEND","RDEPEND","PDEPEND","CDEPEND"] + myfoo = portage.portdb.aux_get(mykey, mymeta) + for index in range(0,len(mymeta)): + edepend[mymeta[index]] = myfoo[index] + except (KeyError,IOError): + print "emerge: create(): aux_get() error on",mykey+"; aborting..." + sys.exit(1) + mydep={} + mp=string.join(mybigkey) + + if myroot=="/": + mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"] + if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): + return 0 + else: + mydep["/"]=edepend["DEPEND"] + mydep[myroot]=edepend["RDEPEND"] + if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): + return 0 + if not self.select_dep(myroot,mydep[myroot],myparent=mp,myuse=myuse): + return 0 + + if edepend.has_key("PDEPEND") and edepend["PDEPEND"]: + # Post Depend -- Add to the list without a parent, as it depends + # on a package being present AND must be built after that package. + if not self.select_dep(myroot,edepend["PDEPEND"],myuse=myuse): + return 0 + + return 1 + + def select_files(self,myfiles): + "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list" + myfavorites=[] + for x in myfiles: + if x[-5:]==".tbz2": + if not os.path.exists(x): + if os.path.exists(self.pkgsettings["PKGDIR"]+"/All/"+x): + x=self.pkgsettings["PKGDIR"]+"/All/"+x + elif os.path.exists(self.pkgsettings["PKGDIR"]+"/"+x): + x=self.pkgsettings["PKGDIR"]+"/"+x + else: + print "\n\n!!! Binary package '"+str(x)+"' does not exist." + print "!!! Please ensure the tbz2 exists as specified.\n" + sys.exit(1) + mytbz2=xpak.tbz2(x) + mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(x)[:-5] + if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x): + print red("\n*** You need to adjust PKGDIR to emerge this package.\n") + sys.exit(1) + if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts): + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + elif x[-7:]==".ebuild": + x = os.path.realpath(x) + mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.basename(x)[:-7] + ebuild_path = portage.db["/"]["porttree"].dbapi.findname(mykey) + if ebuild_path: + if os.path.realpath(ebuild_path) != x: + print red("\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") + sys.exit(1) + if mykey not in portage.db["/"]["porttree"].dbapi.xmatch("match-visible", portage.dep_getkey(mykey)): + print red("\n*** You are emerging a masked package. It is MUCH better to use") + print red("*** /etc/portage/package.* to accomplish this. See portage(5) man") + print red("*** page for details.") + countdown(EMERGE_WARNING_DELAY, "Continuing...") + else: + print red("\n*** "+x+" does not exist") + sys.exit(1) + if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts): + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + else: + try: + mykey=portage.dep_expand(x,mydb=portage.portdb) + except ValueError, errpkgs: + print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" + print "!!! one of the following fully-qualified ebuild names instead:\n" + for i in errpkgs[0]: + print " " + green(i) + print + sys.exit(1) + + # select needs to return 0 on dep_check failure + + sys.stdout.flush() + sys.stderr.flush() + + try: + self.mysd = self.select_dep(portage.root,mykey,arg=x) + except portage_exception.MissingSignature, e: + portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n") + portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") + portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") + portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e)) + sys.exit(1) + except portage_exception.InvalidSignature, e: + portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n") + portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") + portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") + portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e)) + sys.exit(1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if "--debug" in myopts: + raise + print "\n\n!!! Problem in",mykey,"dependencies." + print "!!!",str(e),e.__module__ + sys.exit(1) + + if not self.mysd: + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + + missing=0 + if "--usepkgonly" in myopts: + for x in self.digraph.dict.keys(): + xs=string.split(x," ") + if (xs[0] != "binary") and (xs[3]=="merge"): + if missing == 0: + print + missing += 1 + print "Missing binary for:",xs[2] + + # We're true here unless we are missing binaries. + return (not missing,myfavorites) + + def is_newer_ver_installed(self,myroot,pkg,pkgver): + "if there is a version of pkg installed newer than pkgver, return it" + vardbapi=portage.db[myroot]["vartree"].dbapi + + matches=portage.db[myroot]["vartree"].dbapi.match(pkg) + if matches: + myslot=portage.db["/"]["porttree"].getslot(pkgver) + for match in matches: + if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(match)[1:]) < 0: + curslot=portage.db[myroot]["vartree"].getslot(match) + if curslot == myslot: + return match + + def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None): + "given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure" + if "--debug" in myopts: + print + print "Parent: ",myparent + print "Depstring:",depstring + if not arg: + #processing dependencies + mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkg" in myopts)) + #mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse) + + if not mycheck[0]: + mymerge=[] + else: + mymerge=mycheck[1] + + else: + #we're processing a command-line argument; unconditionally merge it even if it's already merged + mymerge=[depstring] + + # dep_check has been run so we can now add our parent to our + # build state to update virtuals and other settings. This + # happens after the package is added to the tree so that a + # package can depend on a virtual which it satisfies. + if myparent: + myp = myparent.split() + if myp[3]=="merge": + self.mydbapi[myroot].cpv_inject(myp[2]) + if myp[0]=="binary": + self.pkgsettings.setinst(myp[2],portage.db["/"]["bintree"].dbapi) + else: + self.pkgsettings.setinst(myp[2],portage.db[myroot]["porttree"].dbapi) + + if not mymerge: + return 1 + + if "--debug" in myopts: + print "Candidates:",mymerge + for x in mymerge: + myk=None + binpkguseflags=None + if x[0]=="!": + # if this package is myself, don't append it to block list. + if "--debug" in myopts: + print "Myparent",myparent + if (myparent): + if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]): + # myself, so exit. + continue + # adding block + myk=["blocks",myroot,x[1:]] + else: + #We are not processing a blocker but a normal dependency + myeb=None + myeb_matches = portage.portdb.xmatch("match-visible",x) + if ("--usepkgonly" not in myopts): + myeb=portage.best(myeb_matches) + + myeb_pkg=None + if ("--usepkg" in myopts): + # The next line assumes the binarytree has been populated. + # XXX: Need to work out how we use the binary tree with roots. + myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x) + if ("--usepkgonly" not in myopts): + # Remove any binary package entries that are masked in the portage tree (#55871) + for idx in range(len(myeb_pkg_matches)-1,-1,-1): + if myeb_pkg_matches[idx] not in myeb_matches: + del myeb_pkg_matches[idx] + myeb_pkg = portage.best(myeb_pkg_matches) + + if not myeb_pkg: + myeb_pkg = None + elif ("--newuse" in myopts): + iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["IUSE"])[0]) + old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["USE"])[0]) + self.pkgsettings.setcpv(myeb_pkg) + now_use=string.split(self.pkgsettings["USE"]) + self.pkgsettings.reset() + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + myeb_pkg = None + break + + if (not myeb) and (not myeb_pkg): + if not arg: + xinfo='"'+x+'"' + else: + xinfo='"'+arg+'"' + if myparent: + xfrom = '(dependency required by '+green('"'+myparent.split()[2]+'"')+red(' ['+myparent.split()[0]+"])") + alleb=portage.portdb.xmatch("match-all",x) + if alleb: + if "--usepkgonly" not in myopts: + print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") + print "!!! One of the following masked packages is required to complete your request:" + oldcomment = "" + for p in alleb: + mreasons = portage.getmaskingstatus(p) + print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")" + comment = portage.getmaskingreason(p) + if comment and comment != oldcomment: + print comment + oldcomment = comment + print + print "For more information, see MASKED PACKAGES section in the emerge man page or " + print "section 2.2 \"Software Availability\" in the Gentoo Handbook." + if myparent: + print "!!! "+red(xfrom) + print + else: + print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo) + print "!!! Either add a suitable binary package or compile from an ebuild." + else: + print "\nemerge: there are no ebuilds to satisfy "+xinfo+"." + print + return 0 + + if "--debug" in myopts: + print "ebuild:",myeb + print "binpkg:",myeb_pkg + + if myeb and myeb_pkg: + myeb_s = portage.catpkgsplit(myeb) + myeb_s = [myeb_s[0]+"/"+myeb_s[1], myeb_s[2], myeb_s[3]] + myeb_pkg_s = portage.catpkgsplit(myeb_pkg) + myeb_pkg_s = [myeb_pkg_s[0]+"/"+myeb_pkg_s[1], myeb_pkg_s[2], myeb_pkg_s[3]] + + if portage.pkgcmp(myeb_s, myeb_pkg_s) == 0: # pkg is same version as ebuild + myeb = None + else: + myeb_pkg = None + + if "--upgradeonly" in myopts: + # Check that there isn't a newer version of this package already installed + cand = None + try: + # XXX: This can throw an exception if the ebuild doesn't exist + if myeb: + cand=self.is_newer_ver_installed(myroot,x,myeb) + elif myeb_pkg: + cand=self.is_newer_ver_installed(myroot,x,myeb_pkg) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Warning: "+str(e) + if cand: + myeb=cand + + if myeb: + myk=["ebuild",myroot,myeb] + elif myeb_pkg: + binpkguseflags=portage.db[portage.root]["bintree"].get_use(myeb_pkg) + myk=["binary",myroot,myeb_pkg] + else: + sys.stderr.write("!!! Confused... Don't know what I'm using for dependency info. :(\n") + sys.exit(1) + + #if "--usepkg" in myopts: + # #If we want to use packages, see if we have a pre-built one... + # mypk=portage.db["/"]["bintree"].dbapi.match(x) + # if myeb in mypk: + # #Use it only if it's exactly the version we want. + # myk=["binary",myroot,myeb] + # else: + # myk=["ebuild",myroot,myeb] + #else: + # myk=["ebuild",myroot,myeb] + if myparent: + #we are a dependency, so we want to be unconditionally added + if not self.create(myk,myparent,myuse=binpkguseflags): + return 0 + else: + #if mysource is not set, then we are a command-line dependency and should not be added + #if --onlydeps is specified. + if not self.create(myk,myparent,"--onlydeps" not in myopts,myuse=binpkguseflags): + return 0 + + if "--debug" in myopts: + print "Exiting...",myparent + return 1 + + + def altlist(self): + mygraph=self.digraph.copy() + dolist=["/"] + retlist=[] + for x in portage.db.keys(): + portage.db[x]["merge"]=[] + if x not in dolist: + dolist.append(x) + while (not mygraph.empty()): + mycurkey=mygraph.firstzero() + if not mycurkey: + print "!!! Error: circular dependencies:" + print + for x in mygraph.dict.keys(): + for y in mygraph.dict[x][1]: + print y,"depends on",x + print + sys.exit(1) + splitski=string.split(mycurkey) + #I'm not sure of the significance of the following lines (vestigal?) so I'm commenting 'em out. + #These lines remove already-merged things from our alt-list + #if "--update" in myopts: + # if not portage.db["/"]["vartree"].exists_specific(splitski[2]): + # portage.db["/"]["merge"].append(splitski) + #else: + portage.db[splitski[1]]["merge"].append(splitski) + mygraph.delnode(mycurkey) + for x in dolist: + for y in portage.db[x]["merge"]: + retlist.append(y) + return retlist + + def xcreate(self,mode="system"): + global syslist + if mode=="system": + mylist=syslist + else: + #world mode + worldlist=getlist("world") + sysdict=genericdict(syslist) + worlddict=genericdict(worldlist) + #we're effectively upgrading sysdict to contain all new deps from worlddict + for x in worlddict.keys(): + #only add the world node if the package is: + #actually installed -- this prevents the remerging of already unmerged packages when we do a world --update; + #actually available -- this prevents emerge from bombing out due to no match being found (we want a silent ignore) + if "empty" in myparams: + if portage.db["/"]["vartree"].dbapi.match(x): + sysdict[x]=worlddict[x] + elif portage.db[portage.root]["vartree"].dbapi.match(x): + #package is installed + sysdict[x]=worlddict[x] + else: + print "\n*** Package in world file is not installed: "+x + mylist = sysdict.keys() + + for mydep in mylist: + myeb=portage.portdb.xmatch("bestmatch-visible",mydep) + if not myeb: + #this is an unavailable world entry; just continue + continue + + if "--upgradeonly" in myopts: + cand=self.is_newer_ver_installed(portage.root,mydep,myeb) + if cand: + myeb=cand + + #THIS NEXT BUNCH OF CODE NEEDS TO BE REPLACED TO SUPPORT WORLD ANTI-DEPS + #if mydep2[0]=="!":, etc. + binpkguseflags = None + if "--usepkg" in myopts: + mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) + if myeb==mypk: + myk=["binary",portage.root,mypk] + binpkguseflags=portage.db[portage.root]["bintree"].get_use(mypk) + if ("--newuse" in myopts): + iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(mypk, ["IUSE"])[0]) + old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(mypk, ["USE"])[0]) + self.pkgsettings.setcpv(mypk) + now_use=string.split(self.pkgsettings["USE"]) + self.pkgsettings.reset() + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + myk=["ebuild",portage.root,myeb] + binpkguseflags=None + break + elif "--usepkgonly" in myopts: + if not mypk: + self.missingbins += [myeb] + myk=["binary",portage.root,myeb] + else: + myk=["binary",portage.root,mypk] + else: + myk=["ebuild",portage.root,myeb] + else: + myk=["ebuild",portage.root,myeb] + + if not self.create(myk,myuse=binpkguseflags): + print + print "!!! Problem with",myk[0],myk[2] + print "!!! Possibly a DEPEND/*DEPEND problem." + print + return 0 + return 1 + + def match(self,mydep,myroot=portage.root,mykey=None): + # support mutual exclusive deps + mydep2=mydep + if mydep2[0]=="!": + mydep2=mydep[1:] + + if mydep[0]=="!": + #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example) + myk="blocks "+myroot+" "+mydep2 + else: + myeb=portage.db[portage.root]["porttree"].dep_bestmatch(mydep2) + if not myeb: + if not mykey: + print "\n!!! Error: couldn't find match for",mydep + else: + print "\n!!! Error: couldn't find match for",mydep,"in",mykey + print + sys.exit(1) + + if "--usepkg" in myopts: + mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) + if myeb==mypk: + myk="binary "+portage.root+" "+mypk + else: + myk="ebuild "+myroot+" "+myeb + else: + myk="ebuild "+myroot+" "+myeb + + return myk + + def display(self,mylist): + changelogs=[] + p=[] + totalsize=0 + + if "--verbose" in myopts: + overlays = string.split(portage.settings['PORTDIR_OVERLAY']) + + if "--tree" in myopts: + mylist.reverse() + mygraph=self.digraph.copy() + + i = 0 + while i < len(mylist): + if mylist[i][-1]=="nomerge": + if not ("--tree" in myopts): + # we don't care about this elements + mylist.pop(i) + continue + if (i == (len(mylist) - 1)) \ + or (mygraph.depth(string.join(mylist[i])) \ + >= mygraph.depth(string.join(mylist[i+1]))): + # end of a useless branch (may be the last one) + # -> delete the element and test the previous one + mylist.pop(i) + if i > 0: + i -= 1 + continue + # the branch continues, or we've found a good element. + # -> let's see what's next, if anything + i += 1 + + display_overlays=False + # files to fetch list - avoids counting a same file twice + # in size display (verbose mode) + myfetchlist=[] + for x in mylist: + fetch=" " + + if x[0]=="blocks": + addl=""+red("B")+" "+fetch+" " + resolved=portage.db[x[1]]["vartree"].resolve_key(x[2]) + print "["+x[0]+" "+addl+"]",red(resolved), + if resolved!=x[2]: + if x[3]: + print red("(\""+x[2]+"\" is blocking "+x[3]+")") + else: + print red("(\""+x[2]+"\")") + else: + if x[3]: + print red("(is blocking "+x[3]+")") + else: + print + else: + if (x[0]!="binary") and ("fetch" in string.split(portage.portdb.aux_get(x[2],["RESTRICT"])[0])): + fetch = red("F") + if portage.portdb.fetch_check(x[2], portage.settings): + fetch = green("f") + + #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty" + #param is used for -u, where you still *do* want to see when something is being upgraded. + myoldbest="" + if (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]): + addl=" "+yellow("R")+fetch+" " + elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]): + if x[0] == "binary": + mynewslot=portage.db["/"]["bintree"].getslot(x[2]) + elif x[0] == "ebuild": + mynewslot=portage.db["/"]["porttree"].getslot(x[2]) + myoldlist=portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0]) + myinslotlist=filter((lambda p: portage.db[portage.root]["vartree"].getslot(p)==mynewslot),myoldlist) + if myinslotlist: + myoldbest=portage.best(myinslotlist) + addl=" "+fetch + if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: + # Downgrade in slot + addl+=turquoise("U")+blue("D") + else: + # Update in slot + addl+=turquoise("U")+" " + else: + # New slot, mark it new. + addl=" "+green("NS")+fetch+" " + + if "--changelog" in myopts: + changelogs.extend(self.calc_changelog( + portage.portdb.findname(x[2]), + portage.db["/"]["vartree"].dep_bestmatch('/'.join(portage.catpkgsplit(x[2])[:2])), + x[2] + )) + else: + addl=" "+green("N")+" "+fetch+" " + + verboseadd="" + if "--verbose" in myopts: + # iuse verbose + try: + if x[0] == "binary": + iuse_split = string.split(portage.db["/"]["bintree"].dbapi.aux_get(x[2],["IUSE"])[0]) + elif x[0] == "ebuild": + iuse_split = string.split(portage.portdb.aux_get(x[2],["IUSE"])[0]) + else: + iuse_split = [] + except SystemExit, e: + raise # Needed else can't exit + except: + portage.writemsg("!!! Error getting IUSE (report this to bugs.gentoo.org)\n") + portage.writemsg("!!! %s\n" % x) + iuse_split = [] + iuse_split.sort() + old_use=None + if myoldbest: + pkg=myoldbest + else: + pkg=x[2] + if portage.db["/"]["vartree"].dbapi.cpv_exists(pkg): + try: + old_use=string.split(portage.db["/"]["vartree"].dbapi.aux_get(pkg, ["USE"])[0]) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + iuse="" + now_use=self.applied_useflags[x[2]] + for ebuild_iuse in portage_util.unique_array(iuse_split): + usechange="" + if old_use: + if (old_use.count(ebuild_iuse) and not now_use.count(ebuild_iuse)) or (not old_use.count(ebuild_iuse) and now_use.count(ebuild_iuse)): + usechange="*" + + if ebuild_iuse in self.applied_useflags[x[2]]: + if usechange == "*": + iuse=green("+"+ebuild_iuse) + else: + iuse=red("+"+ebuild_iuse) + elif ebuild_iuse in portage.settings.usemask: + iuse=blue("(-"+ebuild_iuse+")") + else: + iuse=blue("-"+ebuild_iuse) + verboseadd+=iuse+usechange+" " + + # size verbose + mysize=0 + if x[0] == "ebuild" and x[-1]!="nomerge": + myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug) + if myfilesdict==None: + myfilesdict="[empty/missing/bad digest]" + else: + for myfetchfile in myfilesdict.keys(): + if myfetchfile not in myfetchlist: + mysize+=myfilesdict[myfetchfile] + myfetchlist.append(myfetchfile) + totalsize+=mysize + verboseadd+=format_size(mysize)+" " + + # overlay verbose + # XXX: Invalid binaries have caused tracebacks here. 'if file_name' + # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge'] + file_name=portage.portdb.findname(x[2]) + if file_name: # It might not exist in the tree + dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..") + if (overlays.count(dir_name)>0): + verboseadd+=teal("["+str(overlays.index(os.path.normpath(dir_name))+1)+"]")+" " + display_overlays=True + else: + verboseadd += "[No ebuild?]" + + xs=portage.pkgsplit(x[2]) + if xs[2]=="r0": + xs[2]="" + else: + xs[2]="-"+xs[2] + + if self.pkgsettings.has_key("COLUMNWIDTH"): + mywidth=int(self.pkgsettings.settings["COLUMNWIDTH"]) + else: + mywidth=130 + oldlp=mywidth-30 + newlp=oldlp-30 + + indent="" + if ("--tree" in myopts): + indent=" "*mygraph.depth(string.join(x)) + + if myoldbest: + myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] + if myoldbest[-3:]=="-r0": + myoldbest=myoldbest[:-3] + myoldbest=blue("["+myoldbest+"]") + + if x[1]!="/": + if "--columns" in myopts: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) + if (newlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(newlp-nc_len(myprint))) + myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " + if (oldlp-nc_len(myprint)) > 0: + myprint=myprint+" "*(oldlp-nc_len(myprint)) + myprint=myprint+myoldbest + myprint=myprint+darkgreen(" to "+x[1])+" "+verboseadd + else: + myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd + else: + if "--columns" in myopts: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) + if (newlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(newlp-nc_len(myprint))) + myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") + if (oldlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(oldlp-nc_len(myprint))) + myprint=myprint+myoldbest+" "+verboseadd + else: + if x[3]=="nomerge": + myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd + else: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd + p.append(myprint) + + if ("--tree" not in myopts): + mysplit=portage.pkgsplit(x[2]) + + # XXX mysplit _can_ be None.... Why? + if mysplit and (len(mysplit)==3): + if "--emptytree" not in myopts: + if mysplit[0]=="sys-apps/portage": + if ((mysplit[1]+mysplit[2]) != portage.VERSION) and \ + ("livecvsportage" not in portage.settings.features): + if mylist.index(x)<len(mylist)-1: + p.append(red("*** Portage will stop merging at this point and reload itself,")) + p.append(red(" recalculate dependencies, and complete the merge.")) + if "--update" not in myopts: + p.append(darkgreen(" You may avoid the remerging of packages by updating portage on its own.")) + print + else: + if mysplit[0]=="sys-apps/portage" and ("--emptytree" in myopts): + if mysplit[1]+mysplit[2]!=portage.VERSION: + p.append(red("***")+" Please update portage to the above version before proceeding.") + p.append(" Failure to do so may result in failed or improper merges.") + p.append(" A simple '"+green("emerge -u portage")+"' is sufficient.") + p.append("") + del mysplit + + for x in p: + print x + + if "--verbose" in myopts: + print + print "Total size of downloads: "+format_size(totalsize) + if overlays and display_overlays: + print "Portage overlays:" + y=0 + for x in overlays: + y=y+1 + print " "+teal("["+str(y)+"]"),x + + if "--changelog" in myopts: + print + for revision,text in changelogs: + print bold('*'+revision) + sys.stdout.write(text) + + def calc_changelog(self,ebuildpath,current,next): + current = '-'.join(portage.catpkgsplit(current)[1:]) + if current.endswith('-r0'): current = current[:-3] + next = '-'.join(portage.catpkgsplit(next)[1:]) + if next.endswith('-r0'): next = next[:-3] + changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') + try: + changelog = open(changelogpath).read() + except SystemExit, e: + raise # Needed else can't exit + except: + return [] + divisions = self.find_changelog_tags(changelog) + #print 'XX from',current,'to',next + #for div,text in divisions: print 'XX',div + # skip entries for all revisions above the one we are about to emerge + for i in range(len(divisions)): + if divisions[i][0]==next: + divisions = divisions[i:] + break + # find out how many entries we are going to display + for i in range(len(divisions)): + if divisions[i][0]==current: + divisions = divisions[:i] + break + else: + # couldnt find the current revision in the list. display nothing + return [] + return divisions + + def find_changelog_tags(self,changelog): + divs = [] + release = None + while 1: + match = re.search(r'^\*\ ?([-a-zA-Z0-9_.]*)(?:\ .*)?\n',changelog,re.M) + if match is None: + if release is not None: + divs.append((release,changelog)) + return divs + if release is not None: + divs.append((release,changelog[:match.start()])) + changelog = changelog[match.end():] + release = match.group(1) + if release.endswith('.ebuild'): + release = release[:-7] + if release.endswith('-r0'): + release = release[:-3] + + def outdated(self): + return self.outdatedpackages + + def merge(self,mylist): + returnme=0 + mymergelist=[] + + #check for blocking dependencies + if ("--fetchonly" not in myopts) and ("--buildpkgonly" not in myopts): + for x in mylist: + if x[0]=="blocks": + print "\n!!! Error: the "+x[2]+" package conflicts with another package." + print "!!! both can't be installed on the same system together." + print "!!! Please use 'emerge --pretend' to determine blockers." + print + if ("--pretend" not in myopts): + sys.exit(1) + + #buildsyspkg: I need mysysdict also on resume (moved from the else block) + mysysdict=genericdict(syslist) + if ("--resume" in myopts): + # We're resuming. + print green("*** Resuming merge...") + emergelog(" *** Resuming merge...") + mymergelist=portage.mtimedb["resume"]["mergelist"][:] + if ("--skipfirst" in myopts) and mymergelist: + del portage.mtimedb["resume"]["mergelist"][0] + del mymergelist[0] + else: + myfavs=portage.grabfile(portage.root+portage.WORLD_FILE) + myfavdict=genericdict(myfavs) + for x in range(len(mylist)): + if mylist[x][3]!="nomerge": + # Add to the mergelist + mymergelist.append(mylist[x]) + else: + myfavkey=portage.cpv_getkey(mylist[x][2]) + if "--onlydeps" in myopts: + continue + # Add to the world file. Since we won't be able to later. + if (not "--fetchonly" in myopts) and (myfavkey in favorites): + #don't record if already in system profile or already recorded + if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): + #we don't have a favorites entry for this package yet; add one + myfavdict[myfavkey]=myfavkey + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + if not "--fetchonly" in myopts: + portage.writedict(myfavdict,portage.root+portage.WORLD_FILE,writekey=0) + + portage.mtimedb["resume"]["mergelist"]=mymergelist[:] + + # We need to yank the harmful-to-new-builds settings from features. + myorigfeat=self.pkgsettings["FEATURES"] + myfeat=myorigfeat.split() + while ("keeptemp" in myfeat): + del myfeat[myfeat.index("keeptemp")] + while ("keepwork" in myfeat): + del myfeat[myfeat.index("keepwork")] + + self.pkgsettings["FEATURES"]=string.join(myfeat) + + mergecount=0 + for x in mymergelist: + mergecount+=1 + myroot=x[1] + pkgindex=2 + if x[0]=="blocks": + pkgindex=3 + y=portage.portdb.findname(x[pkgindex]) + if not "--pretend" in myopts: + print ">>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+")",x[pkgindex],"to",x[1] + emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1]) + + self.pkgsettings["EMERGE_FROM"] = x[0][:] + self.pkgsettings.backup_changes("EMERGE_FROM") + + #buildsyspkg: Check if we need to _force_ binary package creation + issyspkg = ("buildsyspkg" in myfeat) \ + and x[0] != "blocks" \ + and mysysdict.has_key(portage.cpv_getkey(x[2])) \ + and not ("--buildpkg" in myopts) + if x[0] in ["ebuild","blocks"]: + if (x[0]=="blocks") and ("--fetchonly" not in myopts): + raise Exception, "Merging a blocker" + elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): + if ("--fetch-all-uri" in myopts): + retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1) + else: + retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1) + if (retval == None) or retval: + print + print "!!! Fetch for",y,"failed, continuing..." + print + returnme=1 + continue + elif "--buildpkg" in myopts or issyspkg: + #buildsyspkg: Sounds useful to display something, but I don't know if we should also log it + if issyspkg: + print ">>> This is a system package, let's pack a rescue tarball." + #emergelog(">>> This is a system package, let's pack a rescue tarball.") + #create pkg, then merge pkg + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + #dynamically update our database + if "--buildpkgonly" not in myopts: + portage.db[portage.root]["bintree"].inject(x[2]) + mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + + self.pkgsettings["EMERGE_FROM"] = "binary" + self.pkgsettings.backup_changes("EMERGE_FROM") + + retval=portage.pkgmerge(mytbz2,myroot,self.pkgsettings) + if retval==None: + sys.exit(1) + else: + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + #dynamically update our database + elif x[0]=="binary": + #merge the tbz2 + mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) + if portage.db[portage.root]["bintree"].isremote(x[2]): + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch" + emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) + portage.db[portage.root]["bintree"].gettbz2(x[2]) + + if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): + continue + + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) + retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings) + if retval==None: + sys.exit(1) + #need to check for errors + if "--buildpkgonly" not in myopts: + portage.db[x[1]]["vartree"].inject(x[2]) + myfavkey=portage.cpv_getkey(x[2]) + if "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts and myfavkey in favorites: + myfavs=portage.grabfile(myroot+portage.WORLD_FILE) + myfavdict=genericdict(myfavs) + mysysdict=genericdict(syslist) + #don't record if already in system profile or already recorded + if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): + #we don't have a favorites entry for this package yet; add one + myfavdict[myfavkey]=myfavkey + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")") + portage.writedict(myfavdict,myroot+portage.WORLD_FILE,writekey=0) + + if ("noclean" not in portage.features) and (x[0] != "binary"): + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean Post" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + + if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + # Clean the old package that we have merged over top of it. + if self.pkgsettings["AUTOCLEAN"]=="yes": + xsplit=portage.pkgsplit(x[2]) + emergelog(" >>> AUTOCLEAN: "+xsplit[0]) + retval=unmerge("clean", [xsplit[0]]) + if not retval: + emergelog(" --- AUTOCLEAN: Nothing unmerged.") + + # Figure out if we need a restart. + mysplit=portage.pkgsplit(x[2]) + if mysplit[0]=="sys-apps/portage": + myver=mysplit[1]+"-"+mysplit[2] + if myver[-3:]=='-r0': + myver=myver[:-3] + if (myver != portage.VERSION) and \ + ("livecvsportage" not in portage.settings.features): + if len(mymergelist) > mergecount: + myargv=sys.argv + myr=0 + for myra in range(len(myargv)): + if myargv[myr][0:len("portage")]=="portage": + del myargv[myr] + myr-=1 + if myargv[myr][0:len("sys-apps/portage")]=="sys-apps/portage": + del myargv[myr] + myr-=1 + myr+=1 + emergelog(" *** RESTARTING emerge via exec() after change of portage version.") + portage.portageexit() + # Remove --ask from options before restarting + mynewargv=[] + badlongopts = ["--ask","--tree","--changelog"] + badshortopts = ["a","t","l"] + for arg in myargv: + if arg[0:2] == "--": + if arg in badlongopts: + continue + mynewargv += [arg] + elif arg[0] == "-": + myarg = "-" + for ch in arg[1:]: + if ch in badshortopts: + continue + myarg += ch + mynewargv += [myarg] + else: + mynewargv += [arg] + os.execv("/usr/lib/portage/bin/emerge", mynewargv) + + if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1]) + + # Unsafe for parallel merges + del portage.mtimedb["resume"]["mergelist"][0] + + emergelog(" *** Finished. Cleaning up...") + + # We're out of the loop... We're done. Delete the resume data. + if portage.mtimedb.has_key("resume"): + del portage.mtimedb["resume"] + + if ("--pretend" not in myopts): + if ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + if (mergecount>0): + if retval: + portage.env_update() + + #by doing an exit this way, --fetchonly can continue to try to + #fetch everything even if a particular download fails. + if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + if returnme: + print "\n\n!!! Some fetch errors were encountered. Please see above for details.\n\n" + sys.exit(returnme) + else: + sys.exit(0) + +def unmerge(unmerge_action, unmerge_files): + candidate_catpkgs=[] + global_unmerge=0 + + realsyslist = getlist("system") + syslist = [] + for x in realsyslist: + mycp = portage.dep_getkey(x) + if mycp in portage.settings.virtuals: + syslist.extend(portage.settings.virtuals[mycp]) + syslist.append(mycp) + + global myopts + mysettings = portage.config(clone=portage.settings) + + if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files: + if "unmerge"==unmerge_action: + print + print bold("emerge unmerge")+" can only be used with specific package names, not with "+bold("world")+" or" + print bold("system")+" targets." + print + return 0 + else: + global_unmerge=1 + + localtree=portage.db[portage.root]["vartree"] + # process all arguments and add all valid db entries to candidate_catpkgs + if global_unmerge: + if not unmerge_files or "world" in unmerge_files: + candidate_catpkgs.extend(localtree.getallnodes()) + elif "system" in unmerge_files: + candidate_catpkgs.extend(getlist("system")) + else: + #we've got command-line arguments + if not unmerge_files: + print "\nNo packages to unmerge have been provided.\n" + return 0 + for x in unmerge_files: + arg_parts=x.split('/') + if (x[0] not in [".","/"]) and (arg_parts[-1][-7:] != ".ebuild"): + #possible cat/pkg or dep; treat as such + candidate_catpkgs.append(x) + elif unmerge_action in ["prune","clean"]: + print "\n!!! Prune and clean do not accept individual ebuilds as arguments;\n skipping.\n" + continue + else: + # it appears that the user is specifying an installed ebuild and we're in "unmerge" mode, so it's + # ok. + if not os.path.exists(x): + print "\n!!! The path '"+x+"' doesn't exist.\n" + return 0 + + absx = os.path.abspath(x) + sp_absx = absx.split("/") + if sp_absx[-1][-7:] == ".ebuild": + del sp_absx[-1] + absx = string.join(sp_absx,"/") + + sp_absx_len = len(sp_absx) + + vdb_path = portage.root+portage.VDB_PATH + vdb_len = len(vdb_path) + + sp_vdb = vdb_path.split("/") + sp_vdb_len = len(sp_vdb) + + if not os.path.exists(absx+"/CONTENTS"): + print "!!! Not a valid db dir: "+str(absx) + return 0 + + if sp_absx_len <= sp_vdb_len: + # The Path is shorter... so it can't be inside the vdb. + print spabsx + print absx + print "\n!!!",x,"cannot be inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" + return 0 + + for idx in range(0,sp_vdb_len): + if (idx >= sp_absx_len) or (sp_vdb[idx] != sp_absx[idx]): + print sp_absx + print absx + print "\n!!!",x,"is not inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" + return 0 + + print "="+string.join(sp_absx[sp_vdb_len:],"/") + candidate_catpkgs.append("="+string.join(sp_absx[sp_vdb_len:],"/")) + + if ("--pretend" in myopts) or ("--ask" in myopts): + print darkgreen("\n>>> These are the packages that I would unmerge:") + + pkgmap={} + numselected=0 + for x in candidate_catpkgs: + #cycle through all our candidate deps and determine what will and will not get unmerged + try: + mymatch=localtree.dep_match(x) + except KeyError: + mymatch=None + except ValueError, errpkgs: + print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" + print "!!! one of the following fully-qualified ebuild names instead:\n" + for i in errpkgs[0]: + print " " + green(i) + print + sys.exit(1) + + if not mymatch and x[0] not in "<>=~": + #add a "=" if missing + mymatch=localtree.dep_match("="+x) + if not mymatch: + print "\n--- Couldn't find " + white(x) + " to "+unmerge_action+"." + continue + mykey=portage.key_expand(portage.dep_getkey(mymatch[0]),portage.db["/"]["vartree"].dbapi) + if not pkgmap.has_key(mykey): + pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } + if unmerge_action=="unmerge": + for y in mymatch: + if y not in pkgmap[mykey]["selected"]: + pkgmap[mykey]["selected"].append(y) + numselected=numselected+len(mymatch) + + else: + #unmerge_action in ["prune", clean"] + slotmap={} + for mypkg in mymatch: + if unmerge_action=="clean": + myslot=localtree.getslot(mypkg) + else: + #since we're pruning, we don't care about slots and put all the pkgs in together + myslot=0 + if not slotmap.has_key(myslot): + slotmap[myslot]={} + slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg + for myslot in slotmap.keys(): + counterkeys=slotmap[myslot].keys() + counterkeys.sort() + if not counterkeys: + continue + counterkeys.sort() + pkgmap[mykey]["protected"].append(slotmap[myslot][counterkeys[-1]]) + del counterkeys[-1] + #be pretty and get them in order of merge: + for ckey in counterkeys: + pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) + numselected=numselected+1 + #ok, now the last-merged package is protected, and the rest are selected + if global_unmerge and not numselected: + print "\n>>> No outdated packages were found on your system.\n" + return 0 + + if not numselected: + print "\n>>>",unmerge_action+": No packages selected for removal.\n" + return 0 + + for x in pkgmap.keys(): + for y in localtree.dep_match(x): + if y not in pkgmap[x]["omitted"] and \ + y not in pkgmap[x]["selected"] and \ + y not in pkgmap[x]["protected"]: + pkgmap[x]["omitted"].append(y) + if global_unmerge and not pkgmap[x]["selected"]: + #avoid cluttering the preview printout with stuff that isn't getting unmerged + continue + if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist): + print red("\a\n\n!!! '%s' is part of your system profile. '%s'" % (mykey)) + print yellow("\a!!! Unmerging it may be damaging to your system.\n") + if "--pretend" not in myopts and "--ask" not in myopts: + global EMERGE_WARNING_DELAY + countdown(EMERGE_WARNING_DELAY,red("Press Ctrl-C to Stop")) + print "\n "+white(x) + for mytype in ["selected","protected","omitted"]: + print string.rjust(mytype,12)+":", + if pkgmap[x][mytype]: + for mypkg in pkgmap[x][mytype]: + mysplit=portage.catpkgsplit(mypkg) + if mysplit[3]=="r0": + myversion=mysplit[2] + else: + myversion=mysplit[2]+"-"+mysplit[3] + if mytype=="selected": + print red(myversion), + else: + print green(myversion), + else: + print "none", + print + + print "\n>>>",red("'Selected'"),"packages are slated for removal." + print ">>>",green("'Protected'"),"and",green("'omitted'"),"packages will not be removed.\n" + + if "--pretend" in myopts: + #we're done... return + return 0 + if "--ask" in myopts: + if userquery("Do you want me to unmerge these packages?")=="No": + # enter pretend mode for correct formatting of results + myopts+=["--pretend"] + print + print "Quitting." + print + return 0 + #the real unmerging begins, after a short delay.... + + global CLEAN_DELAY + countdown(CLEAN_DELAY, ">>> Unmerging") + + for x in pkgmap.keys(): + for y in pkgmap[x]["selected"]: + print ">>> Unmerging "+y+"..." + emergelog("=== Unmerging... ("+y+")") + mysplit=string.split(y,"/") + #unmerge... + retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,mysettings,unmerge_action not in ["clean","prune"]) + if retval: + emergelog(" !!! unmerge FAILURE: "+y) + else: + emergelog(" >>> unmerge success: "+y) + #run ldconfig, etc... + portage.env_update() + if not numselected: + return 0 + else: + return 1 + + +def chk_updated_info_files(retval): + root=portage.root + + infodirs=[] + infodirs.extend(string.split(portage.settings["INFOPATH"], ":")) + infodirs.extend(string.split(portage.settings["INFODIR"], ":")) + + print + if os.path.exists("/usr/bin/install-info"): + regen_infodirs=[] + for z in infodirs: + if z=='': + continue + inforoot=normpath(root+z) + if os.path.isdir(inforoot): + try: + infomtime=os.stat(inforoot)[ST_MTIME] + except SystemExit, e: + raise # Needed else can't exit + except: + infomtime=0 + + if not portage.mtimedb.has_key("info"): + portage.mtimedb["info"]={} + if portage.mtimedb["info"].has_key(inforoot): + if portage.mtimedb["info"][inforoot]==infomtime: + pass + else: + portage.mtimedb["info"][inforoot]=infomtime + regen_infodirs.append(inforoot) + else: + regen_infodirs.append(inforoot) + + if not regen_infodirs: + print " "+green("*")+" GNU info directory index is up-to-date." + else: + print " "+green("*")+" Regenerating GNU info directory index..." + + icount=0 + badcount=0 + for inforoot in regen_infodirs: + if inforoot=='': + continue + try: + os.rename(inforoot+"/dir",inforoot+"/dir.old") + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + if not os.path.isdir(inforoot): + continue + errmsg = "" + for x in os.listdir(inforoot): + if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)): + continue + myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] + existsstr="already exists, for file `" + if myso!="": + if re.search(existsstr,myso): + # Already exists... Don't increment the count for this. + pass + elif myso[:44]=="install-info: warning: no info dir entry in ": + # This info file doesn't contain a DIR-header: install-info produces this + # (harmless) warning (the --quiet switch doesn't seem to work). + # Don't increment the count for this. + pass + else: + badcount=badcount+1 + errmsg += myso + "\n" + icount=icount+1 + + #update mtime so we can potentially avoid regenerating. + portage.mtimedb["info"][inforoot]=os.stat(inforoot)[ST_MTIME] + + if badcount: + print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors." + print errmsg + else: + print " "+green("*")+" Processed",icount,"info files." + + +def post_emerge(retval=0): + global myopts + os.chdir("/") + if "--pretend" in myopts: + sys.exit(retval) + + emergelog(" *** exiting successfully.") + + if "noinfo" not in portage.settings.features: + chk_updated_info_files(retval) + + chk_updated_cfg_files() + sys.exit(retval) + + +def chk_updated_cfg_files(): + if portage.settings["CONFIG_PROTECT"]: + #number of directories with some protect files in them + procount=0 + for x in string.split(portage.settings["CONFIG_PROTECT"]): + if os.path.isdir(x): + a=commands.getstatusoutput("cd "+x+"; find . -iname '._cfg????_*'") + if a[0]!=0: + print " "+red("*")+" error scanning",x + else: + files=string.split(a[1]) + if files: + procount=procount+1 + print " "+yellow("* IMPORTANT:")+"",len(files),"config files in",x,"need updating." + if procount: + #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." + print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." + print + +# general options that should be taken into account before any action +if "--debug" in myopts: + edebug=1 + +if myaction in ["sync","rsync","metadata"] and (not "--help" in myopts): + if "--pretend" in myopts: + print "emerge: \"sync\" actions do not support \"--pretend.\"" + sys.exit(1) + + emergelog(" === "+str(myaction)) + myportdir=portage.settings["PORTDIR"] + if myportdir[-1]=="/": + myportdir=myportdir[:-1] + if not os.path.exists(myportdir): + print ">>>",myportdir,"not found, creating it." + os.makedirs(myportdir,0755) + syncuri=string.rstrip(portage.settings["SYNC"]) + os.umask(0022) + if myaction == "metadata": + if "--ask" in myopts: + if userquery("Are you sure?") == "No": + sys.exit(1) + print "skipping sync" + updatecache_flg = True + tmpservertimestampfile = None + elif syncuri[:8]=="rsync://": + if not os.path.exists("/usr/bin/rsync"): + print "!!! /usr/bin/rsync does not exist, so rsync support is disabled." + print "!!! Type \"emerge net-misc/rsync\" to enable rsync support." + sys.exit(1) + mytimeout=180 + if portage.settings.has_key("RSYNC_TIMEOUT"): + try: + mytimeout=int(portage.settings["RSYNC_TIMEOUT"]) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + rsync_flags = [ + "--recursive", # Recurse directories + "--links", # Consider symlinks + "--safe-links", # Ignore links outside of tree + "--perms", # Preserve permissions + "--times", # Preserive mod times + "--compress", # Compress the data transmitted + "--force", # Force deletion on non-empty dirs + "--whole-file", # Don't do block transfers, only entire files + "--delete", # Delete files that aren't in the master tree + "--delete-after", # Delete only after everything else is done + "--stats", # Show final statistics about what was transfered + "--timeout="+str(mytimeout), # IO timeout if not done in X seconds + "--exclude='/distfiles'", # Exclude distfiles from consideration + "--exclude='/local'", # Exclude local from consideration + "--exclude='/packages'", # Exclude packages from consideration + ] + + if "--quiet" in myopts: + rsync_flags.append("--quiet") # Shut up a lot + else: + rsync_flags.append("--progress") # Progress meter for each file + + if "--verbose" in myopts: + rsync_flags.append("--verbose") # More noise? Not really sure what + + if "--debug" in myopts: + rsync_flags.append("--checksum") # Force checksum on all files + + if portage.settings.has_key("RSYNC_EXCLUDEFROM"): + if os.path.exists(portage.settings["RSYNC_EXCLUDEFROM"]): + rsync_flags.append("--exclude-from="+portage.settings["RSYNC_EXCLUDEFROM"]) + else: + print "!!! RSYNC_EXCLUDEFROM specified, but file does not exist." + + if portage.settings.has_key("RSYNC_RATELIMIT"): + rsync_flags.append("--bwlimit="+portage.settings["RSYNC_RATELIMIT"]) + + rsynccommand = "/usr/bin/rsync " + string.join(rsync_flags, " ") + + servertimestampdir = portage.settings.depcachedir+"/" + servertimestampfile = portage.settings.depcachedir+"/timestamp.chk" + tmpservertimestampdir = portage.settings["PORTAGE_TMPDIR"]+"/" + tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk" + + # We only use the backup if a timestamp exists in the portdir. + content=None + if os.path.exists(myportdir+"/metadata/timestamp.chk"): + content=portage.grabfile(servertimestampfile) + if (not content): + content=portage.grabfile(myportdir+"/metadata/timestamp.chk") + + if (content): + try: + mytimestamp=time.mktime(time.strptime(content[0], "%a, %d %b %Y %H:%M:%S +0000")) + except ValueError: + mytimestamp=0 + else: + mytimestamp=0 + + if not os.path.exists(servertimestampdir): + os.mkdir(servertimestampdir) + os.chown(servertimestampdir, os.getuid(), portage.portage_gid) + os.chmod(servertimestampdir, 02775) + + #exitcode=0 + try: + maxretries=int(portage.settings["RSYNC_RETRIES"]) + except SystemExit, e: + raise # Needed else can't exit + except: + maxretries=3 #default number of retries + + retries=0 + hostname, port=re.split("rsync://([^:/]*)(:[0-9]+)?", syncuri)[1:3]; + if port==None: + port="" + updatecache_flg=True + + ips=[] + while (1): + if ips: + del ips[0] + if ips==[]: + try: + ips=socket.gethostbyname_ex(hostname)[2] + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if ips: + try: + dosyncuri=string.replace(syncuri, "//"+hostname+port+"/", "//"+ips[0]+port+"/", 1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if (retries==0): + if "--ask" in myopts: + if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No": + print + print "Quitting." + print + sys.exit(0) + emergelog(">>> starting rsync with "+dosyncuri) + if "--quiet" not in myopts: + print ">>> starting rsync with "+dosyncuri+"..." + else: + emergelog(">>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)) + print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri) + + if "--quiet" not in myopts: + print ">>> checking server timestamp ..." + mycommand=rsynccommand+" "+dosyncuri+"/metadata/timestamp.chk "+tmpservertimestampdir + exitcode=portage.spawn(mycommand,portage.settings,free=1) + if (exitcode==0): + try: + servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000")) + except SystemExit, e: + raise # Needed else can't exit + except: + servertimestamp = 0 + + if (servertimestamp != 0) and (servertimestamp == mytimestamp): + emergelog(">>> Cancelling sync -- Already current.") + print + print ">>>" + print ">>> Timestamps on the server and in the local repository are the same." + print ">>> Cancelling all further sync action. You are already up to date." + print ">>>" + print + sys.exit(0) + elif (servertimestamp != 0) and (servertimestamp < mytimestamp): + emergelog(">>> Server out of date: %s" % dosyncuri) + print + print ">>>" + print ">>> SERVER OUT OF DATE: %s" % dosyncuri + print ">>>" + print + elif (servertimestamp == 0) or (servertimestamp > mytimestamp): + # actual sync + mycommand=rsynccommand+" "+dosyncuri+"/ "+myportdir + exitcode=portage.spawn(mycommand,portage.settings,free=1) + if exitcode in [0,1,2,3,4,11,14,20,21]: + break + elif exitcode in [0,1,2,3,4,11,14,20,21]: + break + + retries=retries+1 + + if retries<=maxretries: + print ">>> retry ..." + time.sleep(11) + else: + # over retries + # exit loop + updatecache_flg=False + break + + if (exitcode==0): + emergelog("=== Sync completed with %s" % dosyncuri) + elif (exitcode>0): + print + if exitcode==1: + print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure") + print darkred("!!!")+green(" that your SYNC statement is proper.") + print darkred("!!!")+green(" SYNC="+portage.settings["SYNC"]) + elif exitcode==11: + print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally") + print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption") + print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate") + print darkred("!!!")+green(" and try again after the problem has been fixed.") + print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"]) + elif exitcode==20: + print darkred("!!!")+green(" Rsync was killed before it finished.") + else: + print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep") + print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable") + print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a") + print darkred("!!!")+green(" temporary problem unless complications exist with your network") + print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.") + print + sys.exit(exitcode) + elif syncuri[:6]=="cvs://": + if not os.path.exists("/usr/bin/cvs"): + print "!!! /usr/bin/cvs does not exist, so rsync support is disabled." + print "!!! Type \"emerge dev-util/cvs\" to enable CVS support." + sys.exit(1) + cvsroot=syncuri[6:] + cvsdir=os.path.dirname(myportdir) + if not os.path.exists(myportdir+"/CVS"): + #initial checkout + print ">>> starting initial cvs checkout with "+syncuri+"..." + if not portage.spawn("cd "+cvsdir+"; cvs -d "+cvsroot+" login",portage.settings,free=1): + print "!!! cvs login error; exiting." + sys.exit(1) + if os.path.exists(cvsdir+"/gentoo-x86"): + print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." + sys.exit(1) + if not portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",portage.settings,free=1): + print "!!! cvs checkout error; exiting." + sys.exit(1) + if cvsdir!=myportdir: + portage.movefile(cvsdir,portage.settings["PORTDIR"]) + sys.exit(0) + else: + #cvs update + print ">>> starting cvs update with "+syncuri+"..." + sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",portage.settings,free=1)) + else: + print "!!! rsync setting: ",syncuri,"not recognized; exiting." + sys.exit(1) + + try: # Prevent users from affecting ebuild.sh. + os.close(sys.stdin.fileno()) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg: + if "--quiet" not in myopts: + print "\n>>> Updating Portage cache: ", + os.umask(0002) + cachedir = os.path.normpath(portage.settings.depcachedir) + if cachedir in ["/", "/bin", "/dev", "/etc", "/home", + "/lib", "/opt", "/proc", "/root", "/sbin", + "/sys", "/tmp", "/usr", "/var"]: + print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM." + print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir) + sys.exit(73) + if not os.path.exists(cachedir): + os.mkdir(cachedir) + + # Potentially bad + #if os.path.exists(cachedir+"/"+myportdir): + # portage.spawn("rm -Rf "+cachedir+"/"+myportdir+"/*",portage.settings,free=1) + + # save timestamp.chk for next timestamp check. + try: + if tmpservertimestampfile != None: + portage.movefile(tmpservertimestampfile, servertimestampfile) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "!!! Failed to save current timestamp." + print "!!!",e + + portage.portdb.flush_cache() + + try: + os.umask(002) + os.chown(cachedir, os.getuid(), portage.portage_gid) + os.chmod(cachedir, 02775) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + # we don't make overlay trees cache here, plus we don't trust portage.settings.categories + porttree_root = portage.portdb.porttree_root + pdb = portage.portdbapi(porttree_root, portage.config(config_profile_path=portage.settings.profile_path[:], \ + config_incrementals=portage.settings.incrementals[:])) + cp_list = pdb.cp_all() + if len(cp_list) == 0: + print "no metadata to transfer, exiting" + sys.exit(0) + cp_list.sort() + pcnt=0 + pcntstr="" + pcntcount=len(cp_list)/100.0 + nextupdate=pcntcount + current=1 + + def cleanse_cache(pdb, cat, saves, porttree_root=porttree_root): + if len(saves): + d={} + for v in saves: + d[portage.catsplit(v)[1]] = True + for pv in pdb.auxdb[porttree_root][cat].keys(): + if pv not in d: + pdb.auxdb[porttree_root][cat].del_key(pv) + else: + try: + pdb.auxdb[porttree_root][cat].clear() + del pdb.auxdb[porttree_root][cat] + except KeyError: + pass + + savelist = [] + catlist = [] + oldcat = portage.catsplit(cp_list[0])[0] + for cp in cp_list: + current += 1 + if current >= nextupdate: + pcnt += 1 + nextupdate += pcntcount + if "--quiet" not in myopts: + pcntstr = str(pcnt) + sys.stdout.write("\b"*(len(pcntstr)+1)+pcntstr+"%") + sys.stdout.flush() + cat = portage.catsplit(cp)[0] + if cat != oldcat: + catlist.append(oldcat) + cleanse_cache(pdb, oldcat, savelist) + savelist = [] + oldcat = cat + mymatches = pdb.xmatch("match-all", cp) + savelist.extend(mymatches) + for cpv in mymatches: + try: pdb.aux_get(cpv, ["IUSE"],metacachedir=myportdir+"/metadata/cache",debug=("cachedebug" in portage.features)) + except SystemExit: raise + except Exception, e: print "\nFailed cache update:",cpv,e + catlist.append(oldcat) + catlist.append("local") + cleanse_cache(pdb, oldcat, savelist) + filelist = portage.listdir(cachedir+"/"+myportdir) + for x in filelist: + found = False + for y in catlist: + if x.startswith(y): + found = True + break + if not found: + portage.spawn("cd /; rm -Rf "+cachedir+"/"+myportdir+"/"+x,portage.settings,free=1,droppriv=1) + + + sys.stdout.write("\n\n") + sys.stdout.flush() + + portage.portageexit() + reload(portage) + mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage") + mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage")) + + chk_updated_cfg_files() + + if(mybestpv != mypvs): + print + print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended" + print red(" * ")+"that you update portage now, before any other packages are updated." + print red(" * ")+"Please do so and then update "+bold("ALL")+" of your configuration files." + print +elif myaction=="regen": + emergelog(" === regen") + #regenerate cache entries + print "Regenerating cache entries... " + try: + os.close(sys.stdin.fileno()) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + sys.stdout.flush() + mynodes=portage.portdb.cp_all() + for x in mynodes: + mymatches=portage.portdb.xmatch("match-all",x) + if not "--quiet" in myopts: + print "processing",x + for y in mymatches: + try: + foo=portage.portdb.aux_get(y,["DEPEND"],debug=1) + except SystemExit, e: + # sys.exit is an exception... And consequently, we can't catch it. + raise + except Exception, e: + print "\n error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)} + print "done!" +# HELP action +elif "config"==myaction: + if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles: + print red("!!! config can only take a single package atom at this time\n") + sys.exit(1) + + print + pkgs = portage.db[portage.root]["vartree"].dbapi.match(myfiles[0]) + if len(pkgs) == 0: + print "No packages found.\n" + sys.exit(0) + elif len(pkgs) > 1: + if "--ask" in myopts: + options = [] + print "Please select a package to configure:" + idx = 0 + for pkg in pkgs: + idx += 1 + options.append(str(idx)) + print options[-1]+") "+pkg + print "X) Cancel" + options.append("X") + idx = userquery("Selection?", options) + if idx == "X": + sys.exit(0) + pkg = pkgs[int(idx)-1] + else: + print "The following packages available:" + for pkg in pkgs: + print "* "+pkg + print "\nPlease use a specific atom or the --ask option." + sys.exit(1) + else: + pkg = pkgs[0] + + print + if "--ask" in myopts: + if userquery("Ready to configure "+pkg+"?") == "No": + sys.exit(0) + else: + print "Configuring pkg..." + print + ebuildpath = portage.db[portage.root]["vartree"].dbapi.findname(pkg) + mysettings = portage.config(clone=portage.settings) + portage.doebuild(ebuildpath,"config",portage.root,mysettings,debug=("--debug" in myopts),cleanup=True) + print + +# INFO action +elif "info"==myaction: + unameout=commands.getstatusoutput("uname -mrp")[1] + print getportageversion() + print "=================================================================" + print "System uname: "+unameout + if os.path.exists("/etc/gentoo-release"): + os.system("cat /etc/gentoo-release") + else: + print "Unknown Host Operating System" + + output=commands.getstatusoutput("distcc --version") + if not output[0]: + print str(string.split(output[1],"\n",1)[0]), + if "distcc" in portage.features: + print "[enabled]" + else: + print "[disabled]" + + output=commands.getstatusoutput("ccache -V") + if not output[0]: + print str(string.split(output[1],"\n",1)[0]), + if "ccache" in portage.features: + print "[enabled]" + else: + print "[disabled]" + + myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers", + "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] + myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs") + myvars = portage_util.unique_array(myvars) + myvars.sort() + + for x in myvars: + if portage.isvalidatom(x): + pkg_matches = portage.db["/"]["vartree"].dbapi.match(x) + pkgs = [] + for y in pkg_matches: + mycpv = portage.catpkgsplit(y) + if(mycpv[3] != "r0"): + pkgs += [mycpv[2] + "-" + mycpv[3]] + else: + pkgs += [mycpv[2]] + if not pkgs: + pkgs = "[Not Present]" + else: + pkgs = ", ".join(sorted_versions(pkgs)) + print "%-20s %s" % (x+":", pkgs) + else: + print "%-20s %s" % (x+":", "[NOT VALID]") + + libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",") + + if "--verbose" in myopts: + myvars=portage.settings.keys() + else: + myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK', + 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR', + 'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS', + 'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES'] + + myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars")) + + myvars = portage_util.unique_array(myvars) + unset_vars = [] + myvars.sort() + for x in myvars: + if portage.settings.has_key(x): + print x+'="'+portage.settings[x]+'"' + else: + unset_vars.append(x) + if unset_vars: + print "Unset: "+", ".join(unset_vars) + print + + if "--debug" in myopts: + for x in dir(portage): + module = getattr(portage, x) + if "cvs_id_string" in dir(module): + print "%s: %s" % (str(x), str(module.cvs_id_string)) + +# SEARCH action +elif "search"==myaction: + if not myfiles: + print "emerge: no search terms provided." + else: + searchinstance = search() + for mysearch in myfiles: + try: + searchinstance.execute(mysearch) + except re.error, comment: + print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment ) + sys.exit(1) + searchinstance.output() +elif "inject"==myaction: + if not myfiles: + print "emerge: please specify at least one cat/pkg-ver to inject." + sys.exit(1) + if "--pretend" in myopts: + print "emerge: the \"inject\" action does not support \"--pretend.\"" + sys.exit(1) + for x in myfiles: + if x[0] in [">","<","=","!"]: + print "!!! '"+x+"' is an invalid specification." + print "!!! Must be 'category/package-version' with no other symbols." + print + continue + mycps=portage.catpkgsplit(x) + if (not mycps) or (mycps[0]=="null"): + print "!!!",x,"is not a specific cat/pkg-version, skipping..." + continue + if portage.db["/"]["vartree"].exists_specific(x): + print "!!! Not injecting",x+"; Package already exists." + else: + if "--ask" in myopts: + if userquery("Do you want to inject the package %s?" % x)=="No": + print + print "Quitting." + print + sys.exit(0) + portage.db["/"]["vartree"].dbapi.cpv_inject(x) + print ">>> Injected",x+"." + emergelog(" === inject: "+x) +elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction: + if 1==unmerge(myaction, myfiles): + post_emerge() + +elif "depclean"==myaction: + # Kill packages that aren't explicitly merged or are required as a + # dependency of another package. World file is explicit. + + print + print red("*** WARNING ***")+" : DEPCLEAN CAN SERIOUSLY IMPAIR YOUR SYSTEM. USE CAUTION." + print red("*** WARNING ***")+" : (Cancel: CONTROL-C) -- ALWAYS VERIFY ALL PACKAGES IN THE" + print red("*** WARNING ***")+" : CANDIDATE LIST FOR SANITY BEFORE ALLOWING DEPCLEAN TO" + print red("*** WARNING ***")+" : UNMERGE ANY PACKAGES." + print red("*** WARNING ***")+" :" + print red("*** WARNING ***")+" : USE FLAGS MAY HAVE AN EXTREME EFFECT ON THE OUTPUT." + print red("*** WARNING ***")+" : SOME LIBRARIES MAY BE USED BY PACKAGES BUT ARE NOT" + print red("*** WARNING ***")+" : CONSIDERED TO BE A DEPEND DUE TO USE FLAG SETTINGS." + print red("*** WARNING ***")+" : emerge --update --deep --newuse world TO VERIFY" + print red("*** WARNING ***")+" : SANITY IN THIS REGARD." + print red("*** WARNING ***")+" :" + print red("*** WARNING ***")+" : Packages in the list that are desired may be added" + print red("*** WARNING ***")+" : directly to the world file to cause them to be ignored" + print red("*** WARNING ***")+" : by depclean and maintained in the future. BREAKAGES DUE" + print red("*** WARNING ***")+" : TO UNMERGING AN ==IN-USE LIBRARY== MAY BE REPAIRED BY" + print red("*** WARNING ***")+" : MERGING *** THE PACKAGE THAT COMPLAINS *** ABOUT THE" + print red("*** WARNING ***")+" : MISSING LIBRARY." + print + if ("--pretend" not in myopts) and ("--ask" not in myopts): + countdown(EMERGE_WARNING_DELAY, ">>> Depclean") + emergelog(" >>> depclean") + + mydepgraph=depgraph(myaction,myopts) + syslist=getlist("system") + worldlist=getlist("world") + + print "Calculating",myaction,"dependencies ", + if not mydepgraph.xcreate("world"): + print "\n!!! Failed to create deptree." + sys.exit(1) + print "\b\b ... done!" + + if ("--usepkgonly" in myopts) and mydepgraph.missingbins: + sys.stderr.write(red("The following binaries are not available for merging...\n")) + for x in mydepgraph.missingbins: + sys.stderr.write(" "+str(x)+"\n") + sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") + sys.exit(1) + + alldeps=mydepgraph.digraph.allnodes() + myvarlist=portage.vardbapi(portage.root).cp_all() + + if not syslist: + print "!!! You have no system list. Cannot determine system from world." + if not worldlist: + print "!!! You have no world file. Cannot determine explicit merges." + if not myvarlist: + print "!!! You have no installed package tree (%s). This is a problem." % portage.VDB_PATH + if not alldeps: + print "!!! You have no dependencies. Impossible. Bug." + + if not (syslist and worldlist and myvarlist and alldeps): + print + sys.exit(1) + + reallist=[] + for x in alldeps: + myparts=portage.catpkgsplit(string.split(x)[2]) + if not myparts: + sys.stderr.write( + red("!!! There appears to be a problem with the following package:\n")+ + red("!!! "+str(string.split(x)[2])+"\n\n")+ + "!!! Please ensure that blocking/conflicting packages are not merged."+ + "!!! 'emerge -p "+str(string.split(x)[2])+"\n\n") + if ("--pretend" not in myopts) and ("--ask" not in myopts): + countdown(EMERGE_WARNING_DELAY, "*** Continuing") + continue + + catpack=myparts[0]+"/"+myparts[1] + if catpack not in reallist: + reallist.append(catpack) + + cleanlist=[] + for x in myvarlist: + if x not in reallist: + if x not in cleanlist: + cleanlist.append(x) + + for x in syslist+worldlist: + myparts = portage.catpkgsplit(x) + if myparts: + if myparts[0][0] in ('<','>','='): + myparts[0] = myparts[0][1:] + if myparts[0][0] in ('<','>','='): + myparts[0] = myparts[0][1:] + catpack=myparts[0]+"/"+myparts[1] + else: + catpack=x + if catpack in cleanlist: + cleanlist.remove(catpack) + + #print "\n\n\nCleaning: " + #for x in cleanlist: + # print x + #print + + if len(cleanlist): + unmerge("unmerge", cleanlist) + + print + print "Packages installed: "+str(len(myvarlist)) + print "Packages in world: "+str(len(worldlist)) + print "Packages in system: "+str(len(syslist)) + print "Unique package names: "+str(len(reallist)) + print "Required packages: "+str(len(alldeps)) + if "--pretend" in myopts: + print "Number to remove: "+str(len(cleanlist)) + else: + print "Number removed: "+str(len(cleanlist)) + post_emerge() + +# "update", "system", or just process files: +else: + favorites=[] + syslist=getlist("system") + if (("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts)) or ("--ask" in myopts): + if "--tree" in myopts: + print + print darkgreen("These are the packages that I would merge, in reverse order:") + print + else: + print + print darkgreen("These are the packages that I would merge, in order:") + print + + if ("--resume" in myopts) and portage.mtimedb.has_key("resume"): + myresumeopts=portage.mtimedb["resume"]["myopts"][:] + + while "--skipfirst" in myresumeopts: + myresumeopts.remove("--skipfirst") + while "--ask" in myresumeopts: + myresumeopts.remove("--ask") + + for myopt in myopts: + if myopt not in myresumeopts: + myresumeopts.append(myopt) + myopts=myresumeopts + mydepgraph=depgraph("resume",myopts) + if "--resume" not in myopts: + myopts+=["--resume"] + else: + if ("--resume" in myopts): + del myopts[myopts.index("--resume")] + print darkgreen("emerge: It seems we have nothing to resume...") + sys.exit(0) + + mydepgraph=depgraph(myaction,myopts) + if myaction in ["system","world"]: + print "Calculating",myaction,"dependencies ", + sys.stdout.flush() + if not mydepgraph.xcreate(myaction): + print "!!! Depgraph creation failed." + sys.exit(1) + print "\b\b ...done!" + else: + if not myfiles: + print "emerge: please tell me what to do." + help() + sys.exit(1) + #we don't have any files to process; skip this step and exit + print "Calculating dependencies ", + sys.stdout.flush() + retval,favorites=mydepgraph.select_files(myfiles) + if not retval: + sys.exit(1) + print "\b\b ...done!" + + if ("--usepkgonly" in myopts) and mydepgraph.missingbins: + sys.stderr.write(red("The following binaries are not available for merging...\n")) + + if mydepgraph.missingbins: + for x in mydepgraph.missingbins: + sys.stderr.write(" "+str(x)+"\n") + sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") + sys.exit(1) + + if "--ask" in myopts: + if "--resume" in myopts: + mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) + prompt="Do you want me to resume merging these packages?" + else: + mydepgraph.display(mydepgraph.altlist()) + mergecount=0 + for x in mydepgraph.altlist(): + if x[3]!="nomerge": + mergecount+=1 + #check for blocking dependencies + if x[0]=="blocks": + print "\n!!! Error: The above package list contains packages which cannot be installed" + print "!!! on the same system." + print + sys.exit(1) + if mergecount==0: + if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: + prompt="Nothing to merge; do you want me to auto-clean packages?" + else: + print + print "Nothing to merge; quitting." + print + sys.exit(0) + elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + prompt="Do you want me to fetch the source files for these packages?" + else: + prompt="Do you want me to merge these packages?" + print + if userquery(prompt)=="No": + print + print "Quitting." + print + sys.exit(0) + # Don't ask again (e.g. when auto-cleaning packages after merge) + myopts.remove("--ask") + + if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + if ("--resume" in myopts): + mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) + else: + mydepgraph.display(mydepgraph.altlist()) + else: + if ("--buildpkgonly" in myopts): + if not mydepgraph.digraph.hasallzeros(): + print "\n!!! --buildpkgonly requires all dependencies to be merged." + print "!!! Cannot merge requested packages. Merge deps and try again.\n" + sys.exit(1) + + if ("--resume" in myopts): + favorites=portage.mtimedb["resume"]["favorites"] + mydepgraph.merge(portage.mtimedb["resume"]["mergelist"]) + else: + portage.mtimedb["resume"]={} + portage.mtimedb["resume"]["myopts"]=myopts + portage.mtimedb["resume"]["favorites"]=favorites + if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + for pkgline in mydepgraph.altlist(): + if pkgline[0]=="ebuild" and pkgline[3]=="merge": + y=portage.portdb.findname(pkgline[2]) + tmpsettings = portage.config(clone=portage.settings) + retval=portage.doebuild(y,"digest",portage.root,tmpsettings,edebug,("--pretend" in myopts)) + mydepgraph.merge(mydepgraph.altlist()) + + if portage.mtimedb.has_key("resume"): + del portage.mtimedb["resume"] + if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: + print ">>> Auto-cleaning packages ..." + unmerge("clean", ["world"]) + post_emerge() diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync new file mode 100755 index 000000000..024af23e8 --- /dev/null +++ b/bin/emerge-webrsync @@ -0,0 +1,141 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/Attic/emerge-webrsync,v 1.8.2.4 2005/02/26 11:22:38 carpaski Exp $ +# Author: Karl Trygve Kalleberg <karltk@gentoo.org> +# Rewritten from the old, Perl-based emerge-webrsync script + +GENTOO_MIRRORS="${GENTOO_MIRRORS} $(/usr/lib/portage/bin/portageq gentoo_mirrors)" +PORTDIR="$(/usr/lib/portage/bin/portageq portdir)" +FETCHCOMMAND="$(/usr/lib/portage/bin/portageq envvar FETCHCOMMAND)" +USERLAND="$(/usr/lib/portage/bin/portageq envvar USERLAND)" +DISTDIR="$(/usr/lib/portage/bin/portageq envvar PORTAGE_TMPDIR)/emerge-webrsync" + +if [ ! -d $DISTDIR ] ; then + mkdir -p $DISTDIR +fi + +cd "$DISTDIR" + +found=0 +if [ "$1" == "-v" ] ; then + wgetops= +else + #this sucks. probably better to do 1> /dev/null + #that said, waiting on the refactoring. + if [ "${FETCHCOMMAND/wget}" != "${FETCHCOMMAND}" ]; then + wgetops="-q" + elif [ "${FETCHCOMMAND/curl}" != "${FETCHCOMMAND}" ]; then + wgetops="-s -f" + fi +fi + +if type -p md5sum > /dev/null; then + md5_com='md5sum -c "${FILE}.md5sum"' +elif type -p md5 > /dev/null; then + md5_com='[ "$(md5 -q ${FILE})" == "$(cut -d \ -f 1 ${FILE}.md5sum)" ]' +else + echo "warning, unable to do md5 verification of the snapshot!" + echo "no suitable md5/md5sum binary was found!" + md5_com='true' +fi + +sync_local() { + echo Syncing local tree... + if ! tar jxf $FILE; then + echo "Tar failed to extract the image. Please review the output." + echo "Executed command: tar jxf $FILE" + exit 1 + fi + rm -f $FILE + # Make sure user and group file ownership is root + chown -R 0:0 portage + cd portage + rsync -av --progress --stats --delete --delete-after \ + --exclude='/distfiles' --exclude='/packages' \ + --exclude='/local' . ${PORTDIR%%/} + cd .. + echo "cleaning up" + rm -rf portage + echo "transferring metadata/cache" + emerge metadata +} + +echo "Fetching most recent snapshot" + +declare -i attempts=-1 +while (( $attempts < 40 )) ; do + attempts=$(( attempts + 1 )) + + #this too, sucks. it works in the interim though. + if [ "$USERLAND" == "BSD" ] || [ "$USERLAND" == "Darwin" ] ; then + daysbefore=$(expr $(date +"%s") - 86400 \* $attempts) + day=$(date -r $daysbefore +"%d") + month=$(date -r $daysbefore +"%m") + year=$(date -r $daysbefore +"%Y") + else + day=$(date -d "-$attempts day" +"%d") + month=$(date -d "-$attempts day" +"%m") + year=$(date -d "-$attempts day" +"%Y") + fi + + FILE_ORIG="portage-${year}${month}${day}.tar.bz2" + + echo "Attempting to fetch file dated: ${year}${month}${day}" + + got_md5=0 + + if [ ! -e "${FILE_ORIG}.md5sum" ]; then + FILE="${FILE_ORIG}.md5sum" + for i in $GENTOO_MIRRORS ; do + URI="${i}/snapshots/${FILE}" + if (eval "$FETCHCOMMAND $wgetops") && [ -s "${FILE}" ]; then + got_md5=1 + break + fi + done + else + got_md5=1 + fi + FILE="${FILE_ORIG}" + + if (($got_md5 == 0 )); then + echo " --- No md5sum present on the mirror. (Not yet available.)" + continue + elif [ -s "${FILE}" ]; then + if eval "$md5_com"; then + echo " === snapshot $FILE is correct, using it" + sync_local + echo + echo " === Snapshot has beed sync'd" + echo + exit 0 + else + rm $FILE + fi + fi + + for i in $GENTOO_MIRRORS ; do + URI="${i}/snapshots/$FILE" + rm -f "$FILE" + if (eval "$FETCHCOMMAND $wgetops") && [ -s "$FILE" ]; then + if ! eval "$md5_com"; then + echo "md5 failed on $FILE" + rm ${FILE} + continue + else + sync_local + echo + echo " *** Completed websync, please now perform a normal rsync if possible." + echo " Update is current as of the of YYYYMMDD: ${year}${month}${day}" + echo + exit 0 + fi + fi + + done +done + +rm -rf portage + +exit 1 diff --git a/bin/emerge.orig b/bin/emerge.orig new file mode 100755 index 000000000..c66f32eae --- /dev/null +++ b/bin/emerge.orig @@ -0,0 +1,3227 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/emerge,v 1.345.2.33 2005/06/02 00:57:52 vapier Exp $ + +import os,sys +os.environ["PORTAGE_CALLER"]="emerge" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage + +import emergehelp,xpak,string,re,commands,time,shutil,traceback,atexit,signal,socket,types +from stat import * +from output import * + +import portage_util +import portage_locks +import portage_exception + + +spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")", + "Thank you for using Gentoo. :)", + "Are you actually trying to read this?", + "How many times have you stared at this?", + "We are generating the cache right now", + "You are paying too much attention.", + "A theory is better than its explanation.", + "Phasers locked on target, Captain.", + "Thrashing is just virtual crashing.", + "To be is to program.", + "Real Users hate Real Programmers.", + "When all else fails, read the instructions.", + "Functionality breeds Contempt.", + "The future lies ahead.", + "3.1415926535897932384626433832795028841971694", + "Sometimes insanity is the only alternative.", + "Inaccuracy saves a world of explanation.", + ] + + +def update_basic_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % 500 + if (spinpos % 100) == 0: + if spinpos == 0: + sys.stdout.write(". ") + else: + sys.stdout.write(".") + sys.stdout.flush() + +def update_scroll_spinner(): + global spinner, spinpos + if(spinpos >= len(spinner)): + sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))])) + else: + sys.stdout.write(green("\b "+spinner[spinpos])) + sys.stdout.flush() + spinpos = (spinpos+1) % (2*len(spinner)) + +def update_twirl_spinner(): + global spinner, spinpos + spinpos = (spinpos+1) % len(spinner) + sys.stdout.write("\b\b "+spinner[spinpos]) + sys.stdout.flush() + +spinpos = 0 +spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" +update_spinner = update_twirl_spinner +if "candy" in portage.settings.features: + spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)] + update_spinner = update_scroll_spinner +if not sys.stdout.isatty() or ("--nospinner" in sys.argv): + update_spinner = update_basic_spinner + + +if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]): + nocolor() + +def normpath(mystr): + if mystr and (mystr[0]=='/'): + return os.path.normpath("///"+mystr) + else: + return os.path.normpath(mystr) + +def userquery(prompt, responses=None, colours=None): + """Displays a prompt and a set of responses, then waits for a response + which is checked against the responses and the first to match is + returned. + + prompt: a String. + responses: a List of Strings. + colours: a List of Functions taking and returning a String, used to + process the responses for display. Typically these will be functions + like red() but could be e.g. lambda x: "DisplayString". + If responses is omitted, defaults to ["Yes, "No"], [green, red]. + If only colours is omitted, defaults to [bold, ...]. + + Returns a member of the List responses. (If called without optional + arguments, returns "Yes" or "No".) + KeyboardInterrupt is converted to SystemExit to avoid tracebacks being + printed.""" + if responses is None: + responses, colours = ["Yes", "No"], [green, red] + elif colours is None: + colours=[bold] + colours=(colours*len(responses))[:len(responses)] + print bold(prompt), + try: + while True: + response=raw_input("["+string.join([colours[i](responses[i]) for i in range(len(responses))],"/")+"] ") + for key in responses: + if response.upper()==key[:len(response)].upper(): + return key + print "Sorry, response '%s' not understood." % response, + except (EOFError, KeyboardInterrupt): + print "Interrupted." + sys.exit(1) + +def sorted_versions(verlist): + ret = [] + for ver in verlist: + verparts = ver.split("-") + if len(verparts) == 2: + verrev = int(verparts[1][1:]) + else: + verrev = 0 + x = 0 + while x < len(ret): + retparts = ret[x].split("-") + verdiff = portage.vercmp(retparts[0], verparts[0]) + if verdiff > 0: + break + elif verdiff == 0: + if len(retparts) == 2: + retrev = int(retparts[1][1:]) + else: + retrev = 0 + if retrev >= verrev: + break + x += 1 + ret.insert(x, ver) + return ret + +if portage.settings.has_key("PORTAGE_NICENESS"): + try: + os.nice(int(portage.settings["PORTAGE_NICENESS"])) + except SystemExit, e: + raise # Needed else can't exit + except Exception,e: + print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'" + print "!!!",e + +#Freeze the portdbapi for enhanced performance: +portage.portdb.freeze() + +# Kill noauto as it will break merges otherwise. +while 'noauto' in portage.features: + del portage.features[portage.features.index('noauto')] + +#number of ebuilds merged +merged=0 +params=["selective", "deep", "self", "recurse", "empty"] +actions=[ +"clean", "config", "depclean", +"info", "inject", "metadata", +"prune", "regen", "rsync", "search", +"sync", "system", "unmerge", "world", +] +options=[ +"--ask", +"--buildpkg", "--buildpkgonly", +"--changelog", "--columns", +"--debug", "--deep", +"--digest", +"--emptytree", +"--fetchonly", "--fetch-all-uri", +"--getbinpkg", "--getbinpkgonly", +"--help", "--noconfmem", +"--newuse", "--nocolor", +"--nodeps", "--noreplace", +"--nospinner", "--oneshot", +"--onlydeps", "--pretend", +"--quiet", "--resume", +"--searchdesc", "--selective", +"--skipfirst", +"--tree", +"--update", "--upgradeonly", +"--usepkg", "--usepkgonly", +"--verbose", "--version" +] + +shortmapping={ +"1":"--oneshot", +"a":"--ask", +"b":"--buildpkg", "B":"--buildpkgonly", +"c":"--clean", "C":"--unmerge", +"d":"--debug", "D":"--deep", +"e":"--emptytree", +"f":"--fetchonly", "F":"--fetch-all-uri", +"g":"--getbinpkg", "G":"--getbinpkgonly", +"h":"--help", +"i":"--inject", +"k":"--usepkg", "K":"--usepkgonly", +"l":"--changelog", +"n":"--noreplace", "N":"--newuse", +"o":"--onlydeps", "O":"--nodeps", +"p":"--pretend", "P":"--prune", +"q":"--quiet", +"s":"--search", "S":"--searchdesc", +'t':"--tree", +"u":"--update", "U":"--upgradeonly", +"v":"--verbose", "V":"--version" +} + +myaction=None +myopts=[] +myfiles=[] +edebug=0 + +# process short actions +tmpcmdline=sys.argv[1:] +#tmpcmdline.extend(portage.settings["EMERGE_OPTS"].split()) +cmdline=[] +for x in tmpcmdline: + if x[0:1]=="-"and x[1:2]!="-": + for y in x[1:]: + if shortmapping.has_key(y): + if shortmapping[y] in cmdline: + print + print "*** Warning: Redundant use of",shortmapping[y] + else: + cmdline.append(shortmapping[y]) + else: + print "!!! Error: -"+y+" is an invalid short action or option." + sys.exit(1) + else: + cmdline.append(x) + +# process the options and command arguments +for x in cmdline: + if not x: + continue + if len(x)>=2 and x[0:2]=="--": + if x in options: + myopts.append(x) + elif x[2:] in actions: + if x[2:]=="rsync" or x=="rsync": + # "emerge --rsync" + print + print red("*** '--rsync' has been deprecated.") + print red("*** Please use '--sync' instead.") + print + x="--sync" + if myaction: + if myaction not in ["system", "world"]: + myaction="--"+myaction + print + print red("!!!")+green(" Multiple actions requested... Please choose one only.") + print red("!!!")+" '"+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" + print + sys.exit(1) + myaction=x[2:] + else: + print "!!! Error:",x,"is an invalid option." + sys.exit(1) + elif (not myaction) and (x in actions): + if x not in ["system", "world"]: + #print red("*** Deprecated use of action '"+x+"'") + if x=="rsync": + # "emerge rsync" + print + print red("*** 'rsync' will now install the package rsync.") + print red("*** To sync the tree, please use '--sync' instead.") + print + myfiles.append(x) + continue + if myaction: + print + print red("!!!")+green(" Multiple actions requested... Please choose one only.") + print red("!!! '")+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" + print + sys.exit(1) + myaction=x + elif x[-1]=="/": + # this little conditional helps tab completion + myfiles.append(x[:-1]) + else: + myfiles.append(x) + + +if "moo" in myfiles: + print """ + + Gentoo (""" + os.uname()[0] + """) + + _______________________ +< Have you mooed today? > + ----------------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + +""" + +if (myaction in ["world", "system"]) and myfiles: + print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both." + sys.exit(1) + +for x in myfiles: + if (x[-7:] == ".ebuild" or x[-5:] == ".tbz2") and os.path.exists(os.path.abspath(x)): + print "emerging by path implies --oneshot... adding --oneshot to options." + print red("\n*** emerging by path is broken and may not always work!!!\n") + break + +if ("--tree" in myopts) and ("--columns" in myopts): + print "emerge: can't specify both of \"--tree\" and \"--columns\"." + sys.exit(1) + +# Always create packages if FEATURES=buildpkg +# Imply --buildpkg if --buildpkgonly +if ("buildpkg" in portage.features) or ("--buildpkgonly" in myopts): + if "--buildpkg" not in myopts: + myopts.append("--buildpkg") + +# --tree only makes sense with --pretend +if "--tree" in myopts and not (("--pretend" in myopts) or ("--ask" in myopts)): + print ">>> --tree implies --pretend... adding --pretend to options." + myopts.append("--pretend") + +# Also allow -S to invoke search action (-sS) +if ("--searchdesc" in myopts): + if myaction and myaction != "search": + myfiles.append(myaction) + if "--search" not in myopts: + myopts.append("--search") + myaction = "search" + +# Always try and fetch binary packages if FEATURES=getbinpkg +if ("getbinpkg" in portage.features): + myopts.append("--getbinpkg") + +if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): + myopts.append("--usepkgonly") + +if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): + myopts.append("--getbinpkg") + +if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): + myopts.append("--usepkg") + +# Also allow -K to apply --usepkg/-k +if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): + myopts.append("--usepkg") + +# Print deprecation warning for -U +if ("--upgradeonly" in myopts): + print + print red("*** Warning: --upgradeonly is a deprecated option in portage-"+portage.VERSION) + print red("*** and will likely be removed in a future version.") + print + # Also allow -U to apply --update/-u + if not ("--update" in myopts): + print ">>> --upgradeonly implies --update... adding --update to options." + myopts.append("--update") + +# Also allow -l to apply --pretend/-p, but if already in --ask mode +if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)): + print ">>> --changelog implies --pretend... adding --pretend to options." + myopts.append("--pretend") + +# Allow -p to remove --ask +if ("--pretend" in myopts) and ("--ask" in myopts): + print ">>> --pretend disables --ask... removing --ask from options." + myopts.remove("--ask") + +# forbid --ask when not in a terminal +# note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. +if ("--ask" in myopts) and (not sys.stdin.isatty()): + portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n") + sys.exit(1) + +# Set so that configs will be merged regardless of remembered status +if ("--noconfmem" in myopts): + portage.settings.unlock() + portage.settings["NOCONFMEM"]="1" + portage.settings.backup_changes("NOCONFMEM") + portage.settings.lock() + +# Set various debug markers... They should be merged somehow. +if ("--debug" in myopts): + portage.settings.unlock() + portage.settings["PORTAGE_DEBUG"]="1" + portage.settings.backup_changes("PORTAGE_DEBUG") + portage.debug=1 + portage.settings.lock() + +if ("--resume" in myopts): + if "--verbose" in myopts: + print "* --verbose is currently broken with --resume. Disabling..." + myopts.remove("--verbose") + if "--tree" in myopts: + print "* --tree is currently broken with --resume. Disabling..." + myopts.remove("--tree") + +# Set color output +if ("--nocolor" in myopts) and (sys.stdout.isatty()): + nocolor() + +CLEAN_DELAY = 5 +EMERGE_WARNING_DELAY = 10 +if portage.settings["CLEAN_DELAY"]: + CLEAN_DELAY = string.atoi("0"+portage.settings["CLEAN_DELAY"]) +if portage.settings["EMERGE_WARNING_DELAY"]: + EMERGE_WARNING_DELAY = string.atoi("0"+portage.settings["EMERGE_WARNING_DELAY"]) + +if "inject" == myaction: + print + print red("*** --inject has been deprecated.") + print red("*** If you manage a piece of software yourself, add it's name and") + print red("*** version (eg foo/bar-1.0) to /etc/portage/profile/package.provided.") + print red("*** If you want to prevent portage from upgrading a package, add it to") + print red("*** /etc/portage/package.mask prepending it with '>' (eg >foo/bar-1.0)") + print red("*** For more information on fine-grained portage control, please see") + print red("*** the portage man page.") + print + +def emergelog(mystr,short_msg=None): + if "notitles" not in portage.features: + if short_msg: + xtermTitle(short_msg) + else: + xtermTitle(mystr) + try: + #seems odd opening a file each write... + if not os.path.exists("/var/log/emerge.log"): + mylogfile=open("/var/log/emerge.log", "w") + os.chmod("/var/log/emerge.log", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) + os.chown("/var/log/emerge.log", portage.portage_uid, portage.portage_gid) + else: + mylogfile=open("/var/log/emerge.log", "a") + + l=portage_locks.lockfile(mylogfile) + # seek because we may have gotten held up by the lock. + # if so, we may not be positioned at the end of the file. + mylogfile.seek(0,2) + mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") + mylogfile.flush() + portage_locks.unlockfile(l) + mylogfile.close() + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if edebug: + print "emergelog():",e + pass + +def emergeexit(): + """This gets out final log message in before we quit.""" + if "--pretend" not in myopts: + emergelog(" *** terminating.") + if "notitles" not in portage.features: + xtermTitleReset() +atexit.register(emergeexit) + +def emergeexitsig(signum, frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + portage.portageexit() + portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) + sys.exit(100+signum) +signal.signal(signal.SIGINT, emergeexitsig) + +def countdown(secs=5, doing="Starting"): + if secs: + print ">>> Waiting",secs,"seconds before starting..." + print ">>> (Control-C to abort)...\n"+doing+" in: ", + ticks=range(secs) + ticks.reverse() + for sec in ticks: + sys.stdout.write(red(str(sec+1)+" ")) + sys.stdout.flush() + time.sleep(1) + print + +# formats a size given in bytes nicely +def format_size(mysize): + if type(mysize) not in [types.IntType,types.LongType]: + return str(mysize) + mystr=str(mysize/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + return mystr+" kB" + + +def getgccversion(): + """ + rtype: C{str} + return: the current in-use gcc version + """ + + gcc_env_dir = os.path.join('/', 'etc', 'env.d', 'gcc') + gcc_config_config = os.path.join(gcc_env_dir, 'config') + gcc_ver_command = 'gcc -dumpversion' + gcc_ver_prefix = 'gcc-' + + gcc_not_found_error = red( + "!!! No gcc found. You probably need to 'source /etc/profile'\n" + + "!!! to update the environment of this terminal and possibly\n" + + "!!! other terminals also." + ) + + gcc_distcc_broken_error = green( + '!!! Relying on the shell to locate gcc, this may break\n' + + '!!! DISTCC, installing gcc-config and setting your current gcc\n' + + '!!! profile will fix this' + ) + + def fallback(): + + print >>sys.stderr, gcc_distcc_broken_error + + gccout = commands.getstatusoutput(gcc_ver_command) + + if gccout[0] != 0: + print >>sys.stderr, gcc_not_found_error + gccver = "[unavailable]" + else: + gccver = gcc_ver_prefix + gccout[1] + + return gccver + + if os.path.isfile(gcc_config_config): + try: + gccver_str = open(gcc_config_config).read().strip() + gccver = gcc_ver_prefix + string.join(gccver_str.split('-')[4:], '-') + except IndexError: + gccver = fallback() + + else: + import glob + dir_l = glob.glob(os.path.join(gcc_env_dir, '*-*')) + + if len(dir_l) == 1: + try: + gccver = gcc_ver_prefix + dir_l[0].split('-')[-1] + except IndexError: + gccver = fallback() + + else: + # There was no "config" file in /etc/env.d/gcc and there was more + # than one profile in /etc/env.d/gcc so we can't actively + # determine what version of gcc we are using so we fall back on the + # old way that breaks distcc + + gccver = fallback() + + return gccver + +def getportageversion(): + try: + import re + profilever = os.path.normpath("///"+os.readlink("/etc/make.profile")) + basepath = os.path.normpath("///"+portage.settings["PORTDIR"]+"/profiles") + if re.match(basepath,profilever): + profilever = profilever[len(basepath)+1:] + else: + profilever = "!"+profilever + del basepath + except SystemExit, e: + raise # Needed else can't exit + except: + profilever="unavailable" + libcver=[] + libclist = portage.vardbapi(portage.root).match("virtual/libc") + libclist += portage.vardbapi(portage.root).match("virtual/glibc") + libclist = portage_util.unique_array(libclist) + for x in libclist: + xs=portage.catpkgsplit(x) + if libcver: + libcver+=","+string.join(xs[1:], "-") + else: + libcver=string.join(xs[1:], "-") + if libcver==[]: + libcver="unavailable" + + gccver = getgccversion() + unameout=os.uname()[2]+" "+os.uname()[4] + + return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")" + +def help(): + # Move all the help stuff out of this file. + emergehelp.help(myaction,myopts,havecolor) + +# check if root user is the current user for the actions where emerge needs this +if ("--pretend" in myopts) or ("--fetchonly" in myopts or "--fetch-all-uri" in myopts) or (myaction=="search"): + if not portage.secpass: + if portage.wheelgid==portage.portage_gid: + print "emerge: wheel group membership required for \"--pretend\" and search." + print "emerge: wheel group use is being deprecated. Please update group and passwd to" + print " include the portage user as noted above, and then use group portage." + else: + print "emerge: portage group membership required for \"--pretend\" and search." + sys.exit(1) +elif "--version" in myopts: + print getportageversion() + sys.exit(0) +elif "--help" in myopts: + help() + sys.exit(0) +elif portage.secpass!=2: + if myaction in ["search", "info", "regen"]: + pass + elif (not myaction) and (not myfiles): + pass + elif ("--pretend" in myopts) and (myaction in ["world","system","clean","prune","unmerge"]): + pass + else: + if "--debug" in myopts: + print "myaction",myaction + print "myopts",myopts + print "emerge: root access required." + sys.exit(1) + +if not "--pretend" in myopts: + emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) + myelogstr="" + if myopts: + myelogstr=string.join(myopts, " ") + if myaction: + myelogstr+=" "+myaction + if myfiles: + myelogstr+=" "+string.join(myfiles, " ") + emergelog(" *** emerge "+myelogstr) + +#configure emerge engine parameters +# +# self: include _this_ package regardless of if it is merged. +# selective: exclude the package if it is merged +# recurse: go into the dependencies +# empty: pretend nothing is merged +myparams=["self","recurse"] +add=[] +sub=[] +if "--update" in myopts: + add.extend(["selective","empty"]) +if "--emptytree" in myopts: + add.extend(["empty"]) + sub.extend(["selective"]) +if "--nodeps" in myopts: + sub.extend(["recurse"]) +if "--noreplace" in myopts: + add.extend(["selective"]) +if "--deep" in myopts: + add.extend(["deep"]) +if "--selective" in myopts: + add.extend(["selective"]) +if myaction in ["world","system"]: + add.extend(["selective"]) +elif myaction in ["depclean"]: + add.extend(["empty"]) + sub.extend(["selective"]) +for x in add: + if (x not in myparams) and (x not in sub): + myparams.append(x) +for x in sub: + if x in myparams: + myparams.remove(x) + +# search functionality +class search: + + # + # class constants + # + VERSION_SHORT=1 + VERSION_RELEASE=2 + + # + # public interface + # + def __init__(self): + """Searches the available and installed packages for the supplied search key. + The list of available and installed packages is created at object instantiation. + This makes successive searches faster.""" + self.installcache = portage.db["/"]["vartree"] + + def execute(self,searchkey): + """Performs the search for the supplied search key""" + global myopts + match_category = 0 + self.searchkey=searchkey + self.packagematches = [] + if "--searchdesc" in myopts: + self.searchdesc=1 + self.matches = {"pkg":[], "desc":[]} + else: + self.searchdesc=0 + self.matches = {"pkg":[]} + print "Searching... ", + + if self.searchkey[0] == '@': + match_category = 1 + self.searchkey = self.searchkey[1:] + if self.searchkey=="*": + #hack for people who aren't regular expression gurus + self.searchkey==".*" + if re.search("\+\+", self.searchkey): + #hack for people who aren't regular expression gurus + self.searchkey=re.sub("\+\+","\+\+",self.searchkey) + self.searchre=re.compile(self.searchkey.lower(),re.I) + for package in portage.portdb.cp_all(): + update_spinner() + + if match_category: + match_string = package[:] + else: + match_string = package.split("/")[-1] + + masked=0 + if self.searchre.search(match_string): + if not portage.portdb.xmatch("match-visible",package): + masked=1 + self.matches["pkg"].append([package,masked]) + elif self.searchdesc: # DESCRIPTION searching + full_package = portage.portdb.xmatch("bestmatch-visible",package) + if not full_package: + #no match found; we don't want to query description + full_package=portage.best(portage.portdb.xmatch("match-all",package)) + if not full_package: + continue + else: + masked=1 + try: + full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0] + except KeyError: + print "emerge: search: aux_get() failed, skipping" + continue + if self.searchre.search(full_desc): + self.matches["desc"].append([full_package,masked]) + self.mlen=0 + for mtype in self.matches.keys(): + self.matches[mtype].sort() + self.mlen += len(self.matches[mtype]) + + def output(self): + """Outputs the results of the search.""" + print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]" + print "[ Applications found : "+white(str(self.mlen))+" ]" + print " " + for mtype in self.matches.keys(): + for match,masked in self.matches[mtype]: + if mtype=="pkg": + catpack=match + full_package = portage.portdb.xmatch("bestmatch-visible",match) + if not full_package: + #no match found; we don't want to query description + masked=1 + full_package=portage.best(portage.portdb.xmatch("match-all",match)) + else: + full_package = match + match = portage.pkgsplit(match)[0] + + if full_package: + try: + desc, homepage, license = portage.portdb.aux_get(full_package,["DESCRIPTION","HOMEPAGE","LICENSE"]) + except KeyError: + print "emerge: search: aux_get() failed, skipping" + continue + if masked: + print green("*")+" "+white(match)+" "+red("[ Masked ]") + else: + print green("*")+" "+white(match) + myversion = self.getVersion(full_package, search.VERSION_RELEASE) + + mysum = [0,0] + mycat = match.split("/")[0] + mypkg = match.split("/")[1] + + mydigest = portage.db["/"]["porttree"].dbapi.finddigest(mycat+"/"+mypkg + "-" + myversion) + + try: + myfile = open(mydigest,"r") + for line in myfile.readlines(): + mysum[0] += int(line.split(" ")[3]) + myfile.close() + mystr = str(mysum[0]/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + mysum[0]=mystr+" kB" + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if edebug: + print "!!! Exception:",e + mysum[0]=" [no/bad digest]" + + if "--quiet" not in myopts: + print " ", darkgreen("Latest version available:"),myversion + print " ", self.getInstallationStatus(mycat+'/'+mypkg) + print " ", darkgreen("Size of downloaded files:"),mysum[0] + print " ", darkgreen("Homepage:")+" ",homepage + print " ", darkgreen("Description:"),desc + print " ", darkgreen("License:")+" ",license + print + print + # + # private interface + # + def getInstallationStatus(self,package): + installed_package = self.installcache.dep_bestmatch(package) + result = "" + version = self.getVersion(installed_package,search.VERSION_RELEASE) + if len(version) > 0: + result = darkgreen("Latest version installed:")+" "+version + else: + result = darkgreen("Latest version installed:")+" [ Not Installed ]" + return result + + def getVersion(self,full_package,detail): + if len(full_package) > 1: + package_parts = portage.catpkgsplit(full_package) + if detail == search.VERSION_RELEASE and package_parts[3] != 'r0': + result = package_parts[2]+ "-" + package_parts[3] + else: + result = package_parts[2] + else: + result = "" + return result + + +#build our package digraph +def getlist(mode): + if mode=="system": + mylines=portage.settings.packages + elif mode=="world": + try: + myfile=open(portage.root+portage.WORLD_FILE,"r") + mylines=myfile.readlines() + myfile.close() + except OSError: + print "!!! Couldn't open "+pfile+"; exiting." + sys.exit(1) + except IOError: + #world file doesn't exist + mylines=[] + mynewlines=[] + for x in mylines: + myline=string.join(string.split(x)) + if not len(myline): + continue + elif myline[0]=="#": + continue + elif mode=="system": + if myline[0]!="*": + continue + myline=myline[1:] + mynewlines.append(myline.strip()) + + # Remove everything that is package.provided from our list + for myatom in mynewlines[:]: + mykey = portage.dep_getkey(myatom) + if portage.settings.pprovideddict.has_key(mykey) and \ + portage.match_from_list(myatom, portage.settings.pprovideddict[mykey]): + mynewlines.remove(myatom) + + return mynewlines + +def genericdict(mylist): + mynewdict={} + for x in mylist: + mynewdict[portage.dep_getkey(x)]=x + return mynewdict + +olddbapi=None +class depgraph: + + def __init__(self,myaction,myopts): + global olddbapi + self.pkgsettings = portage.config(clone=portage.settings) + if not self.pkgsettings["ARCH"]: + portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n")) + portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n")) + sys.exit(9) + self.applied_useflags = {} + + self.missingbins=[] + self.myaction=myaction + self.digraph=portage.digraph() + self.orderedkeys=[] + self.outdatedpackages=[] + self.mydbapi={} + self.mydbapi["/"] = portage.fakedbapi() + if "empty" not in myparams: + for pkg in portage.db["/"]["vartree"].getallcpv(): + self.mydbapi["/"].cpv_inject(pkg) + if portage.root != "/": + self.mydbapi[portage.root] = portage.fakedbapi() + if "empty" not in myparams: + for pkg in portage.db[portage.root]["vartree"].getallcpv(): + self.mydbapi[portage.root].cpv_inject(pkg) + + if "--usepkg" in myopts: + portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts)) + + def create(self,mybigkey,myparent=None,addme=1,myuse=None): + """creates the actual digraph of packages to merge. return 1 on success, 0 on failure + mybigkey = specification of package to merge; myparent = parent package (one depending on me); + addme = should I be added to the tree? (for the --onlydeps mode)""" + #stuff to add: + #SLOT-aware emerge + #IUSE-aware emerge + #"no downgrade" emerge + #print "mybigkey:",mybigkey + + jbigkey=string.join(mybigkey) + if self.digraph.hasnode(jbigkey+" merge") or self.digraph.hasnode(jbigkey+" nomerge"): + #this conditional is needed to prevent infinite recursion on already-processed deps + return 1 + + update_spinner() + + mytype,myroot,mykey=mybigkey + # select the correct /var database that we'll be checking against + vardbapi=portage.db[myroot]["vartree"].dbapi + + if addme: + # if the package is already on the system, we add a "nomerge" + # directive, otherwise we add a "merge" directive. + if mytype=="blocks": + # we've encountered a "blocks" node. We will totally ignore this + # node and not add it to our digraph if it doesn't apply to us. + if "--buildpkgonly" not in myopts and myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)): + mybigkey.append(myparent.split()[2]) + self.digraph.addnode(string.join(mybigkey),myparent) + return 1 + + if myuse == None: + self.pkgsettings.setcpv(mykey) + myuse=string.split(self.pkgsettings["USE"], " ") + + self.applied_useflags[mykey] = myuse + + merging=1 + if addme: + # this is where we add the node to the list of packages to merge + if not myparent: + # command-line specified or part of a world list... + if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)): + # the package is on the system, so don't merge it. + merging=0 + elif ("selective" in myparams) and vardbapi.cpv_exists(mykey): + merging=0 + + if (merging==0 and mytype=="ebuild" and "--newuse" in myopts and vardbapi.cpv_exists(mykey)): + iuses=string.split(portage.portdb.aux_get(mykey, ["IUSE"])[0]) + old_use=string.split(vardbapi.aux_get(mykey, ["USE"])[0]) + now_use=string.split(self.pkgsettings["USE"]) + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + merging=1 + break + else: + #onlydeps mode; don't merge + merging=2 + if merging==1: + mybigkey.append("merge") + else: + mybigkey.append("nomerge") + + # whatever the case, we need to add the node to our digraph so + # that children can depend upon it. + self.digraph.addnode(string.join(mybigkey),myparent) + if ("deep" not in myparams) and (not merging): + return 1 + elif "recurse" not in myparams: + return 1 + + edepend={} + if mytype=="binary": + mypkgparts=portage.catpkgsplit(mykey) + tbz2name = string.split(mykey, "/")[1]+".tbz2" + if tbz2name in portage.db[portage.root]["bintree"].invalids: + sys.stderr.write("\nINVALID PACKAGE (is required to continue): "+str(mykey)+"\n") + sys.exit(1) + if portage.db[portage.root]["bintree"].isremote(mykey): + edepend = portage.db[portage.root]["bintree"].remotepkgs[tbz2name] + edepend["DEPEND"] ="" + edepend["RDEPEND"]=string.join(string.split(edepend["RDEPEND"])," ") + edepend["PDEPEND"]=string.join(string.split(edepend["PDEPEND"])," ") + edepend["SLOT"] =string.strip(edepend["SLOT"]) + #portage.db[portage.root]["bintree"].gettbz2(mykey) + else: # It's local. + mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey)) + edepend["DEPEND"] ="" + edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ") + edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ") + edepend["SLOT"] =mytbz2.getfile("SLOT",mypkgparts[2]) + elif mytype=="ebuild": + try: + mymeta = ["DEPEND","RDEPEND","PDEPEND"] + myfoo = portage.portdb.aux_get(mykey, mymeta) + for index in range(0,len(mymeta)): + edepend[mymeta[index]] = myfoo[index] + if "--buildpkgonly" in myopts: + edepend["RDEPEND"] = "" + except (KeyError,IOError): + print "emerge: create(): aux_get() error on",mykey+"; aborting..." + sys.exit(1) + mydep={} + mp=string.join(mybigkey) + + if myroot=="/": + mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"] + if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): + return 0 + else: + mydep["/"]=edepend["DEPEND"] + mydep[myroot]=edepend["RDEPEND"] + if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): + return 0 + if not self.select_dep(myroot,mydep[myroot],myparent=mp,myuse=myuse): + return 0 + + if edepend.has_key("PDEPEND") and edepend["PDEPEND"]: + # Post Depend -- Add to the list without a parent, as it depends + # on a package being present AND must be built after that package. + if not self.select_dep(myroot,edepend["PDEPEND"],myuse=myuse): + return 0 + + return 1 + + def select_files(self,myfiles): + "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list" + myfavorites=[] + for x in myfiles: + if x[-5:]==".tbz2": + if not os.path.exists(x): + if os.path.exists(self.pkgsettings["PKGDIR"]+"/All/"+x): + x=self.pkgsettings["PKGDIR"]+"/All/"+x + elif os.path.exists(self.pkgsettings["PKGDIR"]+"/"+x): + x=self.pkgsettings["PKGDIR"]+"/"+x + else: + print "\n\n!!! Binary package '"+str(x)+"' does not exist." + print "!!! Please ensure the tbz2 exists as specified.\n" + sys.exit(1) + mytbz2=xpak.tbz2(x) + mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(x)[:-5] + if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x): + print red("\n*** You need to adjust PKGDIR to emerge this package.\n") + sys.exit(1) + if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts): + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + elif x[-7:]==".ebuild": + x = os.path.realpath(x) + mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.basename(x)[:-7] + ebuild_path = portage.db["/"]["porttree"].dbapi.findname(mykey) + if ebuild_path: + if os.path.realpath(ebuild_path) != x: + print red("\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") + sys.exit(1) + if mykey not in portage.db["/"]["porttree"].dbapi.xmatch("match-visible", portage.dep_getkey(mykey)): + print red("\n*** You are emerging a masked package. It is MUCH better to use") + print red("*** /etc/portage/package.* to accomplish this. See portage(5) man") + print red("*** page for details.") + countdown(EMERGE_WARNING_DELAY, "Continuing...") + else: + print red("\n*** "+x+" does not exist") + sys.exit(1) + if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts): + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + else: + try: + mykey=portage.dep_expand(x,mydb=portage.portdb) + except ValueError, errpkgs: + print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" + print "!!! one of the following fully-qualified ebuild names instead:\n" + for i in errpkgs[0]: + print " " + green(i) + print + sys.exit(1) + + # select needs to return 0 on dep_check failure + + sys.stdout.flush() + sys.stderr.flush() + + try: + self.mysd = self.select_dep(portage.root,mykey,arg=x) + except portage_exception.MissingSignature, e: + portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n") + portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") + portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") + portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e)) + sys.exit(1) + except portage_exception.InvalidSignature, e: + portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n") + portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") + portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") + portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e)) + sys.exit(1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + if "--debug" in myopts: + raise + print "\n\n!!! Problem in",mykey,"dependencies." + print "!!!",str(e),e.__module__ + sys.exit(1) + + if not self.mysd: + return (0,myfavorites) + elif not "--oneshot" in myopts: + myfavorites.append(mykey) + + missing=0 + if "--usepkgonly" in myopts: + for x in self.digraph.dict.keys(): + xs=string.split(x," ") + if (xs[0] != "binary") and (xs[3]=="merge"): + if missing == 0: + print + missing += 1 + print "Missing binary for:",xs[2] + + # We're true here unless we are missing binaries. + return (not missing,myfavorites) + + def is_newer_ver_installed(self,myroot,pkg,pkgver): + "if there is a version of pkg installed newer than pkgver, return it" + vardbapi=portage.db[myroot]["vartree"].dbapi + + matches=portage.db[myroot]["vartree"].dbapi.match(pkg) + if matches: + myslot=portage.db["/"]["porttree"].getslot(pkgver) + for match in matches: + if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(match)[1:]) < 0: + curslot=portage.db[myroot]["vartree"].getslot(match) + if curslot == myslot: + return match + + def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None): + "given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure" + if "--debug" in myopts: + print + print "Parent: ",myparent + print "Depstring:",depstring + if not arg: + #processing dependencies + mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkg" in myopts)) + #mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse) + + if not mycheck[0]: + mymerge=[] + else: + mymerge=mycheck[1] + + else: + #we're processing a command-line argument; unconditionally merge it even if it's already merged + mymerge=[depstring] + + # dep_check has been run so we can now add our parent to our + # build state to update virtuals and other settings. This + # happens after the package is added to the tree so that a + # package can depend on a virtual which it satisfies. + if myparent: + myp = myparent.split() + if myp[3]=="merge": + self.mydbapi[myroot].cpv_inject(myp[2]) + if myp[0]=="binary": + self.pkgsettings.setinst(myp[2],portage.db["/"]["bintree"].dbapi) + else: + self.pkgsettings.setinst(myp[2],portage.db[myroot]["porttree"].dbapi) + + if not mymerge: + return 1 + + if "--debug" in myopts: + print "Candidates:",mymerge + for x in mymerge: + myk=None + binpkguseflags=None + if x[0]=="!": + # if this package is myself, don't append it to block list. + if "--debug" in myopts: + print "Myparent",myparent + if (myparent): + if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]): + # myself, so exit. + continue + # adding block + myk=["blocks",myroot,x[1:]] + else: + #We are not processing a blocker but a normal dependency + myeb=None + myeb_matches = portage.portdb.xmatch("match-visible",x) + if ("--usepkgonly" not in myopts): + myeb=portage.best(myeb_matches) + + myeb_pkg=None + if ("--usepkg" in myopts): + # The next line assumes the binarytree has been populated. + # XXX: Need to work out how we use the binary tree with roots. + myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x) + if ("--usepkgonly" not in myopts): + # Remove any binary package entries that are masked in the portage tree (#55871) + for idx in range(len(myeb_pkg_matches)-1,-1,-1): + if myeb_pkg_matches[idx] not in myeb_matches: + del myeb_pkg_matches[idx] + myeb_pkg = portage.best(myeb_pkg_matches) + + if not myeb_pkg: + myeb_pkg = None + elif ("--newuse" in myopts): + iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["IUSE"])[0]) + old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["USE"])[0]) + self.pkgsettings.setcpv(myeb_pkg) + now_use=string.split(self.pkgsettings["USE"]) + self.pkgsettings.reset() + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + myeb_pkg = None + break + + if (not myeb) and (not myeb_pkg): + if not arg: + xinfo='"'+x+'"' + else: + xinfo='"'+arg+'"' + if myparent: + xfrom = '(dependency required by '+green('"'+myparent.split()[2]+'"')+red(' ['+myparent.split()[0]+"])") + alleb=portage.portdb.xmatch("match-all",x) + if alleb: + if "--usepkgonly" not in myopts: + print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") + print "!!! One of the following masked packages is required to complete your request:" + oldcomment = "" + for p in alleb: + mreasons = portage.getmaskingstatus(p) + print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")" + comment = portage.getmaskingreason(p) + if comment and comment != oldcomment: + print comment + oldcomment = comment + print + print "For more information, see MASKED PACKAGES section in the emerge man page or " + print "section 2.2 \"Software Availability\" in the Gentoo Handbook." + if myparent: + print "!!! "+red(xfrom) + print + else: + print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo) + print "!!! Either add a suitable binary package or compile from an ebuild." + else: + print "\nemerge: there are no ebuilds to satisfy "+xinfo+"." + if myparent: + print xfrom + print + return 0 + + if "--debug" in myopts: + print "ebuild:",myeb + print "binpkg:",myeb_pkg + + if myeb and myeb_pkg: + myeb_s = portage.catpkgsplit(myeb) + myeb_s = [myeb_s[0]+"/"+myeb_s[1], myeb_s[2], myeb_s[3]] + myeb_pkg_s = portage.catpkgsplit(myeb_pkg) + myeb_pkg_s = [myeb_pkg_s[0]+"/"+myeb_pkg_s[1], myeb_pkg_s[2], myeb_pkg_s[3]] + + if portage.pkgcmp(myeb_s, myeb_pkg_s) == 0: # pkg is same version as ebuild + myeb = None + else: + myeb_pkg = None + + if "--upgradeonly" in myopts: + # Check that there isn't a newer version of this package already installed + cand = None + try: + # XXX: This can throw an exception if the ebuild doesn't exist + if myeb: + cand=self.is_newer_ver_installed(myroot,x,myeb) + elif myeb_pkg: + cand=self.is_newer_ver_installed(myroot,x,myeb_pkg) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Warning: "+str(e) + if cand: + myeb=cand + + if myeb: + myk=["ebuild",myroot,myeb] + elif myeb_pkg: + binpkguseflags=portage.db[portage.root]["bintree"].get_use(myeb_pkg) + myk=["binary",myroot,myeb_pkg] + else: + sys.stderr.write("!!! Confused... Don't know what I'm using for dependency info. :(\n") + sys.exit(1) + + #if "--usepkg" in myopts: + # #If we want to use packages, see if we have a pre-built one... + # mypk=portage.db["/"]["bintree"].dbapi.match(x) + # if myeb in mypk: + # #Use it only if it's exactly the version we want. + # myk=["binary",myroot,myeb] + # else: + # myk=["ebuild",myroot,myeb] + #else: + # myk=["ebuild",myroot,myeb] + if myparent: + #we are a dependency, so we want to be unconditionally added + if not self.create(myk,myparent,myuse=binpkguseflags): + return 0 + else: + #if mysource is not set, then we are a command-line dependency and should not be added + #if --onlydeps is specified. + if not self.create(myk,myparent,"--onlydeps" not in myopts,myuse=binpkguseflags): + return 0 + + if "--debug" in myopts: + print "Exiting...",myparent + return 1 + + + def altlist(self): + mygraph=self.digraph.copy() + dolist=["/"] + retlist=[] + for x in portage.db.keys(): + portage.db[x]["merge"]=[] + if x not in dolist: + dolist.append(x) + while (not mygraph.empty()): + mycurkey=mygraph.firstzero() + if not mycurkey: + print "!!! Error: circular dependencies:" + print + for x in mygraph.dict.keys(): + for y in mygraph.dict[x][1]: + print y,"depends on",x + print + sys.exit(1) + splitski=string.split(mycurkey) + #I'm not sure of the significance of the following lines (vestigal?) so I'm commenting 'em out. + #These lines remove already-merged things from our alt-list + #if "--update" in myopts: + # if not portage.db["/"]["vartree"].exists_specific(splitski[2]): + # portage.db["/"]["merge"].append(splitski) + #else: + portage.db[splitski[1]]["merge"].append(splitski) + mygraph.delnode(mycurkey) + for x in dolist: + for y in portage.db[x]["merge"]: + retlist.append(y) + return retlist + + def xcreate(self,mode="system"): + global syslist + if mode=="system": + mylist=syslist + else: + #world mode + worldlist=getlist("world") + sysdict=genericdict(syslist) + worlddict=genericdict(worldlist) + #we're effectively upgrading sysdict to contain all new deps from worlddict + for x in worlddict.keys(): + #only add the world node if the package is: + #actually installed -- this prevents the remerging of already unmerged packages when we do a world --update; + #actually available -- this prevents emerge from bombing out due to no match being found (we want a silent ignore) + if "empty" in myparams: + if portage.db["/"]["vartree"].dbapi.match(x): + sysdict[x]=worlddict[x] + elif portage.db[portage.root]["vartree"].dbapi.match(x): + #package is installed + sysdict[x]=worlddict[x] + else: + print "\n*** Package in world file is not installed: "+x + mylist = sysdict.keys() + + for mydep in mylist: + myeb=portage.portdb.xmatch("bestmatch-visible",mydep) + if not myeb: + #this is an unavailable world entry; just continue + continue + + if "--upgradeonly" in myopts: + cand=self.is_newer_ver_installed(portage.root,mydep,myeb) + if cand: + myeb=cand + + #THIS NEXT BUNCH OF CODE NEEDS TO BE REPLACED TO SUPPORT WORLD ANTI-DEPS + #if mydep2[0]=="!":, etc. + binpkguseflags = None + if "--usepkg" in myopts: + mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) + if myeb==mypk: + myk=["binary",portage.root,mypk] + binpkguseflags=portage.db[portage.root]["bintree"].get_use(mypk) + if ("--newuse" in myopts): + iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(mypk, ["IUSE"])[0]) + old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(mypk, ["USE"])[0]) + self.pkgsettings.setcpv(mypk) + now_use=string.split(self.pkgsettings["USE"]) + self.pkgsettings.reset() + for x in iuses: + if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): + myk=["ebuild",portage.root,myeb] + binpkguseflags=None + break + elif "--usepkgonly" in myopts: + if not mypk: + self.missingbins += [myeb] + myk=["binary",portage.root,myeb] + else: + myk=["binary",portage.root,mypk] + else: + myk=["ebuild",portage.root,myeb] + else: + myk=["ebuild",portage.root,myeb] + + if not self.create(myk,myuse=binpkguseflags): + print + print "!!! Problem with dependencies under ",myk[0],myk[2] + print "!!! Possibly a DEPEND/*DEPEND problem." + print + return 0 + return 1 + + def match(self,mydep,myroot=portage.root,mykey=None): + # support mutual exclusive deps + mydep2=mydep + if mydep2[0]=="!": + mydep2=mydep[1:] + + if mydep[0]=="!": + #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example) + myk="blocks "+myroot+" "+mydep2 + else: + myeb=portage.db[portage.root]["porttree"].dep_bestmatch(mydep2) + if not myeb: + if not mykey: + print "\n!!! Error: couldn't find match for",mydep + else: + print "\n!!! Error: couldn't find match for",mydep,"in",mykey + print + sys.exit(1) + + if "--usepkg" in myopts: + mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) + if myeb==mypk: + myk="binary "+portage.root+" "+mypk + else: + myk="ebuild "+myroot+" "+myeb + else: + myk="ebuild "+myroot+" "+myeb + + return myk + + def display(self,mylist): + changelogs=[] + p=[] + totalsize=0 + + if "--verbose" in myopts: + overlays = string.split(portage.settings['PORTDIR_OVERLAY']) + + if "--tree" in myopts: + mylist.reverse() + mygraph=self.digraph.copy() + + i = 0 + while i < len(mylist): + if mylist[i][-1]=="nomerge": + if not ("--tree" in myopts): + # we don't care about this elements + mylist.pop(i) + continue + if (i == (len(mylist) - 1)) \ + or (mygraph.depth(string.join(mylist[i])) \ + >= mygraph.depth(string.join(mylist[i+1]))): + # end of a useless branch (may be the last one) + # -> delete the element and test the previous one + mylist.pop(i) + if i > 0: + i -= 1 + continue + # the branch continues, or we've found a good element. + # -> let's see what's next, if anything + i += 1 + + display_overlays=False + # files to fetch list - avoids counting a same file twice + # in size display (verbose mode) + myfetchlist=[] + for x in mylist: + fetch=" " + + if x[0]=="blocks": + addl=""+red("B")+" "+fetch+" " + resolved=portage.db[x[1]]["vartree"].resolve_key(x[2]) + print "["+x[0]+" "+addl+"]",red(resolved), + if resolved!=x[2]: + if x[3]: + print red("(\""+x[2]+"\" is blocking "+x[3]+")") + else: + print red("(\""+x[2]+"\")") + else: + if x[3]: + print red("(is blocking "+x[3]+")") + else: + print + else: + if (x[0]!="binary") and ("fetch" in string.split(portage.portdb.aux_get(x[2],["RESTRICT"])[0])): + fetch = red("F") + if portage.portdb.fetch_check(x[2], portage.settings): + fetch = green("f") + + #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty" + #param is used for -u, where you still *do* want to see when something is being upgraded. + myoldbest="" + if (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]): + addl=" "+yellow("R")+fetch+" " + elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]): + if x[0] == "binary": + mynewslot=portage.db["/"]["bintree"].getslot(x[2]) + elif x[0] == "ebuild": + mynewslot=portage.db["/"]["porttree"].getslot(x[2]) + myoldlist=portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0]) + myinslotlist=filter((lambda p: portage.db[portage.root]["vartree"].getslot(p)==mynewslot),myoldlist) + if myinslotlist: + myoldbest=portage.best(myinslotlist) + addl=" "+fetch + if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: + # Downgrade in slot + addl+=turquoise("U")+blue("D") + else: + # Update in slot + addl+=turquoise("U")+" " + else: + # New slot, mark it new. + addl=" "+green("NS")+fetch+" " + + if "--changelog" in myopts: + changelogs.extend(self.calc_changelog( + portage.portdb.findname(x[2]), + portage.db["/"]["vartree"].dep_bestmatch('/'.join(portage.catpkgsplit(x[2])[:2])), + x[2] + )) + else: + addl=" "+green("N")+" "+fetch+" " + + verboseadd="" + if "--verbose" in myopts: + # iuse verbose + try: + if x[0] == "binary": + iuse_split = string.split(portage.db["/"]["bintree"].dbapi.aux_get(x[2],["IUSE"])[0]) + elif x[0] == "ebuild": + iuse_split = string.split(portage.portdb.aux_get(x[2],["IUSE"])[0]) + else: + iuse_split = [] + except SystemExit, e: + raise # Needed else can't exit + except: + portage.writemsg("!!! Error getting IUSE (report this to bugs.gentoo.org)\n") + portage.writemsg("!!! %s\n" % x) + iuse_split = [] + iuse_split.sort() + old_use=None + if myoldbest: + pkg=myoldbest + else: + pkg=x[2] + if portage.db["/"]["vartree"].dbapi.cpv_exists(pkg): + try: + old_use=string.split(portage.db["/"]["vartree"].dbapi.aux_get(pkg, ["USE"])[0]) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + iuse="" + now_use=self.applied_useflags[x[2]] + for ebuild_iuse in portage_util.unique_array(iuse_split): + usechange="" + if old_use: + if (old_use.count(ebuild_iuse) and not now_use.count(ebuild_iuse)) or (not old_use.count(ebuild_iuse) and now_use.count(ebuild_iuse)): + usechange="*" + + if ebuild_iuse in self.applied_useflags[x[2]]: + if usechange == "*": + iuse=green("+"+ebuild_iuse) + else: + iuse=red("+"+ebuild_iuse) + elif ebuild_iuse in portage.settings.usemask: + iuse=blue("(-"+ebuild_iuse+")") + else: + iuse=blue("-"+ebuild_iuse) + verboseadd+=iuse+usechange+" " + + # size verbose + mysize=0 + if x[0] == "ebuild" and x[-1]!="nomerge": + myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug) + if myfilesdict==None: + myfilesdict="[empty/missing/bad digest]" + else: + for myfetchfile in myfilesdict.keys(): + if myfetchfile not in myfetchlist: + mysize+=myfilesdict[myfetchfile] + myfetchlist.append(myfetchfile) + totalsize+=mysize + verboseadd+=format_size(mysize)+" " + + # overlay verbose + # XXX: Invalid binaries have caused tracebacks here. 'if file_name' + # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge'] + file_name=portage.portdb.findname(x[2]) + if file_name: # It might not exist in the tree + dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..") + if (overlays.count(dir_name)>0): + verboseadd+=teal("["+str(overlays.index(os.path.normpath(dir_name))+1)+"]")+" " + display_overlays=True + else: + verboseadd += "[No ebuild?]" + + xs=portage.pkgsplit(x[2]) + if xs[2]=="r0": + xs[2]="" + else: + xs[2]="-"+xs[2] + + if self.pkgsettings.has_key("COLUMNWIDTH"): + mywidth=int(self.pkgsettings.settings["COLUMNWIDTH"]) + else: + mywidth=130 + oldlp=mywidth-30 + newlp=oldlp-30 + + indent="" + if ("--tree" in myopts): + indent=" "*mygraph.depth(string.join(x)) + + if myoldbest: + myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] + if myoldbest[-3:]=="-r0": + myoldbest=myoldbest[:-3] + myoldbest=blue("["+myoldbest+"]") + + if x[1]!="/": + if "--columns" in myopts: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) + if (newlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(newlp-nc_len(myprint))) + myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " + if (oldlp-nc_len(myprint)) > 0: + myprint=myprint+" "*(oldlp-nc_len(myprint)) + myprint=myprint+myoldbest + myprint=myprint+darkgreen(" to "+x[1])+" "+verboseadd + else: + myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd + else: + if "--columns" in myopts: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) + if (newlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(newlp-nc_len(myprint))) + myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") + if (oldlp-nc_len(myprint)) > 0: + myprint=myprint+(" "*(oldlp-nc_len(myprint))) + myprint=myprint+myoldbest+" "+verboseadd + else: + if x[3]=="nomerge": + myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd + else: + myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd + p.append(myprint) + + if ("--tree" not in myopts): + mysplit=portage.pkgsplit(x[2]) + + # XXX mysplit _can_ be None.... Why? + if mysplit and (len(mysplit)==3): + if "--emptytree" not in myopts: + if mysplit[0]=="sys-apps/portage": + if ((mysplit[1]+mysplit[2]) != portage.VERSION) and \ + ("livecvsportage" not in portage.settings.features): + if mylist.index(x)<len(mylist)-1: + p.append(red("*** Portage will stop merging at this point and reload itself,")) + p.append(red(" recalculate dependencies, and complete the merge.")) + if "--update" not in myopts: + p.append(darkgreen(" You may avoid the remerging of packages by updating portage on its own.")) + print + else: + if mysplit[0]=="sys-apps/portage" and ("--emptytree" in myopts): + if mysplit[1]+mysplit[2]!=portage.VERSION: + p.append(red("***")+" Please update portage to the above version before proceeding.") + p.append(" Failure to do so may result in failed or improper merges.") + p.append(" A simple '"+green("emerge -u portage")+"' is sufficient.") + p.append("") + del mysplit + + for x in p: + print x + + if "--verbose" in myopts: + print + print "Total size of downloads: "+format_size(totalsize) + if overlays and display_overlays: + print "Portage overlays:" + y=0 + for x in overlays: + y=y+1 + print " "+teal("["+str(y)+"]"),x + + if "--changelog" in myopts: + print + for revision,text in changelogs: + print bold('*'+revision) + sys.stdout.write(text) + + def calc_changelog(self,ebuildpath,current,next): + current = '-'.join(portage.catpkgsplit(current)[1:]) + if current.endswith('-r0'): current = current[:-3] + next = '-'.join(portage.catpkgsplit(next)[1:]) + if next.endswith('-r0'): next = next[:-3] + changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') + try: + changelog = open(changelogpath).read() + except SystemExit, e: + raise # Needed else can't exit + except: + return [] + divisions = self.find_changelog_tags(changelog) + #print 'XX from',current,'to',next + #for div,text in divisions: print 'XX',div + # skip entries for all revisions above the one we are about to emerge + for i in range(len(divisions)): + if divisions[i][0]==next: + divisions = divisions[i:] + break + # find out how many entries we are going to display + for i in range(len(divisions)): + if divisions[i][0]==current: + divisions = divisions[:i] + break + else: + # couldnt find the current revision in the list. display nothing + return [] + return divisions + + def find_changelog_tags(self,changelog): + divs = [] + release = None + while 1: + match = re.search(r'^\*\ ?([-a-zA-Z0-9_.]*)(?:\ .*)?\n',changelog,re.M) + if match is None: + if release is not None: + divs.append((release,changelog)) + return divs + if release is not None: + divs.append((release,changelog[:match.start()])) + changelog = changelog[match.end():] + release = match.group(1) + if release.endswith('.ebuild'): + release = release[:-7] + if release.endswith('-r0'): + release = release[:-3] + + def outdated(self): + return self.outdatedpackages + + def merge(self,mylist): + returnme=0 + mymergelist=[] + + #check for blocking dependencies + if ("--fetchonly" not in myopts) and ("--buildpkgonly" not in myopts): + for x in mylist: + if x[0]=="blocks": + print "\n!!! Error: the "+x[2]+" package conflicts with another package." + print "!!! both can't be installed on the same system together." + print "!!! Please use 'emerge --pretend' to determine blockers." + print + if ("--pretend" not in myopts): + sys.exit(1) + + #buildsyspkg: I need mysysdict also on resume (moved from the else block) + mysysdict=genericdict(syslist) + if ("--resume" in myopts): + # We're resuming. + print green("*** Resuming merge...") + emergelog(" *** Resuming merge...") + mymergelist=portage.mtimedb["resume"]["mergelist"][:] + if ("--skipfirst" in myopts) and mymergelist: + del portage.mtimedb["resume"]["mergelist"][0] + del mymergelist[0] + else: + myfavs=portage.grabfile(portage.root+portage.WORLD_FILE) + myfavdict=genericdict(myfavs) + for x in range(len(mylist)): + if mylist[x][3]!="nomerge": + # Add to the mergelist + mymergelist.append(mylist[x]) + else: + myfavkey=portage.cpv_getkey(mylist[x][2]) + if "--onlydeps" in myopts: + continue + # Add to the world file. Since we won't be able to later. + if (not "--fetchonly" in myopts) and (myfavkey in favorites): + #don't record if already in system profile or already recorded + if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): + #we don't have a favorites entry for this package yet; add one + myfavdict[myfavkey]=myfavkey + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + if not "--fetchonly" in myopts: + portage.writedict(myfavdict,portage.root+portage.WORLD_FILE,writekey=0) + + portage.mtimedb["resume"]["mergelist"]=mymergelist[:] + + # We need to yank the harmful-to-new-builds settings from features. + myorigfeat=self.pkgsettings["FEATURES"] + myfeat=myorigfeat.split() + while ("keeptemp" in myfeat): + del myfeat[myfeat.index("keeptemp")] + while ("keepwork" in myfeat): + del myfeat[myfeat.index("keepwork")] + + self.pkgsettings["FEATURES"]=string.join(myfeat) + + mergecount=0 + if "--fetchonly" in myopts: + mynewmergelist = [] + for x in mymergelist: + if x[0] != "blocks": + mynewmergelist.append(x) + mymergelist = mynewmergelist + for x in mymergelist: + mergecount+=1 + myroot=x[1] + pkgindex=2 + if x[0]=="blocks": + pkgindex=3 + y=portage.portdb.findname(x[pkgindex]) + if not "--pretend" in myopts: + print ">>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+")",x[pkgindex],"to",x[1] + emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1]) + + self.pkgsettings["EMERGE_FROM"] = x[0][:] + self.pkgsettings.backup_changes("EMERGE_FROM") + + #buildsyspkg: Check if we need to _force_ binary package creation + issyspkg = ("buildsyspkg" in myfeat) \ + and x[0] != "blocks" \ + and mysysdict.has_key(portage.cpv_getkey(x[2])) \ + and not ("--buildpkg" in myopts) + if x[0] in ["ebuild","blocks"]: + if (x[0]=="blocks") and ("--fetchonly" not in myopts): + raise Exception, "Merging a blocker" + elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): + if x[0] == "blocks": + continue + if ("--fetch-all-uri" in myopts): + retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1) + else: + retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1) + if (retval == None) or retval: + print + print "!!! Fetch for",y,"failed, continuing..." + print + returnme=1 + continue + elif "--buildpkg" in myopts or issyspkg: + #buildsyspkg: Sounds useful to display something, but I don't know if we should also log it + if issyspkg: + print ">>> This is a system package, let's pack a rescue tarball." + #emergelog(">>> This is a system package, let's pack a rescue tarball.") + #create pkg, then merge pkg + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + #dynamically update our database + if "--buildpkgonly" not in myopts: + portage.db[portage.root]["bintree"].inject(x[2]) + mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + + self.pkgsettings["EMERGE_FROM"] = "binary" + self.pkgsettings.backup_changes("EMERGE_FROM") + + retval=portage.pkgmerge(mytbz2,myroot,self.pkgsettings) + if retval==None: + sys.exit(1) + else: + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + #dynamically update our database + elif x[0]=="binary": + #merge the tbz2 + mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) + if portage.db[portage.root]["bintree"].isremote(x[2]): + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch" + emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) + portage.db[portage.root]["bintree"].gettbz2(x[2]) + + if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): + continue + + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) + retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings) + if retval==None: + sys.exit(1) + #need to check for errors + if "--buildpkgonly" not in myopts: + portage.db[x[1]]["vartree"].inject(x[2]) + myfavkey=portage.cpv_getkey(x[2]) + if "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts and myfavkey in favorites: + myfavs=portage.grabfile(myroot+portage.WORLD_FILE) + myfavdict=genericdict(myfavs) + mysysdict=genericdict(syslist) + #don't record if already in system profile or already recorded + if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): + #we don't have a favorites entry for this package yet; add one + myfavdict[myfavkey]=myfavkey + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")") + portage.writedict(myfavdict,myroot+portage.WORLD_FILE,writekey=0) + + if ("noclean" not in portage.features) and (x[0] != "binary"): + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean Post" + emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) + retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1) + if (retval == None): + portage_util.writemsg("Unable to run required binary.\n") + sys.exit(127) + if retval: + sys.exit(retval) + + if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + # Clean the old package that we have merged over top of it. + if self.pkgsettings["AUTOCLEAN"]=="yes": + xsplit=portage.pkgsplit(x[2]) + emergelog(" >>> AUTOCLEAN: "+xsplit[0]) + retval=unmerge("clean", [xsplit[0]]) + if not retval: + emergelog(" --- AUTOCLEAN: Nothing unmerged.") + + # Figure out if we need a restart. + mysplit=portage.pkgsplit(x[2]) + if mysplit[0]=="sys-apps/portage": + myver=mysplit[1]+"-"+mysplit[2] + if myver[-3:]=='-r0': + myver=myver[:-3] + if (myver != portage.VERSION) and \ + ("livecvsportage" not in portage.settings.features): + if len(mymergelist) > mergecount: + myargv=sys.argv + myr=0 + for myra in range(len(myargv)): + if myargv[myr][0:len("portage")]=="portage": + del myargv[myr] + myr-=1 + if myargv[myr][0:len("sys-apps/portage")]=="sys-apps/portage": + del myargv[myr] + myr-=1 + myr+=1 + emergelog(" *** RESTARTING emerge via exec() after change of portage version.") + portage.portageexit() + # Remove --ask from options before restarting + mynewargv=[] + badlongopts = ["--ask","--tree","--changelog"] + badshortopts = ["a","t","l"] + for arg in myargv: + if arg[0:2] == "--": + if arg in badlongopts: + continue + mynewargv += [arg] + elif arg[0] == "-": + myarg = "-" + for ch in arg[1:]: + if ch in badshortopts: + continue + myarg += ch + mynewargv += [myarg] + else: + mynewargv += [arg] + os.execv("/usr/lib/portage/bin/emerge", mynewargv) + + if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1]) + + # Unsafe for parallel merges + del portage.mtimedb["resume"]["mergelist"][0] + + emergelog(" *** Finished. Cleaning up...") + + # We're out of the loop... We're done. Delete the resume data. + if portage.mtimedb.has_key("resume"): + del portage.mtimedb["resume"] + + if ("--pretend" not in myopts): + if ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): + if (mergecount>0): + if retval: + portage.env_update() + + #by doing an exit this way, --fetchonly can continue to try to + #fetch everything even if a particular download fails. + if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + if returnme: + print "\n\n!!! Some fetch errors were encountered. Please see above for details.\n\n" + sys.exit(returnme) + else: + sys.exit(0) + +def unmerge(unmerge_action, unmerge_files): + candidate_catpkgs=[] + global_unmerge=0 + + realsyslist = getlist("system") + syslist = [] + for x in realsyslist: + mycp = portage.dep_getkey(x) + if mycp in portage.settings.virtuals: + syslist.extend(portage.settings.virtuals[mycp]) + syslist.append(mycp) + + global myopts + mysettings = portage.config(clone=portage.settings) + + if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files: + if "unmerge"==unmerge_action: + print + print bold("emerge unmerge")+" can only be used with specific package names, not with "+bold("world")+" or" + print bold("system")+" targets." + print + return 0 + else: + global_unmerge=1 + + localtree=portage.db[portage.root]["vartree"] + # process all arguments and add all valid db entries to candidate_catpkgs + if global_unmerge: + if not unmerge_files or "world" in unmerge_files: + candidate_catpkgs.extend(localtree.getallnodes()) + elif "system" in unmerge_files: + candidate_catpkgs.extend(getlist("system")) + else: + #we've got command-line arguments + if not unmerge_files: + print "\nNo packages to unmerge have been provided.\n" + return 0 + for x in unmerge_files: + arg_parts=x.split('/') + if (x[0] not in [".","/"]) and (arg_parts[-1][-7:] != ".ebuild"): + #possible cat/pkg or dep; treat as such + candidate_catpkgs.append(x) + elif unmerge_action in ["prune","clean"]: + print "\n!!! Prune and clean do not accept individual ebuilds as arguments;\n skipping.\n" + continue + else: + # it appears that the user is specifying an installed ebuild and we're in "unmerge" mode, so it's + # ok. + if not os.path.exists(x): + print "\n!!! The path '"+x+"' doesn't exist.\n" + return 0 + + absx = os.path.abspath(x) + sp_absx = absx.split("/") + if sp_absx[-1][-7:] == ".ebuild": + del sp_absx[-1] + absx = string.join(sp_absx,"/") + + sp_absx_len = len(sp_absx) + + vdb_path = portage.root+portage.VDB_PATH + vdb_len = len(vdb_path) + + sp_vdb = vdb_path.split("/") + sp_vdb_len = len(sp_vdb) + + if not os.path.exists(absx+"/CONTENTS"): + print "!!! Not a valid db dir: "+str(absx) + return 0 + + if sp_absx_len <= sp_vdb_len: + # The Path is shorter... so it can't be inside the vdb. + print spabsx + print absx + print "\n!!!",x,"cannot be inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" + return 0 + + for idx in range(0,sp_vdb_len): + if (idx >= sp_absx_len) or (sp_vdb[idx] != sp_absx[idx]): + print sp_absx + print absx + print "\n!!!",x,"is not inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" + return 0 + + print "="+string.join(sp_absx[sp_vdb_len:],"/") + candidate_catpkgs.append("="+string.join(sp_absx[sp_vdb_len:],"/")) + + if ("--pretend" in myopts) or ("--ask" in myopts): + print darkgreen("\n>>> These are the packages that I would unmerge:") + + pkgmap={} + numselected=0 + for x in candidate_catpkgs: + #cycle through all our candidate deps and determine what will and will not get unmerged + try: + mymatch=localtree.dep_match(x) + except KeyError: + mymatch=None + except ValueError, errpkgs: + print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" + print "!!! one of the following fully-qualified ebuild names instead:\n" + for i in errpkgs[0]: + print " " + green(i) + print + sys.exit(1) + + if not mymatch and x[0] not in "<>=~": + #add a "=" if missing + mymatch=localtree.dep_match("="+x) + if not mymatch: + print "\n--- Couldn't find " + white(x) + " to "+unmerge_action+"." + continue + mykey=portage.key_expand(portage.dep_getkey(mymatch[0]),portage.db["/"]["vartree"].dbapi) + if not pkgmap.has_key(mykey): + pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } + if unmerge_action=="unmerge": + for y in mymatch: + if y not in pkgmap[mykey]["selected"]: + pkgmap[mykey]["selected"].append(y) + numselected=numselected+len(mymatch) + + else: + #unmerge_action in ["prune", clean"] + slotmap={} + for mypkg in mymatch: + if unmerge_action=="clean": + myslot=localtree.getslot(mypkg) + else: + #since we're pruning, we don't care about slots and put all the pkgs in together + myslot=0 + if not slotmap.has_key(myslot): + slotmap[myslot]={} + slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg + for myslot in slotmap.keys(): + counterkeys=slotmap[myslot].keys() + counterkeys.sort() + if not counterkeys: + continue + counterkeys.sort() + pkgmap[mykey]["protected"].append(slotmap[myslot][counterkeys[-1]]) + del counterkeys[-1] + #be pretty and get them in order of merge: + for ckey in counterkeys: + pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) + numselected=numselected+1 + #ok, now the last-merged package is protected, and the rest are selected + if global_unmerge and not numselected: + print "\n>>> No outdated packages were found on your system.\n" + return 0 + + if not numselected: + print "\n>>>",unmerge_action+": No packages selected for removal.\n" + return 0 + + for x in pkgmap.keys(): + for y in localtree.dep_match(x): + if y not in pkgmap[x]["omitted"] and \ + y not in pkgmap[x]["selected"] and \ + y not in pkgmap[x]["protected"]: + pkgmap[x]["omitted"].append(y) + if global_unmerge and not pkgmap[x]["selected"]: + #avoid cluttering the preview printout with stuff that isn't getting unmerged + continue + if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist): + print red("\a\n\n!!! '%s' is part of your system profile. '%s'" % (mykey)) + print yellow("\a!!! Unmerging it may be damaging to your system.\n") + if "--pretend" not in myopts and "--ask" not in myopts: + global EMERGE_WARNING_DELAY + countdown(EMERGE_WARNING_DELAY,red("Press Ctrl-C to Stop")) + print "\n "+white(x) + for mytype in ["selected","protected","omitted"]: + print string.rjust(mytype,12)+":", + if pkgmap[x][mytype]: + for mypkg in pkgmap[x][mytype]: + mysplit=portage.catpkgsplit(mypkg) + if mysplit[3]=="r0": + myversion=mysplit[2] + else: + myversion=mysplit[2]+"-"+mysplit[3] + if mytype=="selected": + print red(myversion), + else: + print green(myversion), + else: + print "none", + print + + print "\n>>>",red("'Selected'"),"packages are slated for removal." + print ">>>",green("'Protected'"),"and",green("'omitted'"),"packages will not be removed.\n" + + if "--pretend" in myopts: + #we're done... return + return 0 + if "--ask" in myopts: + if userquery("Do you want me to unmerge these packages?")=="No": + # enter pretend mode for correct formatting of results + myopts+=["--pretend"] + print + print "Quitting." + print + return 0 + #the real unmerging begins, after a short delay.... + + global CLEAN_DELAY + countdown(CLEAN_DELAY, ">>> Unmerging") + + for x in pkgmap.keys(): + for y in pkgmap[x]["selected"]: + print ">>> Unmerging "+y+"..." + emergelog("=== Unmerging... ("+y+")") + mysplit=string.split(y,"/") + #unmerge... + retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,mysettings,unmerge_action not in ["clean","prune"]) + if retval: + emergelog(" !!! unmerge FAILURE: "+y) + else: + emergelog(" >>> unmerge success: "+y) + #run ldconfig, etc... + portage.env_update() + if not numselected: + return 0 + else: + return 1 + + +def chk_updated_info_files(retval): + root=portage.root + + infodirs=[] + infodirs.extend(string.split(portage.settings["INFOPATH"], ":")) + infodirs.extend(string.split(portage.settings["INFODIR"], ":")) + + print + if os.path.exists("/usr/bin/install-info"): + regen_infodirs=[] + for z in infodirs: + if z=='': + continue + inforoot=normpath(root+z) + if os.path.isdir(inforoot): + try: + infomtime=os.stat(inforoot)[ST_MTIME] + except SystemExit, e: + raise # Needed else can't exit + except: + infomtime=0 + + if not portage.mtimedb.has_key("info"): + portage.mtimedb["info"]={} + if portage.mtimedb["info"].has_key(inforoot): + if portage.mtimedb["info"][inforoot]==infomtime: + pass + else: + portage.mtimedb["info"][inforoot]=infomtime + regen_infodirs.append(inforoot) + else: + regen_infodirs.append(inforoot) + + if not regen_infodirs: + print " "+green("*")+" GNU info directory index is up-to-date." + else: + print " "+green("*")+" Regenerating GNU info directory index..." + + icount=0 + badcount=0 + for inforoot in regen_infodirs: + if inforoot=='': + continue + try: + os.rename(inforoot+"/dir",inforoot+"/dir.old") + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + if not os.path.isdir(inforoot): + continue + errmsg = "" + for x in os.listdir(inforoot): + if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)): + continue + myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] + existsstr="already exists, for file `" + if myso!="": + if re.search(existsstr,myso): + # Already exists... Don't increment the count for this. + pass + elif myso[:44]=="install-info: warning: no info dir entry in ": + # This info file doesn't contain a DIR-header: install-info produces this + # (harmless) warning (the --quiet switch doesn't seem to work). + # Don't increment the count for this. + pass + else: + badcount=badcount+1 + errmsg += myso + "\n" + icount=icount+1 + + #update mtime so we can potentially avoid regenerating. + portage.mtimedb["info"][inforoot]=os.stat(inforoot)[ST_MTIME] + + if badcount: + print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors." + print errmsg + else: + print " "+green("*")+" Processed",icount,"info files." + + +def post_emerge(retval=0): + global myopts + os.chdir("/") + if "--pretend" in myopts: + sys.exit(retval) + + emergelog(" *** exiting successfully.") + + if "noinfo" not in portage.settings.features: + chk_updated_info_files(retval) + + chk_updated_cfg_files() + sys.exit(retval) + + +def chk_updated_cfg_files(): + if portage.settings["CONFIG_PROTECT"]: + #number of directories with some protect files in them + procount=0 + for x in string.split(portage.settings["CONFIG_PROTECT"]): + if os.path.isdir(x): + a=commands.getstatusoutput("cd "+x+"; find . -iname '._cfg????_*'") + if a[0]!=0: + print " "+red("*")+" error scanning",x + else: + files=string.split(a[1]) + if files: + procount=procount+1 + print " "+yellow("* IMPORTANT:")+"",len(files),"config files in",x,"need updating." + if procount: + #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." + print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." + print + +# general options that should be taken into account before any action +if "--debug" in myopts: + edebug=1 + +if myaction in ["sync","rsync","metadata"] and (not "--help" in myopts): + if "--pretend" in myopts: + print "emerge: \"sync\" actions do not support \"--pretend.\"" + sys.exit(1) + + emergelog(" === "+str(myaction)) + myportdir=portage.settings["PORTDIR"] + if myportdir[-1]=="/": + myportdir=myportdir[:-1] + if not os.path.exists(myportdir): + print ">>>",myportdir,"not found, creating it." + os.makedirs(myportdir,0755) + syncuri=string.rstrip(portage.settings["SYNC"]) + os.umask(0022) + if myaction == "metadata": + if "--ask" in myopts: + if userquery("Are you sure?") == "No": + sys.exit(1) + print "skipping sync" + updatecache_flg = True + tmpservertimestampfile = None + elif syncuri[:8]=="rsync://": + if not os.path.exists("/usr/bin/rsync"): + print "!!! /usr/bin/rsync does not exist, so rsync support is disabled." + print "!!! Type \"emerge net-misc/rsync\" to enable rsync support." + sys.exit(1) + mytimeout=180 + if portage.settings.has_key("RSYNC_TIMEOUT"): + try: + mytimeout=int(portage.settings["RSYNC_TIMEOUT"]) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + rsync_flags = [ + "--recursive", # Recurse directories + "--links", # Consider symlinks + "--safe-links", # Ignore links outside of tree + "--perms", # Preserve permissions + "--times", # Preserive mod times + "--compress", # Compress the data transmitted + "--force", # Force deletion on non-empty dirs + "--whole-file", # Don't do block transfers, only entire files + "--delete", # Delete files that aren't in the master tree + "--delete-after", # Delete only after everything else is done + "--stats", # Show final statistics about what was transfered + "--timeout="+str(mytimeout), # IO timeout if not done in X seconds + "--exclude='/distfiles'", # Exclude distfiles from consideration + "--exclude='/local'", # Exclude local from consideration + "--exclude='/packages'", # Exclude packages from consideration + ] + + if "--quiet" in myopts: + rsync_flags.append("--quiet") # Shut up a lot + else: + rsync_flags.append("--progress") # Progress meter for each file + + if "--verbose" in myopts: + rsync_flags.append("--verbose") # More noise? Not really sure what + + if "--debug" in myopts: + rsync_flags.append("--checksum") # Force checksum on all files + + if portage.settings.has_key("RSYNC_EXCLUDEFROM"): + if os.path.exists(portage.settings["RSYNC_EXCLUDEFROM"]): + rsync_flags.append("--exclude-from="+portage.settings["RSYNC_EXCLUDEFROM"]) + else: + print "!!! RSYNC_EXCLUDEFROM specified, but file does not exist." + + if portage.settings.has_key("RSYNC_RATELIMIT"): + rsync_flags.append("--bwlimit="+portage.settings["RSYNC_RATELIMIT"]) + + rsynccommand = "/usr/bin/rsync " + string.join(rsync_flags, " ") + + servertimestampdir = portage.settings.depcachedir+"/" + servertimestampfile = portage.settings.depcachedir+"/timestamp.chk" + tmpservertimestampdir = portage.settings["PORTAGE_TMPDIR"]+"/" + tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk" + + # We only use the backup if a timestamp exists in the portdir. + content=None + if os.path.exists(myportdir+"/metadata/timestamp.chk"): + content=portage.grabfile(servertimestampfile) + if (not content): + content=portage.grabfile(myportdir+"/metadata/timestamp.chk") + + if (content): + try: + mytimestamp=time.mktime(time.strptime(content[0], "%a, %d %b %Y %H:%M:%S +0000")) + except ValueError: + mytimestamp=0 + else: + mytimestamp=0 + + if not os.path.exists(servertimestampdir): + os.mkdir(servertimestampdir) + os.chown(servertimestampdir, os.getuid(), portage.portage_gid) + os.chmod(servertimestampdir, 02775) + + #exitcode=0 + try: + maxretries=int(portage.settings["RSYNC_RETRIES"]) + except SystemExit, e: + raise # Needed else can't exit + except: + maxretries=3 #default number of retries + + retries=0 + hostname, port=re.split("rsync://([^:/]*)(:[0-9]+)?", syncuri)[1:3]; + if port==None: + port="" + updatecache_flg=True + + ips=[] + while (1): + if ips: + del ips[0] + if ips==[]: + try: + ips=socket.gethostbyname_ex(hostname)[2] + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if ips: + try: + dosyncuri=string.replace(syncuri, "//"+hostname+port+"/", "//"+ips[0]+port+"/", 1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if (retries==0): + if "--ask" in myopts: + if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No": + print + print "Quitting." + print + sys.exit(0) + emergelog(">>> starting rsync with "+dosyncuri) + if "--quiet" not in myopts: + print ">>> starting rsync with "+dosyncuri+"..." + else: + emergelog(">>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)) + print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri) + + if "--quiet" not in myopts: + print ">>> checking server timestamp ..." + mycommand=rsynccommand+" "+dosyncuri+"/metadata/timestamp.chk "+tmpservertimestampdir + exitcode=portage.spawn(mycommand,portage.settings,free=1) + if (exitcode==0): + try: + servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000")) + except SystemExit, e: + raise # Needed else can't exit + except: + servertimestamp = 0 + + if (servertimestamp != 0) and (servertimestamp == mytimestamp): + emergelog(">>> Cancelling sync -- Already current.") + print + print ">>>" + print ">>> Timestamps on the server and in the local repository are the same." + print ">>> Cancelling all further sync action. You are already up to date." + print ">>>" + print + sys.exit(0) + elif (servertimestamp != 0) and (servertimestamp < mytimestamp): + emergelog(">>> Server out of date: %s" % dosyncuri) + print + print ">>>" + print ">>> SERVER OUT OF DATE: %s" % dosyncuri + print ">>>" + print + elif (servertimestamp == 0) or (servertimestamp > mytimestamp): + # actual sync + mycommand=rsynccommand+" "+dosyncuri+"/ "+myportdir + exitcode=portage.spawn(mycommand,portage.settings,free=1) + if exitcode in [0,1,2,3,4,11,14,20,21]: + break + elif exitcode in [0,1,2,3,4,11,14,20,21]: + break + + retries=retries+1 + + if retries<=maxretries: + print ">>> retry ..." + time.sleep(11) + else: + # over retries + # exit loop + updatecache_flg=False + break + + if (exitcode==0): + emergelog("=== Sync completed with %s" % dosyncuri) + elif (exitcode>0): + print + if exitcode==1: + print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure") + print darkred("!!!")+green(" that your SYNC statement is proper.") + print darkred("!!!")+green(" SYNC="+portage.settings["SYNC"]) + elif exitcode==11: + print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally") + print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption") + print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate") + print darkred("!!!")+green(" and try again after the problem has been fixed.") + print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"]) + elif exitcode==20: + print darkred("!!!")+green(" Rsync was killed before it finished.") + else: + print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep") + print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable") + print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a") + print darkred("!!!")+green(" temporary problem unless complications exist with your network") + print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.") + print + sys.exit(exitcode) + elif syncuri[:6]=="cvs://": + if not os.path.exists("/usr/bin/cvs"): + print "!!! /usr/bin/cvs does not exist, so rsync support is disabled." + print "!!! Type \"emerge dev-util/cvs\" to enable CVS support." + sys.exit(1) + cvsroot=syncuri[6:] + cvsdir=os.path.dirname(myportdir) + if not os.path.exists(myportdir+"/CVS"): + #initial checkout + print ">>> starting initial cvs checkout with "+syncuri+"..." + if not portage.spawn("cd "+cvsdir+"; cvs -d "+cvsroot+" login",portage.settings,free=1): + print "!!! cvs login error; exiting." + sys.exit(1) + if os.path.exists(cvsdir+"/gentoo-x86"): + print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." + sys.exit(1) + if not portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",portage.settings,free=1): + print "!!! cvs checkout error; exiting." + sys.exit(1) + if cvsdir!=myportdir: + portage.movefile(cvsdir,portage.settings["PORTDIR"]) + sys.exit(0) + else: + #cvs update + print ">>> starting cvs update with "+syncuri+"..." + sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",portage.settings,free=1)) + else: + print "!!! rsync setting: ",syncuri,"not recognized; exiting." + sys.exit(1) + + try: # Prevent users from affecting ebuild.sh. + os.close(sys.stdin.fileno()) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + + if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg: + if "--quiet" not in myopts: + print "\n>>> Updating Portage cache: ", + os.umask(0002) + cachedir = os.path.normpath(portage.settings.depcachedir) + if cachedir in ["/", "/bin", "/dev", "/etc", "/home", + "/lib", "/opt", "/proc", "/root", "/sbin", + "/sys", "/tmp", "/usr", "/var"]: + print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM." + print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir) + sys.exit(73) + if not os.path.exists(cachedir): + os.mkdir(cachedir) + + # Potentially bad + #if os.path.exists(cachedir+"/"+myportdir): + # portage.spawn("rm -Rf "+cachedir+"/"+myportdir+"/*",portage.settings,free=1) + + # save timestamp.chk for next timestamp check. + try: + if tmpservertimestampfile != None: + portage.movefile(tmpservertimestampfile, servertimestampfile) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "!!! Failed to save current timestamp." + print "!!!",e + + portage.portdb.flush_cache() + + try: + os.umask(002) + os.chown(cachedir, os.getuid(), portage.portage_gid) + os.chmod(cachedir, 02775) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + # we don't make overlay trees cache here. + backup_porttrees=portage.portdb.porttrees + porttree_root = portage.portdb.porttree_root + portage.portdb.porttrees=[porttree_root] + cp_list=portage.portdb.cp_all() + cp_list.sort() + pcnt=0 + pcntstr="" + pcntcount=len(cp_list)/100.0 + nextupdate=pcntcount + current=1 + def cleanse_cache(cat, saves, porttree_root=porttree_root): + if len(saves): + d={} + for v in saves: + d[portage.catsplit(v)[1]] = True + for pv in portage.db["/"]["porttree"].dbapi.auxdb[porttree_root][cat].keys(): + if pv not in d: + portage.db["/"]["porttree"].dbapi.auxdb[porttree_root][cat].del_key(pv) + else: + portage.db["/"]["porttree"].dbapi.auxdb[porttree_root][cat].clear() + del portage.db["/"]["porttree"].dbapi.auxdb[porttree_root][cat] + savelist = [] + catlist = [] + oldcat = portage.catsplit(cp_list[0])[0] + for cp in cp_list: + current += 1 + if current >= nextupdate: + pcnt += 1 + nextupdate += pcntcount + if "--quiet" not in myopts: + pcntstr = str(pcnt) + sys.stdout.write("\b"*(len(pcntstr)+1)+pcntstr+"%") + sys.stdout.flush() + cat = portage.catsplit(cp)[0] + if cat != oldcat: + catlist.append(oldcat) + cleanse_cache(oldcat, savelist) + savelist = [] + oldcat = cat + mymatches = portage.db["/"]["porttree"].dbapi.xmatch("match-all", cp) + savelist.extend(mymatches) + for cpv in mymatches: + try: portage.db["/"]["porttree"].dbapi.aux_get(cpv, ["IUSE"],metacachedir=myportdir+"/metadata/cache",debug=("cachedebug" in portage.features)) + except SystemExit: raise + except Exception, e: print "\nFailed cache update:",cpv,e + catlist.append(oldcat) + catlist.append("local") + cleanse_cache(oldcat, savelist) + filelist = portage.listdir(cachedir+"/"+myportdir) + for x in filelist: + found = False + for y in catlist: + if x.startswith(y): + found = True + break + if not found: + portage.spawn("cd /; rm -Rf "+cachedir+"/"+myportdir+"/"+x,portage.settings,free=1,droppriv=1) + + + portage.portdb.porttrees=backup_porttrees + sys.stdout.write("\n\n") + sys.stdout.flush() + + portage.portageexit() + reload(portage) + mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage") + mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage")) + + chk_updated_cfg_files() + + if(mybestpv != mypvs): + print + print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended" + print red(" * ")+"that you update portage now, before any other packages are updated." + print red(" * ")+"Please do so and then update "+bold("ALL")+" of your configuration files." + print +elif myaction=="regen": + emergelog(" === regen") + #regenerate cache entries + print "Regenerating cache entries... " + try: + os.close(sys.stdin.fileno()) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + sys.stdout.flush() + mynodes=portage.portdb.cp_all() + for x in mynodes: + mymatches=portage.portdb.xmatch("match-all",x) + if not "--quiet" in myopts: + print "processing",x + for y in mymatches: + try: + foo=portage.portdb.aux_get(y,["DEPEND"],debug=1) + except SystemExit, e: + # sys.exit is an exception... And consequently, we can't catch it. + raise + except Exception, e: + print "\n error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)} + print "done!" +# HELP action +elif "config"==myaction: + if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles: + print red("!!! config can only take a single package atom at this time\n") + sys.exit(1) + + print + pkgs = portage.db[portage.root]["vartree"].dbapi.match(myfiles[0]) + if len(pkgs) == 0: + print "No packages found.\n" + sys.exit(0) + elif len(pkgs) > 1: + if "--ask" in myopts: + options = [] + print "Please select a package to configure:" + idx = 0 + for pkg in pkgs: + idx += 1 + options.append(str(idx)) + print options[-1]+") "+pkg + print "X) Cancel" + options.append("X") + idx = userquery("Selection?", options) + if idx == "X": + sys.exit(0) + pkg = pkgs[int(idx)-1] + else: + print "The following packages available:" + for pkg in pkgs: + print "* "+pkg + print "\nPlease use a specific atom or the --ask option." + sys.exit(1) + else: + pkg = pkgs[0] + + print + if "--ask" in myopts: + if userquery("Ready to configure "+pkg+"?") == "No": + sys.exit(0) + else: + print "Configuring pkg..." + print + ebuildpath = portage.db[portage.root]["vartree"].dbapi.findname(pkg) + mysettings = portage.config(clone=portage.settings) + portage.doebuild(ebuildpath,"config",portage.root,mysettings,debug=("--debug" in myopts),cleanup=True) + print + +# INFO action +elif "info"==myaction: + unameout=commands.getstatusoutput("uname -mrp")[1] + print getportageversion() + print "=================================================================" + print "System uname: "+unameout + if os.path.exists("/etc/gentoo-release"): + os.system("cat /etc/gentoo-release") + else: + print "Unknown Host Operating System" + + output=commands.getstatusoutput("distcc --version") + if not output[0]: + print str(string.split(output[1],"\n",1)[0]), + if "distcc" in portage.features: + print "[enabled]" + else: + print "[disabled]" + + output=commands.getstatusoutput("ccache -V") + if not output[0]: + print str(string.split(output[1],"\n",1)[0]), + if "ccache" in portage.features: + print "[enabled]" + else: + print "[disabled]" + + myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers", + "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] + myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs") + myvars = portage_util.unique_array(myvars) + myvars.sort() + + for x in myvars: + if portage.isvalidatom(x): + pkg_matches = portage.db["/"]["vartree"].dbapi.match(x) + pkgs = [] + for y in pkg_matches: + mycpv = portage.catpkgsplit(y) + if(mycpv[3] != "r0"): + pkgs += [mycpv[2] + "-" + mycpv[3]] + else: + pkgs += [mycpv[2]] + if not pkgs: + pkgs = "[Not Present]" + else: + pkgs = ", ".join(sorted_versions(pkgs)) + print "%-20s %s" % (x+":", pkgs) + else: + print "%-20s %s" % (x+":", "[NOT VALID]") + + libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",") + + if "--verbose" in myopts: + myvars=portage.settings.keys() + else: + myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK', + 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR', + 'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS', + 'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES'] + + myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars")) + + myvars = portage_util.unique_array(myvars) + unset_vars = [] + myvars.sort() + for x in myvars: + if portage.settings.has_key(x): + print x+'="'+portage.settings[x]+'"' + else: + unset_vars.append(x) + if unset_vars: + print "Unset: "+", ".join(unset_vars) + print + + if "--debug" in myopts: + for x in dir(portage): + module = getattr(portage, x) + if "cvs_id_string" in dir(module): + print "%s: %s" % (str(x), str(module.cvs_id_string)) + +# SEARCH action +elif "search"==myaction: + if not myfiles: + print "emerge: no search terms provided." + else: + searchinstance = search() + for mysearch in myfiles: + try: + searchinstance.execute(mysearch) + except re.error, comment: + print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment ) + sys.exit(1) + searchinstance.output() +elif "inject"==myaction: + if not myfiles: + print "emerge: please specify at least one cat/pkg-ver to inject." + sys.exit(1) + if "--pretend" in myopts: + print "emerge: the \"inject\" action does not support \"--pretend.\"" + sys.exit(1) + for x in myfiles: + if x[0] in [">","<","=","!"]: + print "!!! '"+x+"' is an invalid specification." + print "!!! Must be 'category/package-version' with no other symbols." + print + continue + mycps=portage.catpkgsplit(x) + if (not mycps) or (mycps[0]=="null"): + print "!!!",x,"is not a specific cat/pkg-version, skipping..." + continue + if portage.db["/"]["vartree"].exists_specific(x): + print "!!! Not injecting",x+"; Package already exists." + else: + if "--ask" in myopts: + if userquery("Do you want to inject the package %s?" % x)=="No": + print + print "Quitting." + print + sys.exit(0) + portage.db["/"]["vartree"].dbapi.cpv_inject(x) + print ">>> Injected",x+"." + emergelog(" === inject: "+x) +elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction: + if 1==unmerge(myaction, myfiles): + post_emerge() + +elif "depclean"==myaction: + # Kill packages that aren't explicitly merged or are required as a + # dependency of another package. World file is explicit. + + print + print red("*** WARNING ***")+" : DEPCLEAN CAN SERIOUSLY IMPAIR YOUR SYSTEM. USE CAUTION." + print red("*** WARNING ***")+" : (Cancel: CONTROL-C) -- ALWAYS VERIFY ALL PACKAGES IN THE" + print red("*** WARNING ***")+" : CANDIDATE LIST FOR SANITY BEFORE ALLOWING DEPCLEAN TO" + print red("*** WARNING ***")+" : UNMERGE ANY PACKAGES." + print red("*** WARNING ***")+" :" + print red("*** WARNING ***")+" : USE FLAGS MAY HAVE AN EXTREME EFFECT ON THE OUTPUT." + print red("*** WARNING ***")+" : SOME LIBRARIES MAY BE USED BY PACKAGES BUT ARE NOT" + print red("*** WARNING ***")+" : CONSIDERED TO BE A DEPEND DUE TO USE FLAG SETTINGS." + print red("*** WARNING ***")+" : emerge --update --deep --newuse world TO VERIFY" + print red("*** WARNING ***")+" : SANITY IN THIS REGARD." + print red("*** WARNING ***")+" :" + print red("*** WARNING ***")+" : Packages in the list that are desired may be added" + print red("*** WARNING ***")+" : directly to the world file to cause them to be ignored" + print red("*** WARNING ***")+" : by depclean and maintained in the future. BREAKAGES DUE" + print red("*** WARNING ***")+" : TO UNMERGING AN ==IN-USE LIBRARY== MAY BE REPAIRED BY" + print red("*** WARNING ***")+" : MERGING *** THE PACKAGE THAT COMPLAINS *** ABOUT THE" + print red("*** WARNING ***")+" : MISSING LIBRARY." + print + if ("--pretend" not in myopts) and ("--ask" not in myopts): + countdown(EMERGE_WARNING_DELAY, ">>> Depclean") + emergelog(" >>> depclean") + + mydepgraph=depgraph(myaction,myopts) + syslist=getlist("system") + worldlist=getlist("world") + + print "Calculating",myaction,"dependencies ", + if not mydepgraph.xcreate("world"): + print "\n!!! Failed to create deptree." + sys.exit(1) + print "\b\b ... done!" + + if ("--usepkgonly" in myopts) and mydepgraph.missingbins: + sys.stderr.write(red("The following binaries are not available for merging...\n")) + for x in mydepgraph.missingbins: + sys.stderr.write(" "+str(x)+"\n") + sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") + sys.exit(1) + + alldeps=mydepgraph.digraph.allnodes() + myvarlist=portage.vardbapi(portage.root).cp_all() + + if not syslist: + print "!!! You have no system list. Cannot determine system from world." + if not worldlist: + print "!!! You have no world file. Cannot determine explicit merges." + if not myvarlist: + print "!!! You have no installed package tree (%s). This is a problem." % portage.VDB_PATH + if not alldeps: + print "!!! You have no dependencies. Impossible. Bug." + + if not (syslist and worldlist and myvarlist and alldeps): + print + sys.exit(1) + + reallist=[] + for x in alldeps: + myparts=portage.catpkgsplit(string.split(x)[2]) + if not myparts: + sys.stderr.write( + red("!!! There appears to be a problem with the following package:\n")+ + red("!!! "+str(string.split(x)[2])+"\n\n")+ + "!!! Please ensure that blocking/conflicting packages are not merged."+ + "!!! 'emerge -p "+str(string.split(x)[2])+"\n\n") + if ("--pretend" not in myopts) and ("--ask" not in myopts): + countdown(EMERGE_WARNING_DELAY, "*** Continuing") + continue + + catpack=myparts[0]+"/"+myparts[1] + if catpack not in reallist: + reallist.append(catpack) + + cleanlist=[] + for x in myvarlist: + if x not in reallist: + if x not in cleanlist: + cleanlist.append(x) + + for x in syslist+worldlist: + myparts = portage.catpkgsplit(x) + if myparts: + if myparts[0][0] in ('<','>','='): + myparts[0] = myparts[0][1:] + if myparts[0][0] in ('<','>','='): + myparts[0] = myparts[0][1:] + catpack=myparts[0]+"/"+myparts[1] + else: + catpack=x + if catpack in cleanlist: + cleanlist.remove(catpack) + + #print "\n\n\nCleaning: " + #for x in cleanlist: + # print x + #print + + if len(cleanlist): + unmerge("unmerge", cleanlist) + + print + print "Packages installed: "+str(len(myvarlist)) + print "Packages in world: "+str(len(worldlist)) + print "Packages in system: "+str(len(syslist)) + print "Unique package names: "+str(len(reallist)) + print "Required packages: "+str(len(alldeps)) + if "--pretend" in myopts: + print "Number to remove: "+str(len(cleanlist)) + else: + print "Number removed: "+str(len(cleanlist)) + post_emerge() + +# "update", "system", or just process files: +else: + favorites=[] + syslist=getlist("system") + if (("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts)) or ("--ask" in myopts): + if "--tree" in myopts: + print + print darkgreen("These are the packages that I would merge, in reverse order:") + print + else: + print + print darkgreen("These are the packages that I would merge, in order:") + print + + if ("--resume" in myopts) and portage.mtimedb.has_key("resume"): + myresumeopts=portage.mtimedb["resume"]["myopts"][:] + + while "--skipfirst" in myresumeopts: + myresumeopts.remove("--skipfirst") + while "--ask" in myresumeopts: + myresumeopts.remove("--ask") + + for myopt in myopts: + if myopt not in myresumeopts: + myresumeopts.append(myopt) + myopts=myresumeopts + mydepgraph=depgraph("resume",myopts) + if "--resume" not in myopts: + myopts+=["--resume"] + else: + if ("--resume" in myopts): + del myopts[myopts.index("--resume")] + print darkgreen("emerge: It seems we have nothing to resume...") + sys.exit(0) + + mydepgraph=depgraph(myaction,myopts) + if myaction in ["system","world"]: + print "Calculating",myaction,"dependencies ", + sys.stdout.flush() + if not mydepgraph.xcreate(myaction): + print "!!! Depgraph creation failed." + sys.exit(1) + print "\b\b ...done!" + else: + if not myfiles: + print "emerge: please tell me what to do." + help() + sys.exit(1) + #we don't have any files to process; skip this step and exit + print "Calculating dependencies ", + sys.stdout.flush() + retval,favorites=mydepgraph.select_files(myfiles) + if not retval: + sys.exit(1) + print "\b\b ...done!" + + if ("--usepkgonly" in myopts) and mydepgraph.missingbins: + sys.stderr.write(red("The following binaries are not available for merging...\n")) + + if mydepgraph.missingbins: + for x in mydepgraph.missingbins: + sys.stderr.write(" "+str(x)+"\n") + sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") + sys.exit(1) + + if "--ask" in myopts: + if "--resume" in myopts: + mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) + prompt="Do you want me to resume merging these packages?" + else: + mydepgraph.display(mydepgraph.altlist()) + mergecount=0 + hasblocks = False + for x in mydepgraph.altlist(): + if x[3]!="nomerge": + mergecount+=1 + #check for blocking dependencies + if x[0]=="blocks": + hasblocks = True + if mergecount==0: + if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: + prompt="Nothing to merge; do you want me to auto-clean packages?" + else: + print + print "Nothing to merge; quitting." + print + sys.exit(0) + elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + prompt="Do you want me to fetch the source files for these packages?" + elif hasblocks: + print "\n!!! Error: The above package list contains packages which cannot be installed" + print "!!! on the same system." + print + sys.exit(1) + else: + prompt="Do you want me to merge these packages?" + print + if userquery(prompt)=="No": + print + print "Quitting." + print + sys.exit(0) + # Don't ask again (e.g. when auto-cleaning packages after merge) + myopts.remove("--ask") + + if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + if ("--resume" in myopts): + mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) + else: + mydepgraph.display(mydepgraph.altlist()) + else: + if ("--buildpkgonly" in myopts): + if not mydepgraph.digraph.hasallzeros(): + print "\n!!! --buildpkgonly requires all dependencies to be merged." + print "!!! Cannot merge requested packages. Merge deps and try again.\n" + sys.exit(1) + + if ("--resume" in myopts): + favorites=portage.mtimedb["resume"]["favorites"] + mydepgraph.merge(portage.mtimedb["resume"]["mergelist"]) + else: + portage.mtimedb["resume"]={} + portage.mtimedb["resume"]["myopts"]=myopts + portage.mtimedb["resume"]["favorites"]=favorites + if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + for pkgline in mydepgraph.altlist(): + if pkgline[0]=="ebuild" and pkgline[3]=="merge": + y=portage.portdb.findname(pkgline[2]) + tmpsettings = portage.config(clone=portage.settings) + retval=portage.doebuild(y,"digest",portage.root,tmpsettings,edebug,("--pretend" in myopts)) + mydepgraph.merge(mydepgraph.altlist()) + + if portage.mtimedb.has_key("resume"): + del portage.mtimedb["resume"] + if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: + print ">>> Auto-cleaning packages ..." + unmerge("clean", ["world"]) + post_emerge() diff --git a/bin/env-update b/bin/env-update new file mode 100755 index 000000000..a60428767 --- /dev/null +++ b/bin/env-update @@ -0,0 +1,11 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/env-update,v 1.9 2004/10/04 13:56:50 vapier Exp $ + +import os,sys +os.environ["PORTAGE_CALLER"] = "env-update" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage +portage.env_update() diff --git a/bin/env-update.sh b/bin/env-update.sh new file mode 100755 index 000000000..5edc2da6b --- /dev/null +++ b/bin/env-update.sh @@ -0,0 +1,221 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/env-update.sh,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +############################################ +############################################ +# ENVIRONMENT SETUP +############################################ + +if [[ ${EUID} -ne 0 ]] ; then + echo "$0: must be root." + exit 1 +fi + +# Make sure our environment is sane +if [[ ! -z "${MAKELINKS}" ]] ; then + export MAKELINKS=0 +else + export MAKELINKS=1 +fi +export ROOT="${ROOT:=/}" +[[ ${ROOT} == */ ]] || export ROOT="${ROOT}/" + +export ENVDIR="${ROOT}etc/env.d" +mkdir -p ${ENVDIR} +chmod 755 ${ENVDIR} +specials=" + KDEDIRS PATH CLASSPATH LDPATH MANPATH INFODIR INFOPATH ROOTPATH + CONFIG_PROTECT CONFIG_PROTECT_MASK PRELINK_PATH PYTHONPATH + PRELINK_PATH_MASK ADA_INCLUDE_PATH ADA_OBJECTS_PATH" +colon_separated=" + ADA_INCLUDE_PATH ADA_OBJECTS_PATH LDPATH PATH MANPATH ROOTPATH + PRELINK_PATH PRELINK_PATH_MASK PYTHON_PATH" + +export LDSOCONF="${ROOT}etc/ld.so.conf" + +export PRELINKCONF="${ROOT}etc/prelink.conf" +defaultprelinkpaths=":/bin:/sbin:/usr/bin:/usr/sbin:/lib:/usr/lib" + +export PROFILEENV="${ROOT}etc/profile.env" +export CSHENV="${ROOT}etc/csh.env" + +# make sure we aren't tricked with previous 'my_envd_' variables +unset $(set | grep '^my_envd_' | cut -d= -f1) + +############################################ +############################################ +# ENV.D PARSING +############################################ + +do_has() { + local x + local me="$1" + shift + + for x in "$@" ; do + [[ ${x} == ${me} ]] && return 0 + done + return 1 +} +has() { + local ret + local ifs="${IFS}" + unset IFS + do_has $1 ${!2} + ret=$? + export IFS="${ifs}" + return ${ret} +} +is_special() { + has $1 specials +} +is_colon_separated() { + has $1 colon_separated +} + +for envd in $(ls ${ENVDIR} | sort) ; do + # make sure file is a vaild env'd entry and not a backup file + num="${envd:0:2}" + if [[ ! -z ${num//[0-9]} ]] ; then + continue + elif [[ ${envd} == *~ || ${envd} == *.bak ]] ; then + continue + fi + + # use bash to make sure the file is valid + envd="${ENVDIR}/${envd}" + if ! (source "${envd}") ; then + echo "!!! Error parsing ${envd}!" + exit 1 + fi + + # parse env.d entries + cnfvars="$(grep '^[[:alpha:]_][[:alnum:]_]*=' "${envd}")" + export IFS=$'\n' + for cnfv in ${cnfvars} ; do + var="${cnfv/=*}" + val="${cnfv:${#var}+1}" + if [ "${val:0:1}" == "\"" ] ; then + val="${val:1:${#val}-2}" + fi + myvar="my_envd_${var}" + if is_special ${var} ; then + if [[ ! -z "${!myvar}" ]] ; then + if is_colon_separated ${var} ; then + sep=":" + else + sep=" " + fi + else + sep="" + fi + export ${myvar}="${!myvar}${sep}${val}" + else + export ${myvar}="${val}" + fi + done + unset IFS +done + +############################################ +############################################ +# LD.SO.CONF HANDLING +############################################ + +# create a : sep list from ld.so.conf +export OLD_LDPATH="" +if [ -s "${LDSOCONF}" ] ; then + while read line ; do + if [[ "${line:0:1}" == "#" ]] ; then + continue + fi + export OLD_LDPATH="${OLD_LDPATH}:${line}" + done < ${LDSOCONF} + export OLD_LDPATH="${OLD_LDPATH:1}" +fi + +# has the ldpath changed ? if so, recreate +if [[ "${OLD_LDPATH}" != "${my_envd_LDPATH}" ]] ; then + cat << EOF > ${LDSOCONF} +# ld.so.conf autogenerated by env-update; make all changes to +# contents of /etc/env.d directory +${my_envd_LDPATH//:/ +} +EOF +fi + +############################################ +############################################ +# HANDLE PRELINK PATHS +############################################ + +if prelink --version >& /dev/null ; then + # we assume LDPATH and PATH aren't empty ... if they were, we got other problems + envdprelinkcheckpaths="${my_envd_LDPATH}:${my_envd_PATH}" + if [[ ! -z "${my_envd_PRELINK_PATH}" ]] ; then + envdprelinkcheckpaths="${envdprelinkcheckpaths}:${my_envd_PRELINK_PATH}" + fi + + if [[ ! -z "${my_envd_PRELINK_PATH_MASK}" ]] ; then + export prelink_mask=":${PRELINK_PATH_MASK}:" + envdprelinkpaths="" + export IFS=":" + for dir in ${envdprelinkcheckpaths} ; do + if [[ ${dir:0-1} == / ]] ; then + noslashdir="${dir:0:${#dir}-1}" + else + dir="${dir}/" + noslashdir="${dir}" + fi + if [[ ${prelink_mask/:${dir}:/} == ${prelink_mask} \ + && ${prelink_mask/:${noslashdir}:/} == ${prelink_mask} ]] ; then + envdprelinkpaths="${envdprelinkpaths}:${dir}" + fi + done + unset IFS + else + envdprelinkpaths=":${envdprelinkcheckpaths}" + fi + + cat << EOF > ${PRELINKCONF} +# prelink.conf autogenerated by env-update; make all changes to +# contents of /etc/env.d directory +${defaultprelinkpaths//:/ +-l } +${envdprelinkpaths//:/ +-h } +EOF +fi +unset my_envd_LDPATH + +############################################ +############################################ +# RUN EXTERNAL PROGRAMS NOW +############################################ + +echo ">>> Regenerating ${ROOT}etc/ld.so.cache..." +if [[ ${MAKELINKS} -eq 0 ]] ; then + (cd / ; /sbin/ldconfig -X -r ${ROOT} >& /dev/null) +else + (cd / ; /sbin/ldconfig -r ${ROOT} >& /dev/null) +fi + +cat << EOF > ${PROFILEENV} +# THIS FILE IS AUTOMATICALLY GENERATED BY env-update. +# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES +# GO INTO /etc/profile NOT /etc/profile.env + +$(set | grep '^my_envd_' | sed -e 's:^my_envd_:export :') +EOF + +cat << EOF > ${CSHENV} +# THIS FILE IS AUTOMATICALLY GENERATED BY env-update. +# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES +# GO INTO /etc/csh.cshrc NOT /etc/csh.env + +$(set | grep '^my_envd_' | sed -e 's:^my_envd_\([[:alpha:]_][[:alnum:]_]*\)=:setenv \1 :') +EOF + +[[ ${ROOT} == / ]] && /sbin/depscan.sh diff --git a/bin/etc-update b/bin/etc-update new file mode 100755 index 000000000..e8ea9376b --- /dev/null +++ b/bin/etc-update @@ -0,0 +1,407 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/etc-update,v 1.23.2.5 2005/05/29 12:40:08 jstubbs Exp $ + +# Author Brandon Low <lostlogic@gentoo.org> +# +# Previous version (from which I've borrowed a few bits) by: +# Jochem Kossen <j.kossen@home.nl> +# Leo Lipelis <aeoo@gentoo.org> +# Karl Trygve Kalleberg <karltk@gentoo.org> + +export PORTAGE_CALLER="etc-update" + +eval $(python -c 'import portage; print "export PORTAGE_TMPDIR="+portage.settings["PORTAGE_TMPDIR"]; print "export USERLAND="+portage.settings["USERLAND"]') + +if [ "$USERLAND" == "BSD" ] ; then + function sed() { gsed "$@"; } +elif [ "$USERLAND" == "Darwin" ] && [ -x /bin/gsed ]; then + function sed() { gsed "$@"; } +fi + +function get_config() { + item=$1 + + # First strip off comment lines, then grab the configuration + # item. If there's more than one of the same configuration item, + # then allow the last setting to take precedence. + cut -d'#' -f1-1 /etc/etc-update.conf | \ + sed -ne "s/^ *$item *= *\([\"']\{0,1\}\)\(.*\)\1/\2/p" |sed -e '$p;d' +} + +function scan() { + + echo "Scanning Configuration files..." + rm -rf ${TMP}/files > /dev/null 2>&1 + mkdir ${TMP}/files || die "Failed mkdir command!" 1 + count=0 + input=0 + + for path in ${CONFIG_PROTECT}; do if [ -d ${path} ]; then + ofile="" + for file in `find ${path}/ -iname "._cfg????_*" | + sed -e "s:\(^.*/\)\(\._cfg[0-9]*_\)\(.*$\):\1\2\3\%\2\%\3:" | + sort -t'%' -k3 -k2 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'`; do + rpath=`echo "${file/\/\///}" | sed -e "s:/[^/]*$::"` + rfile=`echo "${file/\/\///}" | sed -e "s:^.*/::"` + for mpath in ${CONFIG_PROTECT_MASK}; do + if [[ "${rpath}" == "${mpath}"* ]]; then + mv ${rpath}/${rfile} ${rpath}/${rfile:10} + break + fi + done + [ ! -f ${file} ] && continue + + + if [[ "${ofile:10}" != "${rfile:10}" ]] || + [[ ${opath} != ${rpath} ]]; then + MATCHES=0 + if [[ "${EU_AUTOMERGE}" == "yes" ]]; then + if [ ! -e "${rpath}/${rfile}" ] || [ ! -e "${rpath}/${rfile:10}" ]; then + MATCHES=0 + else + diff -Bbua ${rpath}/${rfile} ${rpath}/${rfile:10} | egrep '^[+-]' | egrep -v '^[+-][\t ]*#|^--- |^\+\+\+ ' | egrep -qv '^[-+][\t ]*$' + MATCHES=$? + fi + elif [[ -z `diff -Nua ${rpath}/${rfile} ${rpath}/${rfile:10}| + grep "^[+-][^+-]"|grep -v '# .Header:.*'` ]]; then + MATCHES=1 + fi + if [[ "${MATCHES}" == "1" ]]; then + echo "Automerging trivial changes in: ${rfile:10}" + mv ${rpath}/${rfile} ${rpath}/${rfile:10} + continue + else + count=${count}+1 + echo "${rpath}/${rfile:10}" > ${TMP}/files/${count} + echo "${rpath}/${rfile}" >> ${TMP}/files/${count} + ofile="${rfile}" + opath="${rpath}" + continue + fi + fi + + if [[ -z `diff -Nua ${rpath}/${rfile} ${rpath}/${ofile}| + grep "^[+-][^+-]"|grep -v '# .Header:.*'` ]]; then + mv ${rpath}/${rfile} ${rpath}/${ofile} + continue + else + echo "${rpath}/${rfile}" >> ${TMP}/files/${count} + ofile="${rfile}" + opath="${rpath}" + fi + done + fi; done + +} + +function sel_file() { + local -i isfirst=0 + until [ -f ${TMP}/files/${input} ] || [ ${input} == -1 ] || [ ${input} == -3 ]; do + for file in `ls ${TMP}/files|sort -n`; do + if (( ${isfirst} == 0 )); then + isfirst=${file} + fi + echo -n "${file}${PAR} " + if (( ${mode} == 0 )); then + for word in `cat ${TMP}/files/${file}`; do + echo ${word} + done + else + head -n1 ${TMP}/files/${file} + fi + done > ${TMP}/menuitems + + if [ "${OVERWRITE_ALL}" == "yes" ]; then + input=0 + else + if (( ${mode} == 0 )); then + echo "The following is the list of files which need updating, each +configuration file is followed by a list of possible replacement files." + else + local my_title="Please select a file to update" + fi + + if (( ${mode} == 0 )); then + cat ${TMP}/menuitems + echo "Please select a file to edit by entering the corresponding number." + echo " (don't use -3 or -5 if you're unsure what to do)" + echo " (-1 to exit) (-3 to auto merge all remaining files)" + echo -n " (-5 to auto-merge AND not use 'mv -i'): " + read input + else + dialog --title "${title}" --menu "${my_title}" \ + 0 0 0 `echo "-1 Exit";cat ${TMP}/menuitems` \ + 2> ${TMP}/input + input=`cat ${TMP}/input` + fi + if (( ${input} == -5 )); then + input=-3 + export mv_opts="" + fi + if (( ${input} == -3 )); then + input=0 + export OVERWRITE_ALL="yes" + fi + fi # -3 automerge + if (( ${input} == 0 )); then + input=${isfirst} + fi + done +} + +function do_file() { + echo + local -i my_input + local -i fcount=0 + until (( `cat ${TMP}/files/${input}|wc -l` < 2 )); do + my_input=0 + if (( `cat ${TMP}/files/${input}|wc -l` == 2 )); then + my_input=1 + fi + until (( ${my_input} > 0 )) && (( ${my_input} < `cat ${TMP}/files/${input}|wc -l` )); do + fcount=0 + + if [ "${OVERWRITE_ALL}" == "yes" ]; then + my_input=0 + else + for line in `cat ${TMP}/files/${input}`; do + if (( ${fcount} > 0 )); then + echo -n "${fcount}${PAR} " + echo "${line}" + else + if (( ${mode} == 0 )); then + echo "Below are the new config files for ${line}:" + else + local my_title="Please select a file to process for ${line}" + fi + fi + fcount=${fcount}+1 + done > ${TMP}/menuitems + + if (( ${mode} == 0 )); then + cat ${TMP}/menuitems + echo -n "Please select a file to process (-1 to exit this file): " + read my_input + else + dialog --title "${title}" --menu "${my_title}" \ + 0 0 0 `cat ${TMP}/menuitems;echo "${fcount} Exit"` \ + 2> ${TMP}/input + my_input=`cat ${TMP}/input` + fi + fi # OVERWRITE_ALL + + if (( ${my_input} == 0 )); then + my_input=1 + elif (( ${my_input} == -1 )); then + input=0 + return + elif (( ${my_input} == ${fcount} )); then + break + fi + done + if (( ${my_input} == ${fcount} )); then + break + fi + + fcount=${my_input}+1 + + file=`cat ${TMP}/files/${input} | sed -e "${fcount}p;d"` + ofile=`head -n1 ${TMP}/files/${input}` + + do_cfg "${file}" "${ofile}" + + cat ${TMP}/files/${input}|sed -e "${fcount}!p;d" > ${TMP}/files/sed + mv ${TMP}/files/sed ${TMP}/files/${input} + + if (( ${my_input} == -1 )); then + break + fi + done + echo + rm ${TMP}/files/${input} + count=${count}-1 +} + +function do_cfg() { + + local file="${1}" + local ofile="${2}" + local -i my_input=0 + + until (( ${my_input} == -1 )) || [ ! -f ${file} ]; do + if [ "${OVERWRITE_ALL}" == "yes" ]; then + my_input=1 + else + showdiffcmd=$(echo "${diff_command}" | + sed -e "s:%file1:${ofile}:" -e "s:%file2:${file}:") + + if [ "${using_editor}" == 0 ]; then + ( + echo "Showing differences between ${ofile} and ${file}" + ${showdiffcmd} + ) | ${pager} + else + echo "Beginning of differences between ${ofile} and ${file}" + ${showdiffcmd} + echo "End of differences between ${ofile} and ${file}" + fi + if [ -L "${file}" ]; then + echo + echo "-------------------------------------------------------------" + echo "NOTE: File is a symlink to another file. REPLACE recommended." + echo " The original file may simply have moved. Please review." + echo "-------------------------------------------------------------" + echo + fi + echo -n "1) Replace original with update +2) Delete update, keeping original as is +3) Interactively merge original with update +4) Show differences again +Please select from the menu above (-1 to ignore this update): " + read my_input + fi + + case ${my_input} in + 1) echo "Replacing ${ofile} with ${file}" + mv ${mv_opts} ${file} ${ofile} + my_input=-1 + continue + ;; + 2) echo "Deleting ${file}" + rm ${rm_opts} ${file} + continue + ;; + 3) do_merge "${file}" "${ofile}" + my_input=${?} +# [ ${my_input} == 255 ] && my_input=-1 + continue + ;; + 4) continue + ;; + *) continue + ;; + esac + done +} + +function do_merge() { + + local file="${1}" + local ofile="${2}" + local mfile="${2}.merged" + local -i my_input=0 + echo "${file} ${ofile} ${mfile}" + + if [ -e ${mfile} ] ; then + echo "A previous version of the merged file exists, cleaning..." + rm ${rm_opts} ${mfile} + fi + + until (( ${my_input} == -1 )); do + echo "Merging ${file} and ${ofile}" + `echo "${merge_command}" | + sed -e "s:%merged:${mfile}:g" \ + -e "s:%orig:${ofile}:g" \ + -e "s:%new:${file}:g"` + until (( ${my_input} == -1 )); do + echo -n "1) Replace ${ofile} with merged file +2) Show differences between merged file and original +3) Remerge original with update +4) Edit merged file +5) Return to the previous menu +Please select from the menu above (-1 to exit, losing this merge): " + read my_input + case ${my_input} in + 1) echo "Replacing ${ofile} with ${mfile}" + chmod --reference=${ofile} ${mfile} + mv ${mv_opts} ${mfile} ${ofile} + rm ${rm_opts} ${file} + return 255 + ;; + 2) ( echo "Showing differences between ${ofile} and ${mfile}" + `echo "${diff_command}" | \ + sed -e "s:%file1:${ofile}:" \ + -e "s:%file2:${mfile}:"` ) | ${pager} + continue + ;; + 3) break + ;; + 4) ${EDITOR:-nano -w} "${mfile}" + continue + ;; + 5) rm ${rm_opts} ${mfile} + return 0 + ;; + *) continue + ;; + esac + done + done + rm ${rm_opts} ${mfile} + return 255 +} + +function die() { + trap "" term + trap "" kill + echo "Exiting: ${1}" + rm -rf ${TMP} + exit ${2} +} + +# +# Run the script +# +scriptname=`basename $0` + +trap die term + +TMP="${PORTAGE_TMPDIR}/$$" +rm -rf ${TMP} 2> /dev/null +mkdir ${TMP} || die "failed mkdir command!" 1 + +# I need the CONFIG_PROTECT value +CONFIG_PROTECT=$(/usr/lib/portage/bin/portageq config_protect) +CONFIG_PROTECT_MASK=$(/usr/lib/portage/bin/portageq config_protect_mask) + +# load etc-config's configuration +EU_AUTOMERGE=`get_config eu_automerge` +rm_opts=`get_config rm_opts` +mv_opts=`get_config mv_opts` +cp_opts=`get_config cp_opts` +pager=`get_config pager` +diff_command=`get_config diff_command` +using_editor=`get_config using_editor` +merge_command=`get_config merge_command` +declare -i mode=`get_config mode` +[ -z ${mode} ] && mode=0 +[ -z "${pager}" ] && pager="cat" + +#echo "rm_opts: $rm_opts, mv_opts: $mv_opts, cp_opts: $cp_opts" +#echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command" + +if (( ${mode} == 0 )); then + PAR=")" +else + PAR="" +fi + +declare -i count=0 +declare -i input=0 +declare title="Gentoolkit's etc-update tool!" + +scan + +until (( ${input} == -1 )); do + if (( ${count} == 0 )); then + die "Nothing left to do; exiting. :)" 0 + fi + sel_file + if (( ${input} != -1 )); then + do_file + fi +done + +die "User termination!" 0 diff --git a/bin/find-requires b/bin/find-requires new file mode 100755 index 000000000..44bc51dae --- /dev/null +++ b/bin/find-requires @@ -0,0 +1,44 @@ +#!/bin/sh +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/find-requires,v 1.5 2004/10/04 13:56:50 vapier Exp $ + +# note this works for both a.out and ELF executables +# it also auto-generates requirment lines for shell scripts + +ulimit -c 0 + +filelist=`sed "s/['\"]/\\\&/g"` +exelist=`echo $filelist | $XARGS file | grep ":.*executable" | cut -d: -f1 ` +scriptlist=`echo $filelist | $XARGS file | egrep ":.* (commands|script) " | cut -d: -f1 ` +liblist=`echo $filelist | $XARGS file | grep ":.*shared object" | cut -d : -f1 ` + +for f in $exelist; do + if [ -x $f ]; then + ldd $f | awk '/=>/ { print $1 }' + fi +done | sort -u | sed "s/['\"]/\\\&/g" | $XARGS -n 1 basename | grep -v 'libNoVersion.so' | sort -u + +for f in $liblist; do + ldd $f | awk '/=>/ { print $1 }' +done | sort -u | sed "s/['\"]/\\\&/g" | $XARGS -n 1 basename | grep -v 'libNoVersion.so' | sort -u + +for f in $scriptlist; do + if [ -x $f ]; then + head -1 $f | sed -e 's/^\#\![ ]*//' | cut -d" " -f1 + fi +done | sort -u + +#for f in $liblist $exelist ; do +# objdump -p $f | awk ' +# BEGIN { START=0; LIBNAME=""; } +# /Version References:/ { START=1; } +# /required from/ && (START==1) { +# sub(/:/, "", $3); +# LIBNAME=$3; +# } +# (START==1) && (LIBNAME!="") && ($4~/^GLIBC_*/) { print LIBNAME "(" $4 ")"; } +# /^$/ { START=0; } +# ' +#done | sort -u + diff --git a/bin/fix-db.py b/bin/fix-db.py new file mode 100755 index 000000000..d185580fa --- /dev/null +++ b/bin/fix-db.py @@ -0,0 +1,175 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/fix-db.py,v 1.8 2004/10/11 04:01:00 jstubbs Exp $ + +import os,sys,re +sys.path = ["/usr/lib/portage/pym"]+sys.path + +from stat import * +from output import * +from portage import lockfile,unlockfile,VDB_PATH,root + + +mylog = open("/var/log/emerge_fix-db.log", "a") +def writemsg(msg): + if msg[-1] != '\n': + msg += "\n" + sys.stderr.write(msg) + sys.stderr.flush() + mylog.write(msg) + mylog.flush() + +def fix_global_counter(value): + myf = open("/var/cache/edb/counter") + newvalue = value+1000 + myf.write(str(newvalue)) + myf.flush() + myf.close() + return newvalue + +bad = {} +counters = {} +times = {} + +try: + real_counter = long(open("/var/cache/edb/counter").read()) +except SystemExit, e: + raise # This needs to be propogated +except: + writemsg("ERROR: Real counter is invalid.\n") + real_counter = 0 + +vardbdir = root+VDB_PATH+"/" +for cat in os.listdir(vardbdir): + catdir = vardbdir+cat+"/" + if not os.path.isdir(catdir): + writemsg("Invalid file: '%s'\n" % catdir[:-1]) + continue + for pkg in os.listdir(catdir): + pkgdir = catdir+pkg+"/" + catpkg = cat+"/"+pkg + + if not os.path.isdir(catdir): + writemsg("Invalid file: '%s'\n" % pkgdir) + continue + + bad[catpkg] = [] + + pkgdirlist = os.listdir(pkgdir) + if not pkgdirlist: + writemsg("ERROR: Package directory is empty for '%s'\n" % catpkg) + writemsg(" Deleting this directory. Remerge if you want it back.\n") + os.rmdir(pkgdir) + del bad[catpkg] + continue + + if "CONTENTS" not in pkgdirlist: + bad[catpkg] += ["CONTENTS is missing"] + times[catpkg] = -1 + writemsg("ERROR: Contents file is missing from the package directory.\n") + writemsg(" '%s' is corrupt and should be deleted.\n" % catpkg) + else: + times[catpkg] = None + for line in open(pkgdir+"CONTENTS").readlines(): + mysplit = line.split() + if mysplit[0] == "obj": + try: + times[catpkg] = long(mysplit[-1]) + except SystemExit, e: + raise # This needs to be propogated + except: + times[catpkg] = -1 + bad[catpkg] += ["CONTENTS is corrupt"] + writemsg("ERROR: Corrupt CONTENTS file in '%s'\n" % catpkg) + writemsg(" This package should be deleted.\n") + break + if times[catpkg] == None: + times[catpkg] = os.stat(pkgdir+"CONTENTS")[ST_MTIME] + + if "COUNTER" not in pkgdirlist: + bad[catpkg] += ["COUNTER is missing"] + writemsg("ERROR: COUNTER file missing from '%s'.\n" % catpkg) + counters[catpkg] = -1 + else: + try: + counters[catpkg] = long(open(pkgdir+"COUNTER").read().strip()) + if counters[catpkg] > real_counter: + writemsg("ERROR: Global counter is lower than the '%s' COUNTER." % catpkg) + real_counter = fix_global_counter(counters[catpkg]) + except SystemExit, e: + raise # This needs to be propogated + except: + bad[catpkg] += ["COUNTER is corrupt"] + counters[catpkg] = -1 + + if "SLOT" not in pkgdirlist: + writemsg("ERROR: SLOT file missing from '%s'.\n" % catpkg) + writemsg(" RE-MERGE this exact package version or unmerge and remerge.\n") + bad[catpkg] += ["SLOT is missing"] + else: + myslot = open(pkgdir+"SLOT").read() + if myslot and myslot[-1]=="\n": + #writemsg("WARN: SLOT file has a newline. '%s'\n" % catpkg) + myslot = myslot[:-1] + if not myslot: + bad[catpkg] += ["SLOT is empty"] + writemsg("ERROR: SLOT file is empty for '%s'.\n" % catpkg) + writemsg(" RE-MERGE this exact package version or unmerge and remerge it.\n") + elif re.search("[^-a-zA-Z0-9\._]", myslot): + bad[catpkg] += ["SLOT is corrupt"] + writemsg("ERROR: SLOT file is corrupt for '%s'.\n" % catpkg) + writemsg(" RE-MERGE this exact package version or unmerge and remerge it.\n") + elif myslot.strip() != myslot: + writemsg("WARN: SLOT file has invalid characters. '%s'\n" % catpkg) + bad[catpkg] += ["SLOT is invalid"] + + if not bad[catpkg]: + del bad[catpkg] + + +actions = {} +writemsg("\n\n") +for catpkg in bad.keys(): + bad[catpkg].sort() + + mystr = "" + for x in bad[catpkg]: + mystr += " "+str(x)+"\n" + + if bad[catpkg] == ["CONTENTS is missing", "SLOT is missing"]: + writemsg("%s: (possibly injected)\n%s\n" % (green(catpkg), mystr)) + actions[catpkg] = ["ignore"] + elif bad[catpkg] == ["SLOT is empty"]: + writemsg("%s: (old package) []\n%s\n" % (yellow(catpkg), mystr)) + actions[catpkg] = ["remerge"] + else: + writemsg("%s: (damaged/invalid) []\n%s\n" % (red(catpkg), mystr)) + actions[catpkg] = ["merge exact"] + +if (len(sys.argv) > 1) and (sys.argv[1] == "--fix"): + writemsg("These are only directions, at the moment.") + for catpkg in actions.keys(): + action = actions[catpkg] + writemsg("We will now '%s' '%s'..." % (action, catpkg)) + #if action == +else: + #writemsg("Run with '--fix' to attempt automatic correction.") + pass + + + + + + + + + + + + + + + + + diff --git a/bin/fixdbentries b/bin/fixdbentries new file mode 100755 index 000000000..a9c3e1844 --- /dev/null +++ b/bin/fixdbentries @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/fixdbentries,v 1.3 2004/10/04 13:56:50 vapier Exp $ + +# Script to adjust the contents of the DB entries after a package move. +# Fairly straight forward... ./movedbentry 'from/here' 'to/here' /over/here + +VAR=$1 +NEW=$2 +SPATH=$3 + +grep -FrZl "${VAR}" "${SPATH}" | +sed "s#${SPATH}[^\d000]\+/CONTENTS\d000##g" | +$XARGS -0 sed -i -e " +s#${VAR}\$#${NEW}#g; +s#${VAR}\([[:space:]]\)#${NEW}\1#g; +s#${VAR}\(-[^a-zA-Z]\)#${NEW}\1#g; +s#${VAR}\([^a-zA-Z0-9-]\)#${NEW}\1#g +" diff --git a/bin/fixpackages b/bin/fixpackages new file mode 100755 index 000000000..f8d1948ac --- /dev/null +++ b/bin/fixpackages @@ -0,0 +1,14 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/fixpackages,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +import os,sys +os.environ["PORTAGE_CALLER"]="fixpackages" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage + +print +print "Done." +print diff --git a/bin/fowners b/bin/fowners new file mode 100755 index 000000000..cc13372a7 --- /dev/null +++ b/bin/fowners @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/fowners,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -lt 2 ] ; then + echo "${0}: at least two arguments needed" + exit 1 +fi + +OWNER="${1}" +shift +for FILE in $*; do + chown "${OWNER}" "${D}${FILE}" +done diff --git a/bin/fperms b/bin/fperms new file mode 100755 index 000000000..ce72126e2 --- /dev/null +++ b/bin/fperms @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/fperms,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +if [ ${#} -lt 2 ] ; then + echo "${0}: at least two arguments needed" + exit 1 +fi + +PERM="${1}" +shift +for FILE in $*; do + chmod "${PERM}" "${D}${FILE}" +done diff --git a/bin/md5check.py b/bin/md5check.py new file mode 100755 index 000000000..e64d54a96 --- /dev/null +++ b/bin/md5check.py @@ -0,0 +1,102 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/md5check.py,v 1.4 2004/10/10 10:07:20 carpaski Exp $ + +import os,sys,string +os.environ["PORTAGE_CALLER"]="mirror" +os.environ["FEATURES"]="mirror cvs" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage +from threading import * +from output import red,green,blue,bold +from random import shuffle +from time import sleep + + +def cstrip(mystr,mychars): + newstr = "" + for x in mystr: + if x not in mychars: + newstr += x + return newstr + +md5_list = {} +bn_list = [] +col_list = [] + +hugelist = [] +for mycp in portage.db["/"]["porttree"].dbapi.cp_all(): + hugelist += portage.db["/"]["porttree"].dbapi.cp_list(mycp) +hugelist.sort() + +for mycpv in hugelist: + pv = string.split(mycpv, "/")[-1] + + newuri = portage.db["/"]["porttree"].dbapi.aux_get(mycpv,["SRC_URI"])[0] + newuri = string.split(newuri) + + digestpath = portage.db["/"]["porttree"].dbapi.findname(mycpv) + digestpath = os.path.dirname(digestpath)+"/files/digest-"+pv + md5sums = portage.digestParseFile(digestpath) + + if md5sums == None: + portage.writemsg("Missing digest: %s\n" % mycpv) + md5sums = {} + + for x in md5sums.keys(): + if x[0] == '/': + del md5sums[x] + + #portage.writemsg("\n\ndigestpath: %s\n" % digestpath) + #portage.writemsg("md5sums: %s\n" % md5sums) + #portage.writemsg("newuri: %s\n" % newuri) + + bn_list = [] + for x in newuri: + if not x: + continue + if (x in [")","(",":","||"]) or (x[-1] == "?"): + # ignore it. :) + continue + x = cstrip(x,"()|?") + if not x: + continue + + mybn = os.path.basename(x) + if mybn not in bn_list: + bn_list += [mybn] + else: + continue + + if mybn not in md5sums.keys(): + portage_util.writemsg("Missing md5sum: %s in %s\n" % (mybn, mycpv)) + else: + if mybn in md5_list.keys(): + if (md5_list[mybn]["MD5"] != md5sums[mybn]["MD5"]) or \ + (md5_list[mybn]["size"] != md5sums[mybn]["size"]): + + # This associates teh md5 with each file. [md5/size] + md5joins = string.split(md5_list[mybn][2],",") + md5joins = string.join(md5joins," ["+md5_list[mybn][0]+"/"+md5_list[mybn][1]+"],") + md5joins += " ["+md5_list[mybn][0]+"/"+md5_list[mybn][1]+"]" + + portage.writemsg("Colliding md5: %s of %s [%s/%s] and %s\n" % (mybn,mycpv,md5sums[mybn][0],md5sums[mybn][1],md5joins)) + col_list += [mybn] + else: + md5_list[mybn][2] += ","+mycpv + else: + md5_list[mybn] = md5sums[mybn]+[mycpv] + del md5sums[mybn] + + #portage.writemsg(str(bn_list)+"\n") + for x in md5sums.keys(): + if x not in bn_list: + portage.writemsg("Extra md5sum: %s in %s\n" % (x, mycpv)) + + +print col_list +print +print str(len(md5_list.keys()))+" unique distfile md5s." +print str(len(bn_list))+" unique distfile names." diff --git a/bin/md5check.sh b/bin/md5check.sh new file mode 100755 index 000000000..a4f9f3fda --- /dev/null +++ b/bin/md5check.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/md5check.sh,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +# pipe in the data. + +sort -u - > md5check.tmp +grep '^Extra' md5check.tmp > md5check.tmp.extra +grep '^Missing' md5check.tmp > md5check.tmp.missing +grep '^Coll' md5check.tmp > md5check.tmp.colliding + +sed -i " +s:^Col:\nCol: +s:,:\n :g +s: of :\n :g +s: and :\n :g" md5check.tmp.colliding +sed -i "s/^[^ ]\+ md5sum: \(.*\) in \(.*\)$/ \2: \1/g" md5check.tmp.missing +sed -i "s/^[^ ]\+ md5sum: \(.*\) in \(.*\)$/ \2: \1/g" md5check.tmp.extra + +#echo "Colliding files:" > md5check.colliding +#sort -u md5check.tmp.colliding >> md5check.colliding +cp md5check.tmp.colliding md5check.colliding + +echo "Missing from digest:" > md5check.missing +sort -u md5check.tmp.missing >> md5check.missing + +echo "Extra files in digest:" > md5check.extra +sort -u md5check.tmp.extra >> md5check.extra + +rm md5check.tmp* diff --git a/bin/mirror.py b/bin/mirror.py new file mode 100755 index 000000000..1e08574a4 --- /dev/null +++ b/bin/mirror.py @@ -0,0 +1,167 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/mirror.py,v 1.3 2004/10/10 10:07:20 carpaski Exp $ + +# Defines the number of threads carrying out the downloading. +maxsems=5 + +import os,sys,string +os.environ["PORTAGE_CALLER"]="mirror" +os.environ["FEATURES"]="mirror cvs" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage +from threading import * +from output import red,green,blue,bold +from random import shuffle +from time import sleep + + +def cstrip(mystr,mychars): + newstr = "" + for x in mystr: + if x not in mychars: + newstr += x + return newstr + +class fetcher(Thread): + def __init__(self, filename, urilist, dest, md5sum): + self.filename = filename + self.myurilist = urilist + self.myuri = None + self.mydest = dest + self.destpath = self.mydest+"/"+self.filename + self.md5sum = md5sum + self.result = None + Thread.__init__(self) + + def fetch(self): + #print "Started",self.filename + sys.stderr.write(".") + sys.stderr.flush() + portage.spawn("wget -q -P "+str(self.mydest)+" "+self.myuri, free=1) + + def finished(self): + if os.path.exists(self.destpath) and self.md5sum: + ok,reason = portage_checksum.verify_all(self.destpath, md5sum) + if not ok: + portage_util.writemsg("Failed verification:" + reason + "\n") + return 1 + return 0 + + def delete(self): + if os.path.exists(self.destpath): + #print "Unlink:",self.destpath + os.unlink(self.destpath) + + def run(self): + if not self.finished(): + self.delete() + + while not self.finished(): + if self.myurilist: + self.myuri = self.myurilist.pop(0)+"/"+self.filename + self.fetch() + else: + self.delete() + self.result = 0 + #print "Failed:",self.filename + return 1 + + #print "Finished:",self.filename + self.result = 1 + return 0 + + +uri_list = {} +fetchers = [] +fetcher_sem = BoundedSemaphore(value=maxsems) +failures = 0 +successes = 0 + +def clean_fetchers(): + global fetcher_sem,fetchers,uri_list,failures,successes,maxsems + while len(fetchers) == maxsems: + for x in fetchers: + if not x.isAlive(): + failures += (x.result == 0) + successes += (x.result == 1) + if x.filename in uri_list.keys(): + del uri_list[x.filename] + del fetchers[fetchers.index(x)] + fetcher_sem.release() + if len(fetchers) == maxsems: + sleep(1) + + +def start_fetcher(fname, urilist, dest, md5sum): + global fetcher_sem,fetchers,uri_list,failures,successes + fetcher_sem.acquire() + fetchers.append(fetcher(fname, urilist, dest, md5sum)) + fetchers[-1].start() + + +tpm = portage.thirdpartymirrors +destdir = portage.settings["DISTDIR"][:] + +hugelist = [] +for mycp in portage.db["/"]["porttree"].dbapi.cp_all(): + hugelist += portage.db["/"]["porttree"].dbapi.cp_list(mycp) +shuffle(hugelist) + +mycount = -1 +for mycpv in hugelist: + pv = string.split(mycpv, "/")[-1] + + clean_fetchers() + + mycount += 1 + if ((mycount % 20) == 0): + sys.stdout.write("\nCompleted: %s\n" % mycount) + sys.stdout.flush() + newuri = portage.db["/"]["porttree"].dbapi.aux_get(mycpv,["SRC_URI"])[0] + newuri = string.split(newuri) + + digestpath = portage.db["/"]["porttree"].dbapi.findname(mycpv) + digestpath = os.path.dirname(digestpath)+"/files/digest-"+pv + md5sums = portage.digestParseFile(digestpath) + + for x in newuri: + clean_fetchers() + if not x: + continue + if (x in [")","(",":","||"]) or (x[-1] == "?"): + # ignore it. :) + continue + x = cstrip(x,"()|?") + if not x: + continue + mybn = os.path.basename(x) + mydn = os.path.dirname(x) + if mybn not in uri_list.keys(): + if (len(mybn) > len("mirror://")) and (mybn[:len("mirror://")] == "mirror://"): + mysite = string.split(x[len("mirror://"):], "/")[0] + shuffle(tpm[mysite]) + uri_list[mybn] = tpm[mysite][:] + else: + uri_list[mybn] = [os.path.dirname(x)] + clean_fetchers() + if (not md5sums) or (mybn not in md5sums.keys()): + start_fetcher(mybn, uri_list[mybn], destdir, None) + else: + start_fetcher(mybn, uri_list[mybn], destdir, md5sums[mybn]) + else: + break + +sys.stderr.write("\n\nWaiting last set\n") +sys.stderr.flush() +while fetchers: + if fetchers[0].isAlive(): + fetchers[0].join() + clean_fetchers() + +print +print +print "Successes:",successes +print "Failures: ",failures diff --git a/bin/newbin b/bin/newbin new file mode 100755 index 000000000..6c7904cd8 --- /dev/null +++ b/bin/newbin @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newbin,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +dobin "${T}/${2}" diff --git a/bin/newconfd b/bin/newconfd new file mode 100755 index 000000000..662b40ede --- /dev/null +++ b/bin/newconfd @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newconfd,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doconfd "${T}/${2}" diff --git a/bin/newdoc b/bin/newdoc new file mode 100755 index 000000000..a3c43a2ff --- /dev/null +++ b/bin/newdoc @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newdoc,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +dodoc "${T}/${2}" diff --git a/bin/newenvd b/bin/newenvd new file mode 100755 index 000000000..0ceec650f --- /dev/null +++ b/bin/newenvd @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newenvd,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doenvd "${T}/${2}" diff --git a/bin/newexe b/bin/newexe new file mode 100755 index 000000000..a2585b3f5 --- /dev/null +++ b/bin/newexe @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newexe,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doexe "${T}/${2}" diff --git a/bin/newinitd b/bin/newinitd new file mode 100755 index 000000000..cb23dd798 --- /dev/null +++ b/bin/newinitd @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newinitd,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doinitd "${T}/${2}" diff --git a/bin/newins b/bin/newins new file mode 100755 index 000000000..965ff94b3 --- /dev/null +++ b/bin/newins @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newins,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Error: Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doins "${T}/${2}" diff --git a/bin/newlib.a b/bin/newlib.a new file mode 100755 index 000000000..3ec62a3e9 --- /dev/null +++ b/bin/newlib.a @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newlib.a,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Error: Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +dolib.a "${T}/${2}" diff --git a/bin/newlib.so b/bin/newlib.so new file mode 100755 index 000000000..aa9f9a174 --- /dev/null +++ b/bin/newlib.so @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newlib.so,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Error: Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +dolib.so "${T}/${2}" diff --git a/bin/newman b/bin/newman new file mode 100755 index 000000000..227411a56 --- /dev/null +++ b/bin/newman @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newman,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +doman "${T}/${2}" diff --git a/bin/newsbin b/bin/newsbin new file mode 100755 index 000000000..eadfba220 --- /dev/null +++ b/bin/newsbin @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/newsbin,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +if [ -z "${T}" ] || [ -z "${2}" ] ; then + echo "Nothing defined to do." + exit 1 +fi + +rm -rf "${T}/${2}" +cp "${1}" "${T}/${2}" +dosbin "${T}/${2}" diff --git a/bin/pemerge.py b/bin/pemerge.py new file mode 100755 index 000000000..08de6eda3 --- /dev/null +++ b/bin/pemerge.py @@ -0,0 +1,44 @@ +#!/usr/bin/python -O + +import profile,time,sys,os +sys.path = ["/usr/lib/portage/bin","/usr/lib/portage/pym"]+sys.path + +def clock(): + return time.time() +profile.time.clock = clock + +profile.run("import emerge", os.getcwd()+"/prof") + +class StatsProcesser: + def __init__(self, stats): + self.output = [] + self.last = "" + import sys + sys.stdout = self + stats.print_stats() + sys.stdout = sys.__stdout__ + funcs = ["?"] + for line in self.output: + spline = line.split() + if len(spline) == 6 and spline[0][0].isdigit(): + func = spline[5][spline[5].index("(")+1:-1] + print line + if func not in funcs: + funcs.append(func) + func = "\\(" + func + "\\)" + stats.print_callers(func) + + def write(self, text): + new = self.last + text + new = new.split("\n") + if len(new) > 1: + self.output += new[:-1] + self.last = new[-1] + +import pstats +p = pstats.Stats("prof") +dir(p) +p.sort_stats("time") +p.print_stats() + +sp = StatsProcesser(p) diff --git a/bin/pkgmerge b/bin/pkgmerge new file mode 100755 index 000000000..2bbb5f680 --- /dev/null +++ b/bin/pkgmerge @@ -0,0 +1,59 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/pkgmerge,v 1.8 2004/10/04 13:56:50 vapier Exp $ + +import sys,os,string +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage,xpak + +#build our package digraph + +def digraph_create(digraph,mykey,myprovides=None): + mytbz2=xpak.tbz2(bintree.getname(mykey)) + mydep=mytbz2.getelements("RDEPEND") + digraph.addnode(mykey,myprovides) + mycheck=roottree.depcheck(string.join(mydep," ")) + if mycheck[0]==0: + print "!!! Error: RDEPEND string formatted incorrectly:",mydep + return None + for x in mycheck[1]: + mymatch=bintree.dep_bestmatch(x) + if mymatch=="": + print "!!! Error: can't resolve dependency --",x + return None + if not digraph_create(digraph,mymatch,mykey): + return None + return 1 + +#main program loop +myvirtuals=portage.getvirtuals(portage.root) +roottree=portage.vartree(portage.root,myvirtuals) +bintree=portage.binarytree("/",myvirtuals) +pretend=0 +if len(sys.argv)>=2: + if sys.argv[1]=="--pretend": + print "These are the packages that I would merge, in order:" + pretend=1 + del sys.argv[1] + elif sys.argv[1]=="--help": + print "Usage: pkgmerge [--pretend] pkg1.tbz2 [pkg2.tbz2]..." + sys.exit(1) +for mypkg in sys.argv[1:]: + digraph=portage.digraph() + mytbz2=xpak.tbz2(mypkg) + mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(mypkg)[:-5] + digraph_create(digraph,mykey) + while not digraph.empty(): + mykey=digraph.firstzero() + if not mykey: + print "!!! Error: circular dependencies" + sys.exit(1) + mytbz2=bintree.getname(mykey) + if pretend: + print mytbz2 + else: + portage.pkgmerge(mytbz2,portage.settings["ROOT"]) + digraph.delnode(mykey) + diff --git a/bin/pkgmerge.new b/bin/pkgmerge.new new file mode 100755 index 000000000..66dbe1676 --- /dev/null +++ b/bin/pkgmerge.new @@ -0,0 +1,84 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/pkgmerge.new,v 1.7 2004/10/04 13:56:50 vapier Exp $ + +import os,string,sys +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage,xpak + +#beautiful directed graph functions + +def dig_addnode(digraph,mykey,myprovides): + if not digraph.has_key(mykey): + if myprovides==None: + digraph[mykey]=[0,[]] + else: + digraph[mykey]=[0,[myprovides]] + digraph[myprovides][0]=digraph[myprovides][0]+1 + return + digraph[mykey]=[digraph[mykey][0],digraph[mykey][1].append(myprovides)] + +def dig_delnode(digraph,mykey): + if not digraph.has_key(mykey): + return + for x in digraph[mykey][1]: + digraph[x][0]=digraph[x][0]-1 + del digraph[mykey] + +def dig_firstzero(digraph): + for x in digraph.keys(): + if digraph[x][0]==0: + return x + return None + +#build our package digraph + +def digraph_create(digraph,mykey,myprovides=None): + mytbz2=xpak.tbz2(bintree.getname(mykey)) + mydep=mytbz2.getelements("RDEPEND") + dig_addnode(digraph,mykey,myprovides) + mycheck=roottree.depcheck(string.join(mydep," ")) + if mycheck[0]==0: + print "!!! Error: RDEPEND string formatted incorrectly:",mydep + return None + for x in mycheck[1]: + mymatch=bintree.dep_bestmatch(x) + if mymatch=="": + print "!!! Error: can't resolve dependency --",x + return None + if not digraph_create(digraph,mymatch,mykey): + return None + return 1 + +#main program loop +myvirtuals=portage.getvirtual(portage.root) +roottree=portage.vartree(portage.root,myvirtuals) +bintree=portage.binarytree("/",myvirtuals) +pretend=0 +if len(sys.argv)>=2: + if sys.argv[1]=="--pretend": + print "These are the packages that I would merge, in order:" + pretend=1 + del sys.argv[1] + elif sys.argv[1]=="--help": + print "Usage: pkgmerge [--pretend] pkg1.tbz2 [pkg2.tbz2]..." + sys.exit(1) +for mypkg in sys.argv[1:]: + digraph={} + mytbz2=xpak.tbz2(mypkg) + mykey=mytbz2.getelements("CATEGORY")[0]+"/"+mypkg[:-5] + digraph_create(digraph,mykey) + while (len(digraph)): + mykey=dig_firstzero(digraph) + if not mykey: + print "!!! Error: circular dependencies" + sys.exit(1) + mytbz2=bintree.getname(mykey) + if pretend: + print mytbz2 + else: + portage.pkgmerge(mytbz2) + dig_delnode(digraph,mykey) + diff --git a/bin/pkgname b/bin/pkgname new file mode 100755 index 000000000..22be6f1da --- /dev/null +++ b/bin/pkgname @@ -0,0 +1,17 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/pkgname,v 1.8 2004/10/04 13:56:50 vapier Exp $ + +import sys +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage + +a=portage.pkgsplit(sys.argv[1]) +if a: + print a[0],a[1],a[2][1:] + sys.exit(0) +else: + print '!!! Error: package name is invalid.' + sys.exit(1) diff --git a/bin/portage_gpg_update.sh b/bin/portage_gpg_update.sh new file mode 100755 index 000000000..a20d9bc1b --- /dev/null +++ b/bin/portage_gpg_update.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/portage_gpg_update.sh,v 1.2 2004/10/04 13:56:50 vapier Exp $ + +wget -O - http://www.gentoo.org/proj/en/devrel/roll-call/userinfo.xml | sed 's:.*\(0x[0-9a-fA-F]\+\)[^0-9a-fA-F].*:\1:gp;d' | xargs gpg -vvv --no-default-keyring --no-permission-warning --homedir /usr/portage/metadata --keyring "gentoo.gpg" --keyserver subkeys.pgp.net --recv-keys &> gpg.log diff --git a/bin/portageq b/bin/portageq new file mode 100755 index 000000000..6bd6c402e --- /dev/null +++ b/bin/portageq @@ -0,0 +1,256 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/portageq,v 1.13.2.1 2005/04/12 12:23:41 jstubbs Exp $ + +import sys, os +os.environ["PORTAGE_CALLER"] = "portageq" +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import portage,types,string + + +#----------------------------------------------------------------------------- +# +# To add functionality to this tool, add a function below. +# +# The format for functions is: +# +# def function(argv): +# """<list of options for this function> +# <description of the function> +# """ +# <code> +# +# "argv" is an array of the command line parameters provided after the command. +# +# Make sure you document the function in the right format. The documentation +# is used to display help on the function. +# +# You do not need to add the function to any lists, this tool is introspective, +# and will automaticly add a command by the same name as the function! +# + + +def has_version(argv): + """<root> <category/package> + Return code 0 if it's available, 1 otherwise. + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1]) + if mylist: + sys.exit(0) + else: + sys.exit(1) + except KeyError: + sys.exit(1) + + +def best_version(argv): + """<root> <category/package> + Returns category/package-version (without .ebuild). + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + mylist=portage.db[argv[0]]["vartree"].dbapi.match(argv[1]) + print portage.best(mylist) + except KeyError: + sys.exit(1) + + +def mass_best_version(argv): + """<root> [<category/package>]+ + Returns category/package-version (without .ebuild). + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + for pack in argv[1:]: + mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack) + print pack+":"+portage.best(mylist) + except KeyError: + sys.exit(1) + + +def best_visible(argv): + """<root> [<category/package>]+ + Returns category/package-version (without .ebuild). + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + mylist=portage.db[argv[0]]["porttree"].dbapi.match(argv[1]) + print portage.best(mylist) + except KeyError: + sys.exit(1) + + +def mass_best_visible(argv): + """<root> [<category/package>]+ + Returns category/package-version (without .ebuild). + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + for pack in argv[1:]: + mylist=portage.db[argv[0]]["porttree"].dbapi.match(pack) + print pack+":"+portage.best(mylist) + except KeyError: + sys.exit(1) + + +def all_best_visible(argv): + """<root> + Returns all best_visible packages (without .ebuild). + """ + if (len(argv) < 1): + print "ERROR: insufficient parameters!" + + #print portage.db[argv[0]]["porttree"].dbapi.cp_all() + for pkg in portage.db[argv[0]]["porttree"].dbapi.cp_all(): + mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg)) + if mybest: + print mybest + +def match(argv): + """<root> <category/package> + Returns \n seperated list of category/package-version + """ + if (len(argv) < 2): + print "ERROR: insufficient parameters!" + sys.exit(2) + try: + print string.join(portage.db[argv[0]]["vartree"].dbapi.match(argv[1]),"\n") + except KeyError: + sys.exit(1) + + +def vdb_path(argv): + """ + Returns the path used for the var(installed) package database for the + set environment/configuration options. + """ + print portage.root+portage.VDB_PATH + +def gentoo_mirrors(argv): + """ + Returns the mirrors set to use in the portage configuration. + """ + print portage.settings["GENTOO_MIRRORS"] + + +def portdir(argv): + """ + Returns the PORTDIR path as defined in the portage configuration. + """ + print portage.settings["PORTDIR"] + + +def config_protect(argv): + """ + Returns the CONFIG_PROTECT paths as defined in the portage configuration. + """ + print portage.settings["CONFIG_PROTECT"] + + +def config_protect_mask(argv): + """ + Returns the CONFIG_PROTECT_MASK paths as defined in the portage configuration. + """ + print portage.settings["CONFIG_PROTECT_MASK"] + + +def portdir_overlay(argv): + """ + Returns the PORTDIR_OVERLAY path as defined in the portage configuration. + """ + print portage.settings["PORTDIR_OVERLAY"] + + +def pkgdir(argv): + """ + Returns the PKGDIR path as defined in the portage configuration. + """ + print portage.settings["PKGDIR"] + + +def distdir(argv): + """ + Returns the DISTDIR path as defined in the portage configuration. + """ + print portage.settings["DISTDIR"] + + +def envvar(argv): + """<variable> + Returns a specific environment variable as exists prior to ebuild.sh. + Similar to: emerge --verbose --info | egrep '^<variable>=' + """ + print portage.settings[argv[0]] + + +#----------------------------------------------------------------------------- +# +# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED! +# + +def usage(): + rev="$Revision: 1.13.2.1 $" + ver=string.split(rev, ' ')[1] + print ">>> Portage information query tool -- version "+ver + print ">>> Usage: portageq <command> [<option> ...]" + print "" + print "Available commands:" + + # + # Show our commands -- we do this by scanning the functions in this + # file, and formatting each functions documentation. + # + for name in globals().keys(): + # Drop python stuff, modules, and our own support functions. + if (name in ("usage", "__doc__", "__name__", "main", "os", "portage", "sys", "__builtins__", "types", "string")): + continue + + # Drop non-functions + obj = globals()[name] + if (type(obj) != types.FunctionType): + continue + + doc = obj.__doc__ + if (doc == None): + print " "+name + print " MISSING DOCUMENTATION!" + print "" + continue + + lines = string.split(doc, '\n') + print " "+name+" "+string.strip(lines[0]) + for line in lines[1:]: + print " "+string.strip(line) + + +def main(): + if (len(sys.argv) < 2): + usage() + sys.exit() + + cmd = sys.argv[1] + try: + function = globals()[cmd] + function(sys.argv[2:]) + except KeyError: + usage() + sys.exit() + +main() + + +#----------------------------------------------------------------------------- diff --git a/bin/prepall b/bin/prepall new file mode 100755 index 000000000..3826f74fe --- /dev/null +++ b/bin/prepall @@ -0,0 +1,39 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepall,v 1.10 2004/10/14 23:31:33 ferringb Exp $ + +prepallman +prepallinfo +prepallstrip + +#this should help to ensure that all (most?) shared libraries are executable +for i in "${D}"opt/*/lib{,32,64} \ + "${D}"lib{,32,64} \ + "${D}"usr/lib{,32,64} \ + "${D}"usr/X11R6/lib{,32,64} ; do + [ ! -d "${i}" ] && continue + + for j in "${i}"/*.so.* "${i}"/*.so ; do + [ ! -e "${j}" ] && continue + [ -L "${j}" ] && continue + echo "making executable: /${j/${D}/}" + chmod +x "${j}" + done +done + +# Move aclocals +for i in `find "${D}"/ -name "aclocal" -type d 2>/dev/null` ; do + [ -z "${i}" ] && continue + + # Strip double '/' + dir1="`echo "${i}" | sed -e 's:/\{2,\}:/:g'`" + dir2="`echo "${D}/usr/share/aclocal" | sed -e 's:/\{2,\}:/:g'`" + + [ "${dir1}" == "${dir2}" ] && continue + + echo "moving aclocal: /${i/${D}/}" + install -d "${D}"usr/share/aclocal + mv "${i}"/* "${D}"usr/share/aclocal + rm -fr "${i}" +done diff --git a/bin/prepalldocs b/bin/prepalldocs new file mode 100755 index 000000000..26ac80ca4 --- /dev/null +++ b/bin/prepalldocs @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepalldocs,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +z="`find "${D}"usr/share/doc \( -type f -or -type l \) -not -name "*.gz" -not -name "*.js" 2>/dev/null`" + +for y in ${z} ; do + if [ -L "${y}" ] ; then + # Symlink ... + mylink="${y}" + linkto="`readlink "${y}"`" + + if [ "${linkto##*.}" != "gz" ] ; then + linkto="${linkto}.gz" + fi + if [ "${mylink##*.}" != "gz" ] ; then + mylink="${mylink}.gz" + fi + + echo "fixing doc symlink: ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [ "${y}" != "${mylink}" ] ; then + echo "removing old symlink: ${y##*/}" + rm -f "${y}" + fi + else + if [ "${y##*.}" != "gz" ] ; then + echo "gzipping doc: ${y##*/}" + gzip -f -9 "${y}" + fi + fi +done diff --git a/bin/prepallinfo b/bin/prepallinfo new file mode 100755 index 000000000..134e8326e --- /dev/null +++ b/bin/prepallinfo @@ -0,0 +1,9 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepallinfo,v 1.6 2004/10/04 13:56:50 vapier Exp $ + +[ ! -d "${D}usr/share/info" ] && exit 0 + +echo "info:" +prepinfo diff --git a/bin/prepallman b/bin/prepallman new file mode 100755 index 000000000..26486fda7 --- /dev/null +++ b/bin/prepallman @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepallman,v 1.10 2004/10/04 13:56:50 vapier Exp $ + +echo "man:" +for x in "${D}"opt/*/man "${D}"usr/share/man "${D}"usr/local/man "${D}"usr/X11R6/man ; do + if [ -d "${x}" ] + then + prepman "`echo "${x}" | sed -e "s:${D}::" -e "s:/man[/]*$::"`" + fi +done diff --git a/bin/prepallstrip b/bin/prepallstrip new file mode 100755 index 000000000..57994738e --- /dev/null +++ b/bin/prepallstrip @@ -0,0 +1,11 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepallstrip,v 1.12 2004/10/04 13:56:50 vapier Exp $ + +if [ "${FEATURES//*nostrip*/true}" == "true" ] || [ "${RESTRICT//*nostrip*/true}" == "true" ] ; then + exit 0 +fi + +echo "prepallstrip:" +prepstrip "${D}" diff --git a/bin/prepinfo b/bin/prepinfo new file mode 100755 index 000000000..65bfba32c --- /dev/null +++ b/bin/prepinfo @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepinfo,v 1.6.2.1 2005/05/29 12:40:08 jstubbs Exp $ + +if [ -z "$1" ] ; then + z="${D}usr/share/info" +else + if [ -d "${D}$1/share/info" ] ; then + z="${D}$1/share/info" + else + z="${D}$1/info" + fi +fi + +[ ! -d "${z}" ] && exit 0 + +rm -f "${z}"/{dir,dir.info,dir.info.gz} + +for x in `find "${z}"/ -mindepth 1 -maxdepth 1 \( -type f -or -type l \) 2>/dev/null` ; do + if [ -L "${x}" ] ; then + # Symlink ... + mylink="${x}" + linkto="`readlink "${x}"`" + + if [ "${linkto##*.}" != "gz" ] ; then + linkto="${linkto}.gz" + fi + if [ "${mylink##*.}" != "gz" ] ; then + mylink="${mylink}.gz" + fi + + echo "fixing GNU info symlink: ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [ "${x}" != "${mylink}" ] ; then + echo "removing old symlink: ${x##*/}" + rm -f "${x}" + fi + else + if [ "${x##*.}" != "gz" ] ; then + echo "gzipping GNU info page: ${x##*/}" + gzip -f -9 "${x}" + fi + fi +done diff --git a/bin/preplib b/bin/preplib new file mode 100755 index 000000000..2a4312606 --- /dev/null +++ b/bin/preplib @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/preplib,v 1.7.2.1 2005/01/02 09:36:02 jstubbs Exp $ + +LIBDIR_VAR="LIBDIR_${ABI}" +if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then + CONF_LIBDIR="${!LIBDIR_VAR}" +fi +unset LIBDIR_VAR + +if [ -z "${CONF_LIBDIR}" ]; then + # we need this to default to lib so that things dont break + CONF_LIBDIR="lib" +fi + +if [ -z "$1" ] ; then + z="${D}usr/${CONF_LIBDIR}" +else + z="${D}$1/${CONF_LIBDIR}" +fi + +if [ -d "${z}" ] ; then + ldconfig -n -N "${z}" +fi diff --git a/bin/preplib.so b/bin/preplib.so new file mode 100755 index 000000000..13d67d9c9 --- /dev/null +++ b/bin/preplib.so @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/preplib.so,v 1.10.2.1 2004/12/06 03:01:43 carpaski Exp $ + +for x in "$@" ; do + if [ -d "${D}${x}" ] ; then + ldconfig -n -N "${D}${x}" + fi +done diff --git a/bin/prepman b/bin/prepman new file mode 100755 index 000000000..2042c4d3d --- /dev/null +++ b/bin/prepman @@ -0,0 +1,46 @@ +#!/bin/bash +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepman,v 1.10.2.3 2005/05/29 12:40:08 jstubbs Exp $ + +if [ -z "$1" ] ; then + z="${D}usr/share/man" +else + z="${D}$1/man" +fi + +[ ! -d "${z}" ] && exit 0 + +for x in `find "${z}"/ -type d 2>/dev/null` ; do + for y in `find "${x}"/ -mindepth 1 -maxdepth 1 \( -type f -or -type l \) ! -name '.keep' 2>/dev/null` ; do + if [ -L "${y}" ] ; then + # Symlink ... + mylink="${y}" + linkto="`readlink "${y}"`" + + # Do NOT change links to directories + if [ -d "${z}/${linkto}" ] ; then + continue + fi + + if [ "${linkto##*.}" != "gz" ] && [ "${linkto##*.}" != "bz2" ]; then + linkto="${linkto}.gz" + fi + if [ "${mylink##*.}" != "gz" ] && [ "${mylink##*.}" != "bz2" ]; then + mylink="${mylink}.gz" + fi + + echo "fixing man page symlink: ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [ "${y}" != "${mylink}" ] ; then + echo "removing old symlink: ${y##*/}" + rm -f "${y}" + fi + else + if [ "${y##*.}" != "gz" ] && [ "${y##*.}" != "bz2" ] && [ ! -d "${y}" ]; then + echo "gzipping man page: ${y##*/}" + gzip -f -9 "${y}" + fi + fi + done +done diff --git a/bin/prepstrip b/bin/prepstrip new file mode 100755 index 000000000..f5a51a378 --- /dev/null +++ b/bin/prepstrip @@ -0,0 +1,48 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/prepstrip,v 1.23.2.3 2005/08/15 02:58:20 vapier Exp $ + +if [ "${FEATURES//*nostrip*/true}" == "true" ] || [ "${RESTRICT//*nostrip*/true}" == "true" ] ; then + echo "nostrip" + STRIP="/bin/false" + PORTAGE_STRIP_FLAGS="" +else + STRIP="${STRIP:-${CHOST}-strip}" + type -p ${STRIP} > /dev/null || STRIP=strip + PORTAGE_STRIP_FLAGS=${PORTAGE_STRIP_FLAGS:---strip-unneeded} +fi + +banner=1 +retval=0 + +for x in "$@" ; do + if [ -d "${x}" ]; then + # We only want files. So make a pass for each directory and call again. + find "${x}" -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 -or -name '*.so' -or -name '*.so.*' \) -print0 | + $XARGS -0 -n500 prepstrip + else + if [ ${banner} -eq 1 ] ; then + echo "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}" + banner=0 + fi + + f=$(file "${x}") || continue + [ -z "${f}" ] && continue + + if [ -z "${f/*current ar archive*/}" ]; then + echo " ${x:${#D}:${#x}}" + ${STRIP} -g "${x}" + fi + if [ -z "${f/*SB executable*/}" ]; then + echo " ${x:${#D}:${#x}}" + ${STRIP} "${x}" + fi + if [ -z "${f/*SB shared object*/}" ]; then + echo " ${x:${#D}:${#x}}" + ${STRIP} ${PORTAGE_STRIP_FLAGS} "${x}" + fi + fi +done + +exit ${retval} diff --git a/bin/quickpkg b/bin/quickpkg new file mode 100755 index 000000000..f5baa4cbe --- /dev/null +++ b/bin/quickpkg @@ -0,0 +1,148 @@ +#!/bin/bash +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/quickpkg,v 1.13.2.6 2005/08/10 22:08:48 vapier Exp $ + +# This script tries to quickly create a Gentoo binary package using the +# VDB_PATH/category/pkg/* files +# +# Resulting tbz2 file will be created in ${PKGDIR} ... +# default is /usr/portage/packages/All/ + +if [ "`whoami`" != "root" ] ; then + echo "You must run this as root" + exit 1 +fi + +export PORTAGE_DB=$(portageq vdb_path) +if [ -z "$1" ] || [ $1 == "-h" ] || [ $1 == "--help" ] ; then + echo "QUICKPKG ver 1.2" + echo "USAGE: quickpkg <list of pkgs>" + echo " a pkg can be of the form:" + echo " - ${PORTAGE_DB}/<CATEGORY>/<PKG-VERSION>/" + echo " - single depend-type atom ..." + echo " if portage can emerge it, quickpkg can make a package" + echo " for exact definitions of depend atoms, see ebuild(5)" + echo + echo "EXAMPLE:" + echo " quickpkg ${PORTAGE_DB}/net-www/apache-1.3.27-r1" + echo " package up apache, just version 1.3.27-r1" + echo " quickpkg apache" + echo " package up apache, all versions of apache installed" + echo " quickpkg =apache-1.3.27-r1" + echo " package up apache, just version 1.3.27-r1" + exit 1 +fi + +export PKGDIR=$(portageq envvar PKGDIR) +export PORTAGE_TMPDIR=$(portageq envvar PORTAGE_TMPDIR) + +source /sbin/functions.sh + +# here we make a package given a little info +# $1 = package-name w/version +# $2 = category +do_pkg() { + mkdir -p "${PORTAGE_TMPDIR}/portage-pkg" || exit 1 + chmod 0750 "${PORTAGE_TMPDIR}/portage-pkg" + MYDIR="${PORTAGE_TMPDIR}/portage-pkg/$1" + SRCDIR="${PORTAGE_DB}/$2/$1" + LOG="${PORTAGE_TMPDIR}/portage-pkg/$1-quickpkglog" + + ebegin "Building package for $1" + ( + # clean up temp directory + rm -rf "${MYDIR}" + + # get pkg info files + mkdir -p "${MYDIR}"/temp + cp "${SRCDIR}"/* "${MYDIR}"/temp/ + + # create filelist and a basic tbz2 + gawk '{ + if ($1 != "dir") { + if ($1 == "obj") + NF=NF-2 + else if ($1 == "sym") + NF=NF-3 + print + } + }' "${SRCDIR}"/CONTENTS | cut -f2- -d" " - > "${MYDIR}"/filelist + tar vjcf "${MYDIR}"/bin.tar.bz2 --files-from="${MYDIR}"/filelist --no-recursion + + # join together the basic tbz2 and the pkg info files + xpak "${MYDIR}"/temp "${MYDIR}"/inf.xpak + tbz2tool join "${MYDIR}"/bin.tar.bz2 "${MYDIR}"/inf.xpak "${MYDIR}"/$1.tbz2 + + # move the final binary package to PKGDIR + [ -d "${PKGDIR}"/All ] || mkdir -p "${PKGDIR}"/All + [ -d "${PKGDIR}/$2" ] || mkdir -p "${PKGDIR}/$2" + mv "${MYDIR}"/$1.tbz2 "${PKGDIR}"/All + ( cd "${PKGDIR}/$2" && ln -s ../All/$1.tbz2 ) + + # cleanup again + rm -rf "${MYDIR}" + ) >& "${LOG}" + + if [ -e "${PKGDIR}/All/$1.tbz2" ] ; then + rm -f "${LOG}" + PKGSTATS="${PKGSTATS}"$'\n'"$(einfo $1: $(du -h "${PKGDIR}/All/$1.tbz2" | gawk '{print $1}'))" + eend 0 + else + cat ${LOG} + PKGSTATS="${PKGSTATS}"$'\n'"$(ewarn $1: not created)" + eend 1 + fi +} + +# here we parse the parameters given to use on the cmdline +export PKGERROR="" +export PKGSTATS="" +for x in "$@" ; do + + # they gave us full path + if [ -e "${x}"/CONTENTS ] ; then + x=$(readlink -f $x) + pkg=$(echo ${x} | cut -d/ -f6) + cat=$(echo ${x} | cut -d/ -f5) + do_pkg "${pkg}" "${cat}" + + # lets figure out what they want + else + DIRLIST=$(portageq match / "${x}") + if [ -z "${DIRLIST}" ] ; then + eerror "Could not find anything to match '${x}'; skipping" + export PKGERROR="${PKGERROR} ${x}" + continue + fi + + for d in ${DIRLIST} ; do + pkg=$(echo ${d} | cut -d/ -f2) + cat=$(echo ${d} | cut -d/ -f1) + if [ -f "${PORTAGE_DB}/${cat}/${pkg}/CONTENTS" ] ; then + do_pkg ${pkg} ${cat} + elif [ -d "${PORTAGE_DB}/${cat}/${pkg}" ] ; then + ewarn "Package '${cat}/${pkg}' was injected; skipping" + else + eerror "Unhandled case (${cat}/${pkg}) !" + eerror "Please file a bug at http://bugs.gentoo.org/" + exit 10 + fi + done + fi + +done + +if [ -z "${PKGSTATS}" ] ; then + eerror "No packages found" + exit 1 +else + echo $'\n'"$(einfo Packages now in ${PKGDIR}:)${PKGSTATS}" +fi +if [ ! -z "${PKGERROR}" ] ; then + ewarn "The following packages could not be found:" + ewarn "${PKGERROR}" + exit 2 +fi + +exit 0 diff --git a/bin/regenworld b/bin/regenworld new file mode 100755 index 000000000..2e7f7f841 --- /dev/null +++ b/bin/regenworld @@ -0,0 +1,93 @@ +#!/usr/bin/python +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/regenworld,v 1.10.2.1 2005/01/11 03:40:57 carpaski Exp $ + +import sys +sys.path.insert(0, "/usr/lib/portage/pym") + +import portage, string, re + +__candidatematcher__ = re.compile("^[0-9]+: \\*\\*\\* emerge ") +__noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot| unmerge( |$)") + +def issyspkg(pkgline): + return (pkgline[0] == "*") + +def iscandidate(logline): + return (__candidatematcher__.match(logline) \ + and not __noncandidatematcher__.search(logline)) + +def getpkginfo(logline): + logline = re.sub("^[0-9]+: \\*\\*\\* emerge ", "", logline) + logline = logline.strip() + logline = re.sub("(\\S+\\.(ebuild|tbz2))|(--\\S+)|inject ", "", logline) + return logline.strip() + +__uniqlist__ = [] +def isunwanted(pkgline): + if pkgline in ["world", "system", "depclean", "info", "regen", ""]: + return False + elif pkgline in __uniqlist__: + return False + elif not re.search("^[a-zA-Z<>=~]", pkgline): + return False + else: + __uniqlist__.append(pkgline) + return True + +# show a little description if we have arguments +if len(sys.argv) >= 2 and sys.argv[1] in ["-h", "--help"]: + print "This script regenerates the portage world file by checking the portage" + print "logfile for all actions that you've done in the past. It ignores any" + print "arguments except --help. It is recommended that you make a backup of" + print "your existing world file (%s) before using this tool." % portage.WORLD_FILE + sys.exit(0) + +worldlist = portage.grabfile(portage.WORLD_FILE) +syslist = portage.settings.packages +syslist = filter(issyspkg, syslist) + +logfile = portage.grabfile("/var/log/emerge.log") +biglist = filter(iscandidate, logfile) +biglist = map(getpkginfo, biglist) +tmplist = [] +for l in biglist: + tmplist += l.split() +biglist = filter(isunwanted, tmplist) +#for p in biglist: +# print p +#sys.exit(0) + +# resolving virtuals +realsyslist = [] +for mykey in syslist: + # drop the asterix + mykey = mykey[1:] + #print "candidate:",mykey + mylist=portage.db["/"]["vartree"].dbapi.match(mykey) + if mylist: + mykey=portage.cpv_getkey(mylist[0]) + if mykey not in realsyslist: + realsyslist.append(mykey) + +for mykey in biglist: + #print "checking:",mykey + try: + mylist=portage.db["/"]["vartree"].dbapi.match(mykey) + except KeyError: + if "--debug" in sys.argv: + print "* ignoring broken log entry for %s (likely injected)" % mykey + except ValueError, e: + print "* %s is an ambigous package name, candidates are:\n%s" % (mykey, e) + continue + if mylist: + #print "mylist:",mylist + myfavkey=portage.cpv_getkey(mylist[0]) + if (myfavkey not in realsyslist) and (myfavkey not in worldlist): + print "add to world:",myfavkey + worldlist.append(myfavkey) + +myfile=open(portage.WORLD_FILE, "w") +myfile.write(string.join(worldlist, '\n')+'\n') +myfile.close() diff --git a/bin/repoman b/bin/repoman new file mode 100755 index 000000000..40607d7a6 --- /dev/null +++ b/bin/repoman @@ -0,0 +1,1522 @@ +#!/usr/bin/python -O +# Copyright 1999-2005 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/repoman,v 1.98.2.23 2005/06/18 01:00:43 vapier Exp $ + +# Next to do: dep syntax checking in mask files +# Then, check to make sure deps are satisfiable (to avoid "can't find match for" problems) +# that last one is tricky because multiple profiles need to be checked. + +import os,sys,shutil +exename=os.path.basename(sys.argv[0]) +os.environ["PORTAGE_CALLER"]="repoman" +sys.path = ["/usr/lib/portage/pym"]+sys.path +version="1.2" + +import string,signal,re,pickle,tempfile + +import portage +import portage_checksum +import portage_const +import portage_dep +import cvstree +import time +from output import * +#bold, darkgreen, darkred, green, red, turquoise, yellow + +from commands import getstatusoutput +from fileinput import input +from grp import getgrnam +from stat import * + + +def err(txt): + print exename+": "+txt + sys.exit(1) + +def exithandler(signum=None,frame=None): + sys.stderr.write("\n"+exename+": Interrupted; exiting...\n") + sys.exit(1) + os.kill(0,signal.SIGKILL) +signal.signal(signal.SIGINT,exithandler) + +REPOROOTS=["gentoo-x86"] +modes=["scan","fix","full","help","commit","last","lfull"] +shortmodes={"ci":"commit"} +modeshelp={ +"scan" :"Scan current directory tree for QA issues (default)", +"fix" :"Fix those issues that can be fixed (stray digests, missing digests)", +"full" :"Scan current directory tree for QA issues (full listing)", +"help" :"Show this screen", +"commit":"Scan current directory tree for QA issues; if OK, commit via cvs", +"last" :"Remember report from last run", +"lfull" :"Remember report from last run (full listing)" +} +options=["--pretend","--help","--commitmsg","--commitmsgfile","--verbose","--xmlparse","--ignore-other-arches","--include-masked"] +shortoptions={"-m":"--commitmsg","-M":"--commitmsgfile","-p":"--pretend","-v":"--verbose","-x":"--xmlparse","-I":"--ignore-other-arches"} +optionshelp={ +"--pretend":"Don't actually perform commit or fix steps; just show what would be done (always enabled when not started in a CVS tree).", +"--help" :"Show this screen", +"--commitmsg" :"Adds a commit message via the command line.", +"--commitmsgfile":"Adds a commit message from a file given on the command line.", +"--ignore-other-arches": "Instructs repoman to ignore arches that are not relevent to the committing arch. REPORT/FIX issues you work around.", +"--verbose":"Displays every package name while checking", +"--xmlparse":"Forces the metadata.xml parse check to be carried out", +"--include-masked":"Includes masked packages in scans at category or tree level" +} + +qahelp={ + "CVS/Entries.IO_error":"Attempting to commit, and an IO error was encountered access the Entries file", + "digest.partial":"Digest files do not contain all corresponding URI elements", + "digest.assumed":"Existing digest must be assumed correct (Package level only)", + "digest.unused":"Digest entry has no matching SRC_URI entry", + "digest.fail":"Digest does not match the specified local file", + "digest.stray":"Digest files that do not have a corresponding ebuild", + "digest.missing":"Digest files that are missing (ebuild exists, digest doesn't)", + "digest.disjointed":"Digests not added to cvs when the matching ebuild has been added", + "digest.notadded":"Digests that exist but have not been added to cvs", + "digest.unmatch":"Digests which are incomplete (please check if your USE/ARCH includes all files)", + "ebuild.invalidname":"Ebuild files with a non-parseable or syntactically incorrect name", + "ebuild.namenomatch":"Ebuild files that do not have the same name as their parent directory", + "changelog.missing":"Missing ChangeLog files", + "ebuild.disjointed":"Ebuilds not added to cvs when the matching digest has been added", + "ebuild.notadded":"Ebuilds that exist but have not been added to cvs", + "changelog.notadded":"ChangeLogs that exist but have not been added to cvs", + "filedir.missing":"Package lacks a files directory", + "file.executable":"Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do note need the executable bit", + "file.size":"Files in the files directory must be under 20k", + "KEYWORDS.missing":"Ebuilds that have a missing KEYWORDS variable", + "LICENSE.missing":"Ebuilds that have a missing LICENSE variable", + "DESCRIPTION.missing":"Ebuilds that have a missing DESCRIPTION variable", + "SLOT.missing":"Ebuilds that have a missing SLOT variable", + "HOMEPAGE.missing":"Ebuilds that have a missing HOMEPAGE variable", + "DEPEND.bad":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds)", + "RDEPEND.bad":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds)", + "PDEPEND.bad":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds)", + "DEPEND.badmasked":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds)", + "RDEPEND.badmasked":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds)", + "PDEPEND.badmasked":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds)", + "DEPEND.badindev":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds) in developing arch", + "RDEPEND.badindev":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds) in developing arch", + "PDEPEND.badindev":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds) in developing arch", + "DEPEND.badmaskedindev":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds) in developing arch", + "RDEPEND.badmaskedindev":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds) in developing arch", + "PDEPEND.badmaskedindev":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds) in developing arch", + "DEPEND.syntax":"Syntax error in DEPEND (usually an extra/missing space/parenthesis)", + "RDEPEND.syntax":"Syntax error in RDEPEND (usually an extra/missing space/parenthesis)", + "PDEPEND.syntax":"Syntax error in PDEPEND (usually an extra/missing space/parenthesis)", + "LICENSE.syntax":"Syntax error in LICENSE (usually an extra/missing space/parenthesis)", + "ebuild.syntax":"Error generating cache entry for ebuild; typically caused by ebuild syntax error", + "ebuild.output":"A simple sourcing of the ebuild produces output; this breaks ebuild policy.", + "ebuild.nesteddie":"Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.", + "variable.readonly":"Assigning a readonly variable", + "IUSE.invalid":"This build has a variable in IUSE that is not in the use.desc or use.local.desc file", + "LICENSE.invalid":"This ebuild is listing a license that doesnt exist in portages license/ dir.", + "KEYWORDS.invalid":"This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found", + "ebuild.nostable":"There are no ebuilds that are marked as stable for your ARCH", + "ebuild.allmasked":"All ebuilds are masked for this package (Package level only)", + "ebuild.majorsyn":"This ebuild has a major syntax error that may cause the ebuild to fail partially or fully", + "ebuild.minorsyn":"This ebuild has a minor syntax error that contravenes gentoo coding style", + "ebuild.badheader":"This ebuild has a malformed header", + "metadata.missing":"Missing metadata.xml files", + "metadata.bad":"Bad metadata.xml files", + "virtual.versioned":"PROVIDE contains virtuals with versions", + "virtual.exists":"PROVIDE contains existing package names", + "virtual.unavailable":"PROVIDE contains a virtual which contains no profile default" +} + +qacats = qahelp.keys() +qacats.sort() + +qawarnings=[ +"changelog.missing", +"changelog.notadded", +"ebuild.notadded", +"ebuild.nostable", +"ebuild.allmasked", +"ebuild.nesteddie", +"digest.assumed", +"digest.notadded", +"digest.disjointed", +"digest.missing", +"digest.unused", +"DEPEND.badmasked","RDEPEND.badmasked","PDEPEND.badmasked", +"DEPEND.badindev","RDEPEND.badindev","PDEPEND.badindev", +"DEPEND.badmaskedindev","RDEPEND.badmaskedindev","PDEPEND.badmaskedindev", +"IUSE.invalid", +"ebuild.minorsyn", +"ebuild.badheader", +"file.size", +"metadata.missing", +"metadata.bad", +"virtual.versioned" +] + +missingvars=["KEYWORDS","LICENSE","DESCRIPTION","HOMEPAGE","SLOT"] +allvars=portage.auxdbkeys +commitmessage=None +commitmessagefile=None +for x in missingvars: + x += ".missing" + if x not in qacats: + print "* missingvars values need to be added to qahelp ("+x+")" + qacats.append(x) + qawarnings.append(x) + + +def err(txt): + print exename+": "+txt + sys.exit(1) + +ven_cat = r'[\w0-9-]+' # Category +ven_nam = r'([+a-z0-9-]+(?:[+_a-z0-9-]*[+a-z0-9-]+)*)' # Name +ven_ver = r'((?:\d+\.)*\d+[a-z]?)' # Version +ven_suf = r'(_(alpha\d*|beta\d*|pre\d*|rc\d*|p\d+))?' # Suffix +ven_rev = r'(-r\d+)?' # Revision + +ven_string=ven_cat+'/'+ven_nam+'-'+ven_ver+ven_suf+ven_rev +valid_ebuild_name_re=re.compile(ven_string+'$', re.I) +valid_ebuild_filename_re=re.compile(ven_string+'\.ebuild$', re.I) + +repoman_settings = portage.config(clone=portage.settings) + +def valid_ebuild_name(name): + """(name) --- Checks to ensure that the package name meets portage specs. + Return 1 if valid, 0 if not.""" + # Handle either a path to the ebuild, or cat/pkg-ver string + if (len(name) > 7) and (name[-7:] == ".ebuild"): + if valid_ebuild_filename_re.match(name): + return 1 + else: + if valid_ebuild_name_re.match(name): + return 1 + return 0 + + +def help(): + print + print green(exename+" "+version) + print " \"Quality is job zero.\"" + print " Copyright 1999-2005 Gentoo Foundation" + print " Distributed under the terms of the GNU General Public License v2" + print + print bold(" Usage:"),turquoise(exename),"[",green("option"),"] [",green("mode"),"]" + print bold(" Modes:"),turquoise("scan (default)"), + for x in modes[1:]: + print "|",turquoise(x), + print "\n" + print " "+green(string.ljust("Option",20)+" Description") + for x in options: + print " "+string.ljust(x,20),optionshelp[x] + print + print " "+green(string.ljust("Mode",20)+" Description") + for x in modes: + print " "+string.ljust(x,20),modeshelp[x] + print + print " "+green(string.ljust("QA keyword",20)+" Description") + for x in qacats: + print " "+string.ljust(x,20),qahelp[x] + print + sys.exit(1) + +def last(): + try: + #Retrieve and unpickle stats and fails from saved files + savedf=open('/var/cache/edb/repo.stats','r') + stats = pickle.load(savedf) + savedf.close() + savedf=open('/var/cache/edb/repo.fails','r') + fails = pickle.load(savedf) + savedf.close() + except SystemExit, e: + raise # Need to propogate this + except: + err("Error retrieving last repoman run data; exiting.") + + #dofail will be set to 1 if we have failed in at least one non-warning category + dofail=0 + #dowarn will be set to 1 if we tripped any warnings + dowarn=0 + #dofull will be set if we should print a "repoman full" informational message + dofull=0 + + print + print green("RepoMan remembers...") + print + for x in qacats: + if stats[x]: + dowarn=1 + if x not in qawarnings: + dofail=1 + else: + if mymode!="lfull": + continue + print " "+string.ljust(x,20), + if stats[x]==0: + print green(`stats[x]`) + continue + elif x in qawarnings: + print yellow(`stats[x]`) + else: + print red(`stats[x]`) + if mymode!="lfull": + if stats[x]<12: + for y in fails[x]: + print " "+y + else: + dofull=1 + else: + for y in fails[x]: + print " "+y + print + if dofull: + print bold("Note: type \"repoman lfull\" for a complete listing of repomans last run.") + print + if dowarn and not dofail: + print green("RepoMan sez:"),"\"You only gave me a partial QA payment last time?\nI took it, but I wasn't happy.\"" + elif not dofail: + print green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\"" + print + sys.exit(1) + +mymode=None +myoptions=[] +if len(sys.argv)>1: + x=1 + while x < len(sys.argv): + if sys.argv[x] in shortmodes.keys(): + sys.argv[x]=shortmodes[sys.argv[x]] + if sys.argv[x] in modes: + if mymode==None: + mymode=sys.argv[x] + else: + err("Please specify either \""+mymode+"\" or \""+sys.argv[x]+"\", but not both.") + elif sys.argv[x] in options+shortoptions.keys(): + optionx=sys.argv[x] + if optionx in shortoptions.keys(): + optionx = shortoptions[optionx] + if (optionx=="--commitmsg") and (len(sys.argv)>=(x+1)): + commitmessage=sys.argv[x+1] + x=x+1 + elif (optionx=="--commitmsgfile") and (len(sys.argv)>=(x+1)): + commitmessagefile=sys.argv[x+1] + x=x+1 + elif optionx not in myoptions: + myoptions.append(optionx) + else: + err("\""+sys.argv[x]+"\" is not a valid mode or option.") + x=x+1 +if mymode==None: + mymode="scan" +if mymode=="help" or ("--help" in myoptions): + help() +if mymode=="last" or (mymode=="lfull"): + last() +if mymode=="commit" and "--include-masked" not in myoptions: + myoptions.append("--include-masked") + +isCvs=False +myreporoot=None +if os.path.isdir("CVS"): + repoman_settings["PORTDIR_OVERLAY"]="" + if "cvs" not in portage.features: + print + print + print red('!!! You do not have ')+bold('FEATURES="cvs" ')+red("enabled...") + print red("!!! ")+bold("Adding \"cvs\" to FEATURES") + print + os.environ["FEATURES"]=repoman_settings["FEATURES"]+" cvs" + + try: + isCvs=True + myrepofile=open("CVS/Repository") + myreporoot=myrepofile.readline()[:-1] + myrepofile.close() + myrepofile=open("CVS/Root") + myreporootpath=string.split(myrepofile.readline()[:-1], ":")[-1] + myrepofile.close() + if myreporootpath == myreporoot[:len(myreporootpath)]: + # goofy os x cvs co. + myreporoot = myreporoot[len(myreporootpath):] + while myreporoot and myreporoot[0] == '/': + myreporoot = myreporoot[1:] + except SystemExit, e: + raise # Need to propogate this + except: + err("Error grabbing repository information; exiting.") + myreporootpath=os.path.normpath(myreporootpath) + if myreporootpath=="/space/cvsroot": + print + print + print red("You're using the wrong cvsroot. For Manifests to be correct, you must") + print red("use the same base cvsroot path that the servers use. Please try the") + print red("following script to remedy this:") + print + print "cd my_cvs_tree" + print + print "rm -Rf [a-z]*" + print "cvs up" + print + if portage.userland=="BSD" or portage.userland=="Darwin": + print "find ./ -type f -regex '.*/CVS/Root$' -print0 | xargs -0 sed \\" + else: + print "find ./ -type f -regex '.*/CVS/Root$' -print0 | xargs -0r sed \\" + fi + print " -i 's:/space/cvsroot$:/home/cvsroot:'" + print + print red("You must clear and re-update your tree as all header tags will cause") + print red("problems in manifests for all rsync and /home/cvsroot users.") + print + print "You should do this to any other gentoo trees your have as well," + print "excluding the deletions. 'gentoo-src' should be /home/cvsroot." + print + sys.exit(123) + +if not "--pretend" in myoptions and not isCvs: + print + print darkgreen("Not in a CVS repository; enabling pretend mode.") + myoptions.append("--pretend"); + + +def have_profile_dir(path, maxdepth=3): + while path != "/" and maxdepth: + if os.path.exists(path + "/profiles/package.mask"): + return path + path = os.path.normpath(path + "/..") + maxdepth -= 1 + +portdir=None +portdir_overlay=None +mydir=os.getcwd() +if mydir[-1] != "/": + mydir += "/" + +for overlay in repoman_settings["PORTDIR_OVERLAY"].split(): + if overlay[-1] != "/": + overlay += "/" + if mydir[:len(overlay)] == overlay: + portdir_overlay = overlay + subdir = mydir[len(overlay):] + if subdir and subdir[-1] != "/": + subdir += "/" + if have_profile_dir(mydir, subdir.count("/")): + portdir = portdir_overlay + break + +if not portdir_overlay: + if (repoman_settings["PORTDIR"]+"/")[:len(mydir)] == mydir: + portdir_overlay = repoman_settings["PORTDIR"] + else: + portdir_overlay = have_profile_dir(mydir) + portdir = portdir_overlay + +if not portdir_overlay: + print darkred("Unable to determine PORTDIR.") + sys.exit(1) + +if not portdir: + portdir = repoman_settings["PORTDIR"] + +if portdir[-1] == "/": + portdir = portdir[:-1] +if portdir_overlay[-1] == "/": + portdir_overlay = portdir_overlay[:-1] + +os.environ["PORTDIR"] = portdir +if portdir_overlay != portdir: + os.environ["PORTDIR_OVERLAY"] = portdir_overlay +else: + os.environ["PORTDIR_OVERLAY"] = "" + +print "\nSetting paths:" +print "PORTDIR = \""+os.environ["PORTDIR"]+"\"" +print "PORTDIR_OVERLAY = \""+os.environ["PORTDIR_OVERLAY"]+"\"" + + +reload(portage) +repoman_settings = portage.config(clone=portage.settings) + +if not myreporoot: + myreporoot = os.path.basename(portdir_overlay) + myreporoot += mydir[len(portdir_overlay):-1] + +if isCvs: + reporoot=None + for x in REPOROOTS: + if myreporoot[0:len(x)]==x: + reporoot=myreporoot + if not reporoot: + err("Couldn't recognize repository type. Supported repositories:\n"+repr(REPOROOTS)) +reposplit=string.split(myreporoot,"/") +repolevel=len(reposplit) + +# check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting. +# Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating. +# this check ensure that repoman knows where it is, and the manifest recommit is at least possible. +if mymode == "commit" and repolevel not in [1,2,3]: + print red("***")+" Commit attempts *must* be from within a cvs co, category, or package directory." + print red("***")+" Attempting to commit from a packages files directory will be blocked for instance." + print red("***")+" This is intended behaviour, to ensure the manifest is recommited for a package." + print red("***") + err("Unable to identify level we're commiting from for %s" % string.join(reposplit,'/')) + +if repolevel == 3 and "--include-masked" not in myoptions: + myoptions.append("--include-masked") + +startdir=os.getcwd() + +for x in range(0,repolevel-1): + os.chdir("..") +repodir=os.getcwd() +os.chdir(startdir) + +def caterror(mycat): + err(mycat+" is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.") +print +if "--pretend" in myoptions: + print green("RepoMan does a once-over of the neighborhood...") +else: + print green("RepoMan scours the neighborhood...") + +# retreive local USE list +luselist={} +try: + mylist=portage.grabfile(portdir+"/profiles/use.local.desc") + for mypos in range(0,len(mylist)): + mysplit=mylist[mypos].split()[0] + myuse=string.split(mysplit,":") + if len(myuse)==2: + if not luselist.has_key(myuse[0]): + luselist[myuse[0]] = [] + luselist[myuse[0]].append(myuse[1]) +except SystemExit, e: + raise # Need to propogate this +except: + err("Couldn't read from use.local.desc") + +# setup a uselist from portage +uselist=[] +try: + uselist=portage.grabfile(portdir+"/profiles/use.desc") + for l in range(0,len(uselist)): + uselist[l]=string.split(uselist[l])[0] +except SystemExit, e: + raise # Need to propogate this +except: + err("Couldn't read USE flags from use.desc") + +# retrieve a list of current licenses in portage +liclist=portage.listdir(portdir+"/licenses") +if not liclist: + err("Couldn't find licenses?") + +# retrieve list of offical keywords +try: + kwlist=portage.grabfile(portdir+"/profiles/arch.list") +except SystemExit, e: + raise # Need to propogate this +except: + err("Couldn't read KEYWORDS from arch.list") +if not kwlist: + kwlist=["alpha","arm","hppa","mips","ppc","sparc","x86"] + +scanlist=[] +if repolevel==2: + #we are inside a category directory + catdir=reposplit[-1] + if catdir not in repoman_settings.categories: + caterror(catdir) + mydirlist=os.listdir(startdir) + for x in mydirlist: + if x=="CVS": + continue + if os.path.isdir(startdir+"/"+x): + scanlist.append(catdir+"/"+x) +elif repolevel==1: + for x in repoman_settings.categories: + if not os.path.isdir(startdir+"/"+x): + continue + for y in os.listdir(startdir+"/"+x): + if y=="CVS": + continue + if os.path.isdir(startdir+"/"+x+"/"+y): + scanlist.append(x+"/"+y) +elif repolevel==3: + catdir = reposplit[-2] + if catdir not in repoman_settings.categories: + caterror(catdir) + scanlist.append(catdir+"/"+reposplit[-1]) + +profiles={} +descfile=portdir+"/profiles/profiles.desc" +if os.path.exists(descfile): + for x in portage.grabfile(descfile): + if x[0]=="#": + continue + arch=string.split(x) + if len(arch)!=3: + print "wrong format: \""+red(x)+"\" in "+descfile + continue + if not os.path.isdir(portdir+"/profiles/"+arch[1]): + print "Invalid "+arch[2]+" profile ("+arch[1]+") for arch "+arch[0] + continue + if profiles.has_key(arch[0]): + profiles[arch[0]]+= [[arch[1], arch[2]]] + else: + profiles[arch[0]] = [[arch[1], arch[2]]] + + for x in portage.archlist: + if x[0] == "~": + continue + if not profiles.has_key(x): + print red("\""+x+"\" doesn't have a valid profile listed in profiles.desc.") + print red("You need to either \"cvs update\" your profiles dir or follow this") + print red("up with the "+x+" team.") + print +else: + print red("profiles.desc does not exist: "+descfile) + print red("You need to do \"cvs update\" in profiles dir.") + print + sys.exit(1) + + +stats={} +fails={} +#objsadded records all object being added to cvs +objsadded=[] +for x in qacats: + stats[x]=0 + fails[x]=[] +xmllint_capable = False +if getstatusoutput('which xmllint')[0] != 0: + print red("!!! xmllint not found. Can't check metadata.xml.\n") + if "--xmlparse" in myoptions or repolevel==3: + print red("!!!")+" sorry, xmllint is needed. failing\n" + sys.exit(1) +else: + #hardcoded paths/urls suck. :-/ + must_fetch=1 + backup_exists=0 + try: + # if it's been over a week since fetching (or the system clock is fscked), grab an updated copy of metadata.dtd + # clock is fscked or it's been a week. time to grab a new one. + ct=os.stat(portage.CACHE_PATH + '/metadata.dtd')[ST_CTIME] + if abs(time.time() - ct) > (60*60*24*7): + # don't trap the exception, we're watching for errno 2 (file not found), anything else is a bug. + backup_exists=1 + else: + must_fetch=0 + + except (OSError,IOError), e: + if e.errno != 2: + print red("!!!")+" caught exception '%s' for %s/metadata.dtd, bailing" % (str(e), portage.CACHE_PATH) + sys.exit(1) + + if must_fetch: + print + print green("***")+" the local copy of metadata.dtd needs to be refetched, doing that now" + print + try: + if os.path.exists(repoman_settings["DISTDIR"]+'/metadata.dtd'): + os.remove(repoman_settings["DISTDIR"]+'/metadata.dtd') + val=portage.fetch(['http://www.gentoo.org/dtd/metadata.dtd'],repoman_settings,fetchonly=0, \ + try_mirrors=0) + if val: + if backup_exists: + os.remove(portage.CACHE_PATH+'/metadata.dtd') + shutil.copy(repoman_settings["DISTDIR"]+'/metadata.dtd',portage.CACHE_PATH+'/metadata.dtd') + os.chown(portage.CACHE_PATH+'/metadata.dtd',os.getuid(),portage.portage_gid) + os.chmod(portage.CACHE_PATH+'/metadata.dtd',0664) + + + except SystemExit, e: + raise # Need to propogate this + except Exception,e: + print + print red("!!!")+" attempting to fetch 'http://www.gentoo.org/dtd/metadata.dtd', caught" + print red("!!!")+" exception '%s' though." % str(e) + val=0 + if not val: + print red("!!!")+" fetching new metadata.dtd failed, aborting" + sys.exit(1) + #this can be problematic if xmllint changes their output + xmllint_capable=True + + +arch_caches={} +for x in scanlist: + #ebuilds and digests added to cvs respectively. + if "--verbose" in myoptions: + print "checking package " + x + eadded=[] + dadded=[] + cladded=0 + catdir,pkgdir=x.split("/") + checkdir=repodir+"/"+x + checkdirlist=os.listdir(checkdir) + ebuildlist=[] + for y in checkdirlist: + if y[-7:]==".ebuild": + ebuildlist.append(y[:-7]) + if y in ["Manifest","ChangeLog","metadata.xml"]: + if os.stat(checkdir+"/"+y)[0] & 0x0248: + stats["file.executable"] += 1 + fails["file.executable"].append(checkdir+"/"+y) + digestlist=[] + if isCvs: + try: + mystat=os.stat(checkdir+"/files")[0] + if len(ebuildlist) and not S_ISDIR(mystat): + raise Exception + except SystemExit, e: + raise # Need to propogate this + except: + stats["filedir.missing"] += 1 + fails["filedir.missing"].append(checkdir) + continue + try: + myf=open(checkdir+"/CVS/Entries","r") + myl=myf.readlines() + for l in myl: + if l[0]!="/": + continue + splitl=l[1:].split("/") + if not len(splitl): + continue + objsadded.append(splitl[0]) + if splitl[0][-7:]==".ebuild": + eadded.append(splitl[0][:-7]) + if splitl[0]=="ChangeLog": + cladded=1 + except IOError: + if mymode=="commit": + stats["CVS/Entries.IO_error"] += 1 + fails["CVS/Entries.IO_error"].append(checkdir+"/CVS/Entries") + continue + + try: + myf=open(checkdir+"/files/CVS/Entries","r") + myl=myf.readlines() + for l in myl: + if l[0]!="/": + continue + splitl=l[1:].split("/") + if not len(splitl): + continue + objsadded.append(splitl[0]) + if splitl[0][:7]=="digest-": + dadded.append(splitl[0][7:]) + except IOError: + if mymode=="commit": + stats["CVS/Entries.IO_error"] += 1 + fails["CVS/Entries.IO_error"].append(checkdir+"/files/CVS/Entries") + continue + + if os.path.exists(checkdir+"/files"): + filesdirlist=os.listdir(checkdir+"/files") + for y in filesdirlist: + if y[:7]=="digest-": + if y[7:] not in dadded: + #digest not added to cvs + stats["digest.notadded"]=stats["digest.notadded"]+1 + fails["digest.notadded"].append(x+"/files/"+y) + if y[7:] in eadded: + stats["digest.disjointed"]=stats["digest.disjointed"]+1 + fails["digest.disjointed"].append(x+"/files/"+y) + + if os.stat(checkdir+"/files/"+y)[0] & 0x0248: + stats["file.executable"] += 1 + fails["file.executable"].append(x+"/files/"+y) + + mydigests=portage.digestParseFile(checkdir+"/files/"+y) + + mykey = catdir + "/" + y[7:] + if y[7:] not in ebuildlist: + #stray digest + if mymode=="fix": + if "--pretend" in myoptions: + print "(cd "+repodir+"/"+x+"/files; cvs rm -f "+y+")" + else: + os.system("(cd "+repodir+"/"+x+"/files; cvs rm -f "+y+")") + else: + stats["digest.stray"]=stats["digest.stray"]+1 + fails["digest.stray"].append(x+"/files/"+y) + else: + # We have an ebuild + myuris,myfiles = portage.db["/"]["porttree"].dbapi.getfetchlist(mykey,all=True) + for entry in mydigests.keys(): + if entry not in myfiles: + stats["digest.unused"] += 1 + fails["digest.unused"].append(y+"::"+entry) + uri_dict = {} + for myu in myuris: + myubn = os.path.basename(myu) + if myubn not in uri_dict: + uri_dict[myubn] = [myu] + else: + uri_dict[myubn] += [myu] + + for myf in uri_dict: + myff = repoman_settings["DISTDIR"] + "/" + myf + if not mydigests.has_key(myf): + uri_settings = portage.config(clone=repoman_settings) + if mymode == "fix": + if not portage.fetch(uri_dict[myf], uri_settings): + stats["digest.unmatch"] += 1 + fails["digest.unmatch"].append(y+"::"+myf) + else: + eb_name,eb_location = portage.db["/"]["porttree"].dbapi.findname2(mykey) + portage.doebuild(eb_name, "digest", "/", uri_settings) + else: + stats["digest.partial"] += 1 + fails["digest.partial"].append(y+"::"+myf) + else: + if os.path.exists(myff): + if not portage_checksum.verify_all(myff, mydigests[myf]): + stats["digest.fail"] += 1 + fails["digest.fail"].append(y+"::"+myf) + elif repolevel == 3: + stats["digest.assumed"] += 1 + fails["digest.assumed"].append(y+"::"+myf) + + # recurse through files directory + # use filesdirlist as a stack, appending directories as needed so people can't hide > 20k files in a subdirectory. + while filesdirlist: + y = filesdirlist.pop(0) + try: + mystat = os.stat(checkdir+"/files/"+y) + except OSError, oe: + if oe.errno == 2: + # don't worry about it. it likely was removed via fix above. + continue + else: + raise oe + if S_ISDIR(mystat.st_mode): + for z in os.listdir(checkdir+"/files/"+y): + filesdirlist.append(y+"/"+z) + # current policy is no files over 20k, this is the check. + elif mystat.st_size > 20480: + stats["file.size"] += 1 + fails["file.size"].append("("+ str(mystat.st_size/1024) + "K) "+x+"/files/"+y) + + if "ChangeLog" not in checkdirlist: + stats["changelog.missing"]+=1 + fails["changelog.missing"].append(x+"/ChangeLog") + + #metadata.xml file check + if "metadata.xml" not in checkdirlist: + stats["metadata.missing"]+=1 + fails["metadata.missing"].append(x+"/metadata.xml") + #metadata.xml parse check + else: + #Only carry out if in package directory or check forced + if xmllint_capable: + st=getstatusoutput("xmllint --nonet --noout --dtdvalid %s/metadata.dtd %s/metadata.xml" % (portage.CACHE_PATH, checkdir)) + if st[0] != 0: + for z in st[1].split("\n"): + print red("!!! ")+z + stats["metadata.bad"]+=1 + fails["metadata.bad"].append(x+"/metadata.xml") + + allmasked = True + + for y in ebuildlist: + if os.stat(checkdir+"/"+y+".ebuild")[0] & 0x0248: + stats["file.executable"] += 1 + fails["file.executable"].append(x+"/"+y+".ebuild") + if y not in eadded: + #ebuild not added to cvs + stats["ebuild.notadded"]=stats["ebuild.notadded"]+1 + fails["ebuild.notadded"].append(x+"/"+y+".ebuild") + if y in dadded: + stats["ebuild.disjointed"]=stats["ebuild.disjointed"]+1 + fails["ebuild.disjointed"].append(x+"/"+y+".ebuild") + if not os.path.exists(checkdir+"/files/digest-"+y): + if mymode=="fix": + if "--pretend" in myoptions: + print "You will need to run:" + print " /usr/sbin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest" + else: + retval=os.system("/usr/sbin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest") + if retval: + print "!!! Exiting on ebuild digest (shell) error code:",retval + sys.exit(retval) + else: + stats["digest.missing"]=stats["digest.missing"]+1 + fails["digest.missing"].append(x+"/files/digest-"+y) + myesplit=portage.pkgsplit(y) + if myesplit==None or not valid_ebuild_name(x.split("/")[0]+"/"+y): + stats["ebuild.invalidname"]=stats["ebuild.invalidname"]+1 + fails["ebuild.invalidname"].append(x+"/"+y+".ebuild") + continue + elif myesplit[0]!=pkgdir: + print pkgdir,myesplit[0] + stats["ebuild.namenomatch"]=stats["ebuild.namenomatch"]+1 + fails["ebuild.namenomatch"].append(x+"/"+y+".ebuild") + continue + try: + myaux=portage.db["/"]["porttree"].dbapi.aux_get(catdir+"/"+y,allvars,strict=1) + except KeyError: + stats["ebuild.syntax"]=stats["ebuild.syntax"]+1 + fails["ebuild.syntax"].append(x+"/"+y+".ebuild") + continue + except IOError: + stats["ebuild.output"]=stats["ebuild.output"]+1 + fails["ebuild.output"].append(x+"/"+y+".ebuild") + continue + + mynewaux = {} + for idx in range(len(allvars)): + if idx < len(myaux): + mynewaux[allvars[idx]] = myaux[idx] + else: + mynewaux[allvars[idx]] = "" + myaux = mynewaux + + # Test for negative logic and bad words in the RESTRICT var. + #for x in myaux[allvars.index("RESTRICT")].split(): + # if x.startswith("no"): + # print "Bad RESTRICT value: %s" % x + + myaux["PROVIDE"] = portage_dep.use_reduce(portage_dep.paren_reduce(myaux["PROVIDE"]), matchall=1) + myaux["PROVIDE"] = " ".join(portage.flatten(myaux["PROVIDE"])) + for myprovide in myaux["PROVIDE"].split(): + prov_cp = portage.dep_getkey(myprovide) + if prov_cp != myprovide: + stats["virtual.versioned"]+=1 + fails["virtual.versioned"].append(x+"/"+y+".ebuild: "+myprovide) + prov_pkg = portage.dep_getkey(portage.best(portage.db["/"]["porttree"].dbapi.xmatch("match-all", prov_cp))) + if prov_cp == prov_pkg: + stats["virtual.exists"]+=1 + fails["virtual.exists"].append(x+"/"+y+".ebuild: "+prov_cp) + + for pos in range(0,len(missingvars)): + if not myaux[missingvars[pos]]: + myqakey=missingvars[pos]+".missing" + stats[myqakey]=stats[myqakey]+1 + fails[myqakey].append(x+"/"+y+".ebuild") + + if "--ignore-other-arches" in myoptions: + arches=[[repoman_settings["ARCH"], repoman_settings["ARCH"], portage.groups]] + else: + arches=[] + for keyword in myaux["KEYWORDS"].split(): + if (keyword[0]=="-"): + continue + elif (keyword[0]=="~"): + arches.append([keyword, keyword[1:], [keyword[1:], keyword]]) + else: + arches.append([keyword, keyword, [keyword]]) + allmasked = False + + baddepsyntax = False + badlicsyntax = False + catpkg = catdir+"/"+y + for mytype in ["DEPEND","RDEPEND","PDEPEND","LICENSE"]: + mydepstr = myaux[mytype] + if (string.find(mydepstr, " ?") != -1): + stats[mytype+".syntax"] += 1 + fails[mytype+".syntax"].append(catpkg+".ebuild "+mytype+": '?' preceded by space") + if mytype != "LICENSE": + baddepsyntax = True + else: + badlicsyntax = True + try: + # Missing closing parenthesis will result in a ValueError + mydeplist=portage_dep.paren_reduce(mydepstr) + # Missing opening parenthesis will result in a final "" element + if "" in mydeplist or "(" in mydeplist: + raise ValueError + except ValueError: + stats[mytype+".syntax"] += 1 + fails[mytype+".syntax"].append(catpkg+".ebuild "+mytype+": Mismatched parenthesis") + if mytype != "LICENSE": + baddepsyntax = True + else: + badlicsyntax = True + + for keyword,arch,groups in arches: + portage.groups=groups + + if not profiles.has_key(arch): + # A missing profile will create an error further down + # during the KEYWORDS verification. + continue + + for prof in profiles[arch]: + + profdir = portdir+"/profiles/"+prof[0] + + portage.profiledir=profdir + + if arch_caches.has_key(prof[0]): + dep_settings, portage.portdb, portage.db["/"]["porttree"] = arch_caches[prof[0]] + else: + os.environ["ACCEPT_KEYWORDS"]="-~"+arch + dep_settings=portage.config(config_profile_path=profdir, config_incrementals=portage_const.INCREMENTALS) + portage.portdb=portage.portdbapi(portdir, dep_settings) + portage.db["/"]["porttree"]=portage.portagetree("/",dep_settings.getvirtuals("/")) + arch_caches[prof[0]]=[dep_settings, portage.portdb, portage.db["/"]["porttree"]] + + for myprovide in myaux["PROVIDE"].split(): + prov_cp = portage.dep_getkey(myprovide) + if prov_cp not in dep_settings.virtuals: + stats["virtual.unavailable"]+=1 + fails["virtual.unavailable"].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+prov_cp) + + if not baddepsyntax: + ismasked = (catdir+"/"+y not in portage.db["/"]["porttree"].dbapi.xmatch("list-visible",x)) + if ismasked: + if "--include-masked" not in myoptions: + continue + #we are testing deps for a masked package; give it some lee-way + suffix="masked" + matchmode="match-all" + else: + suffix="" + matchmode="match-visible" + + if prof[1] == "dev": + suffix=suffix+"indev" + + for mytype,mypos in [["DEPEND",len(missingvars)],["RDEPEND",len(missingvars)+1],["PDEPEND",len(missingvars)+2]]: + + mykey=mytype+".bad"+suffix + myvalue = myaux[mytype] + if not myvalue: + continue + try: + mydep=portage.dep_check(myvalue,portage.db["/"]["porttree"].dbapi,dep_settings,use="all",mode=matchmode) + except KeyError, e: + stats[mykey]=stats[mykey]+1 + fails[mykey].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+repr(e[0])) + continue + + if mydep[0]==1: + if mydep[1]!=[]: + #we have some unsolvable deps + #remove ! deps, which always show up as unsatisfiable + d=0 + while d<len(mydep[1]): + if mydep[1][d][0]=="!": + del mydep[1][d] + else: + d += 1 + #if we emptied out our list, continue: + if not mydep[1]: + continue + stats[mykey]=stats[mykey]+1 + fails[mykey].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+repr(mydep[1])) + else: + stats[mykey]=stats[mykey]+1 + fails[mykey].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+repr(mydep[1])) + + # this check needs work, it won't catch (\ndie) + if not os.system("egrep '^[^#]*\([^)]*\<die\>' "+checkdir+"/"+y+".ebuild >/dev/null 2>&1"): + stats["ebuild.nesteddie"]=stats["ebuild.nesteddie"]+1 + fails["ebuild.nesteddie"].append(x+"/"+y+".ebuild") + # uselist checks - global + myuse = myaux["IUSE"].split() + for mypos in range(len(myuse)-1,-1,-1): + if myuse[mypos] and (myuse[mypos] in uselist): + del myuse[mypos] + # uselist checks - local + mykey = portage.dep_getkey(catpkg) + if luselist.has_key(mykey): + for mypos in range(len(myuse)-1,-1,-1): + if myuse[mypos] and (myuse[mypos] in luselist[mykey]): + del myuse[mypos] + for mypos in range(len(myuse)): + stats["IUSE.invalid"]=stats["IUSE.invalid"]+1 + fails["IUSE.invalid"].append(x+"/"+y+".ebuild: %s" % myuse[mypos]) + + # license checks + if not badlicsyntax: + myuse = myaux["LICENSE"] + # Parse the LICENSE variable, remove USE conditions and + # flatten it. + myuse=portage_dep.use_reduce(portage_dep.paren_reduce(myuse), matchall=1) + myuse=portage.flatten(myuse) + # Check each entry to ensure that it exists in PORTDIR's + # license directory. + for mypos in range(0,len(myuse)): + # Need to check for "||" manually as no portage + # function will remove it without removing values. + if myuse[mypos] not in liclist and myuse[mypos] != "||": + stats["LICENSE.invalid"]=stats["LICENSE.invalid"]+1 + fails["LICENSE.invalid"].append(x+"/"+y+".ebuild: %s" % myuse[mypos]) + + #keyword checks + myuse = myaux["KEYWORDS"].split() + for mykey in myuse: + myskey=mykey[:] + if myskey[0]=="-": + myskey=myskey[1:] + if myskey[0]=="~": + myskey=myskey[1:] + if mykey!="-*": + if myskey not in kwlist: + stats["KEYWORDS.invalid"] += 1 + fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s" % mykey) + elif not profiles.has_key(myskey): + stats["KEYWORDS.invalid"] += 1 + fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s (profile invalid)" % mykey) + + #syntax checks + myear = time.gmtime(os.stat(checkdir+"/"+y+".ebuild")[ST_MTIME])[0] + gentoo_copyright = re.compile(r'^# Copyright ((1999|200\d)-)?' + str(myear) + r' Gentoo Foundation') + gentoo_license = re.compile(r'^# Distributed under the terms of the GNU General Public License v2$') + cvs_header = re.compile(r'^#\s*\$Header.*\$$') + ignore_line = re.compile(r'(^$)|(^(\t)*#)') + leading_spaces = re.compile(r'^[\S\t]') + trailing_whitespace = re.compile(r'.*([\S]$)') + readonly_assignment = re.compile(r'^\s*(export\s+)?(A|P|PV|PN|PR|PVR|PF|D|WORKDIR|FILESDIR|FEATURES|USE)=') + continuation_symbol = re.compile(r'(.*[ ]+[\\][ ].*)') + line_continuation_quoted = re.compile(r'(\"|\')(([\w ,:;#\[\]\.`=/|\$\^\*{}()\'-])|(\\.))*\1') + line_continuation = re.compile(r'([^#]*\S)(\s+|\t)\\$') + linenum=0 + for line in input(checkdir+"/"+y+".ebuild"): + linenum += 1 + # Gentoo copyright check + if linenum == 1: + match = gentoo_copyright.match(line) + if not match: + myerrormsg = "Copyright header Error. Possibly date related." + stats["ebuild.badheader"] +=1 + fails["ebuild.badheader"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + # Gentoo license check + elif linenum == 2: + match = gentoo_license.match(line) + if not match: + myerrormsg = "Gentoo License Error." + stats["ebuild.badheader"] +=1 + fails["ebuild.badheader"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + # CVS Header check + elif linenum == 3: + match = cvs_header.match(line) + if not match: + myerrormsg = "CVS Header Error." + stats["ebuild.badheader"] +=1 + fails["ebuild.badheader"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + else: + match = ignore_line.match(line) + if not match: + # Excluded Blank lines and full line comments. Good! + # Leading Spaces Check + match = leading_spaces.match(line) + if not match: + #Line has got leading spaces. Bad! + myerrormsg = "Leading Space Syntax Error. Line %d" % linenum + stats["ebuild.minorsyn"] +=1 + fails["ebuild.minorsyn"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + # Trailing whitespace check + match = trailing_whitespace.match(line) + if not match: + #Line has got trailing whitespace. Bad! + myerrormsg = "Trailing whitespace Syntax Error. Line %d" % linenum + stats["ebuild.minorsyn"] +=1 + fails["ebuild.minorsyn"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + # Readonly variable assignment check + match = readonly_assignment.match(line) + if match: + # invalid assignment, very bad! + myerrormsg = "Readonly variable assignment to %s on line %d" % (match.group(2), linenum) + stats["variable.readonly"] += 1 + fails["variable.readonly"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + # Line continuation check + match = continuation_symbol.match(line) + if match: + #Excluded lines not even containing a " \" match. Good! + line = re.sub(line_continuation_quoted,"\"\"",line) + #line has been edited to collapsed "" and '' quotes to "". Good! + match = continuation_symbol.match(line) + if match: + #Again exclude lines not even containing a " \" match. Good! + #This repetition is done for a slight performance increase + match = line_continuation.match(line) + if not match: + #Line has a line continuation error. Bad! + myerrormsg = "Line continuation (\"\\\") Syntax Error. Line %d" % linenum + stats["ebuild.majorsyn"] +=1 + fails["ebuild.majorsyn"].append(x+"/"+y+".ebuild: %s" % myerrormsg) + + # Check for 'all unstable' or 'all masked' -- ACCEPT_KEYWORDS is stripped + # XXX -- Needs to be implemented in dep code. Can't determine ~arch nicely. + #if not portage.portdb.xmatch("bestmatch-visible",x): + # stats["ebuild.nostable"]+=1 + # fails["ebuild.nostable"].append(x) + if allmasked and repolevel == 3: + stats["ebuild.allmasked"]+=1 + fails["ebuild.allmasked"].append(x) + +#Pickle and save results for instant reuse in last and lfull +savef=open('/var/cache/edb/repo.stats','w') +pickle.dump(stats,savef) +savef.close() +savef=open('/var/cache/edb/repo.fails','w') +pickle.dump(fails,savef) +savef.close() +if not (os.stat('/var/cache/edb/repo.stats')[ST_GID] == getgrnam('portage')[2]): + os.chown('/var/cache/edb/repo.stats',os.geteuid(),getgrnam('portage')[2]) + os.chmod('/var/cache/edb/repo.stats',0664) +if not (os.stat('/var/cache/edb/repo.fails')[ST_GID] == getgrnam('portage')[2]): + os.chown('/var/cache/edb/repo.fails',os.geteuid(),getgrnam('portage')[2]) + os.chmod('/var/cache/edb/repo.fails',0664) +print +#dofail will be set to 1 if we have failed in at least one non-warning category +dofail=0 +#dowarn will be set to 1 if we tripped any warnings +dowarn=0 +#dofull will be set if we should print a "repoman full" informational message +dofull=0 +for x in qacats: + if not isCvs and (string.find(x, "notadded") != -1): + stats[x] = 0 + if stats[x]: + dowarn=1 + if x not in qawarnings: + dofail=1 + else: + continue + print " "+string.ljust(x,30), + if stats[x]==0: + print green(`stats[x]`) + continue + elif x in qawarnings: + print yellow(`stats[x]`) + else: + print red(`stats[x]`) + if mymode!="full": + if stats[x]<12: + for y in fails[x]: + print " "+y + else: + dofull=1 + else: + for y in fails[x]: + print " "+y +print + +def grouplist(mylist,seperator="/"): + """(list,seperator="/") -- Takes a list of elements; groups them into + same initial element categories. Returns a dict of {base:[sublist]} + From: ["blah/foo","spork/spatula","blah/weee/splat"] + To: {"blah":["foo","weee/splat"], "spork":["spatula"]}""" + mygroups={} + for x in mylist: + xs=string.split(x,seperator) + if xs[0]==".": + xs=xs[1:] + if xs[0] not in mygroups.keys(): + mygroups[xs[0]]=[string.join(xs[1:],seperator)] + else: + mygroups[xs[0]]+=[string.join(xs[1:],seperator)] + return mygroups + +if mymode!="commit": + if dofull: + print bold("Note: type \"repoman full\" for a complete listing.") + print + if dowarn and not dofail: + print green("RepoMan sez:"),"\"You're only giving me a partial QA payment?\nI'll take it this time, but I'm not happy.\"" + elif not dofail: + print green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\"" + print +else: + if dofail: + print turquoise("Please fix these important QA issues first.") + print green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n" + sys.exit(1) + + if "--pretend" in myoptions: + print green("RepoMan sez:"), "\"So, you want to play it safe. Good call.\"\n" + + if fails["digest.missing"]: + print green("Creating missing digests...") + for x in fails["digest.missing"]: + xs=string.split(x,"/") + del xs[-2] + myeb=string.join(xs[:-1],"/")+"/"+xs[-1][7:] + if "--pretend" in myoptions: + print "(ebuild "+portdir+"/"+myeb+".ebuild digest)" + else: + retval=os.system("ebuild "+portdir+"/"+myeb+".ebuild digest") + if retval: + print "!!! Exiting on ebuild digest (shell) error code:",retval + sys.exit(retval) + + mycvstree=cvstree.getentries("./",recursive=1) + if isCvs and not mycvstree: + print "!!! It seems we don't have a cvs tree?" + sys.exit(3) + + myunadded=cvstree.findunadded(mycvstree,recursive=1,basedir="./") + myautoadd=[] + if myunadded: + for x in range(len(myunadded)-1,-1,-1): + xs=string.split(myunadded[x],"/") + if xs[-1]=="files": + print "!!! files dir is not added! Please correct this." + sys.exit(-1) + elif xs[-1]=="Manifest": + # It's a manifest... auto add + myautoadd+=[myunadded[x]] + del myunadded[x] + elif len(xs[-1])>=7: + if xs[-1][:7]=="digest-": + del xs[-2] + myeb=string.join(xs[:-1]+[xs[-1][7:]],"/")+".ebuild" + if os.path.exists(myeb): + # Ebuild exists for digest... So autoadd it. + myautoadd+=[myunadded[x]] + del myunadded[x] + + if myautoadd: + print ">>> Auto-Adding missing digests..." + if "--pretend" in myoptions: + print "(/usr/bin/cvs add "+string.join(myautoadd)+")" + retval=0 + else: + retval=os.system("/usr/bin/cvs add "+string.join(myautoadd)) + if retval: + print "!!! Exiting on cvs (shell) error code:",retval + sys.exit(retval) + + if myunadded: + print red("!!! The following files are in your cvs tree but are not added to the master") + print red("!!! tree. Please remove them from the cvs tree or add them to the master tree.") + for x in myunadded: + print " ",x + print + print + sys.exit(1) + + mymissing=None + if mymissing: + print "The following files are obviously missing from your cvs tree" + print "and are being fetched so we can continue:" + for x in mymissing: + print " ",x + if "--pretend" in myoptions: + print "(/usr/bin/cvs -q up "+string.join(mymissing)+")" + retval=0 + else: + retval=os.system("/usr/bin/cvs -q up "+string.join(mymissing)) + if retval: + print "!!! Exiting on cvs (shell) error code:",retval + sys.exit(retval) + del mymissing + + retval=["",""] + if isCvs: + print "Performing a "+green("cvs -n up")+" with a little magic grep to check for updates." + retval=getstatusoutput("/usr/bin/cvs -n up 2>&1 | egrep '^[^\?] .*' | egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'") + + mylines=string.split(retval[1], "\n") + myupdates=[] + for x in mylines: + if not x: + continue + if x[0] not in "UPMAR": # Updates,Patches,Modified,Added,Removed + print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R are ok)") + print red("!!! Note: This is a pretend/no-modify pass...") + print retval[1] + print + sys.exit(1) + elif x[0] in ["U","P"]: + myupdates+=[x[2:]] + + if myupdates: + print green("Fetching trivial updates...") + if "--pretend" in myoptions: + print "(/usr/bin/cvs up "+string.join(myupdates)+")" + retval=0 + else: + retval=os.system("/usr/bin/cvs up "+string.join(myupdates)) + if retval!=0: + print "!!! cvs exited with an error. Terminating." + sys.exit(retval) + + if isCvs: + mycvstree=cvstree.getentries("./",recursive=1) + mychanged=cvstree.findchanged(mycvstree,recursive=1,basedir="./") + mynew=cvstree.findnew(mycvstree,recursive=1,basedir="./") + myremoved=cvstree.findremoved(mycvstree,recursive=1,basedir="./") + if not (mychanged or mynew or myremoved): + print + print green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\"\n" + print + print "(Didn't find any changed files...)" + print + sys.exit(0) + + myupdates=mychanged+mynew + myheaders=[] + mydirty=[] + headerstring="'\$(Header|Id)" + headerstring+=".*\$'" + for myfile in myupdates: + myout=getstatusoutput("egrep -q "+headerstring+" "+myfile) + if myout[0]==0: + myheaders.append(myfile) + + print "*",green(str(len(myupdates))),"files being committed...",green(str(len(myheaders))),"have headers that will change." + print "*","Files with headers will cause the manifests to be made and recommited." + print "myupdates:",myupdates + print "myheaders:",myheaders + print + unlinkfile=0 + if not (commitmessage or commitmessagefile): + print "Please enter a CVS commit message at the prompt:" + while not commitmessage: + try: + commitmessage=raw_input(green("> ")) + except KeyboardInterrupt: + exithandler() + try: + commitmessage+="\n(Portage version: "+str(portage.VERSION)+")" + except: + print "Failed to insert portage version in message!" + commitmessage+="\n(Portage version: Unknown)" + if not commitmessagefile: + unlinkfile=1 + commitmessagefile=tempfile.mktemp(".repoman.msg") + if os.path.exists(commitmessagefile): + os.unlink(commitmessagefile) + mymsg=open(commitmessagefile,"w") + mymsg.write(commitmessage) + mymsg.close() + + print + print green("Using commit message:") + print green("------------------------------------------------------------------------------") + print commitmessage + print green("------------------------------------------------------------------------------") + print + + if "--pretend" in myoptions: + print "(/usr/bin/cvs -q commit -F "+commitmessagefile+")" + retval=0 + else: + retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile) + if retval: + print "!!! Exiting on cvs (shell) error code:",retval + sys.exit(retval) + + # Setup the GPG commands + def gpgsign(filename): + gpgcmd = "gpg --sign --clearsign --yes " + gpgcmd+= "--default-key "+repoman_settings["PORTAGE_GPG_KEY"] + if repoman_settings.has_key("PORTAGE_GPG_DIR"): + gpgcmd += " --homedir "+repoman_settings["PORTAGE_GPG_DIR"] + rValue = os.system(gpgcmd+" "+filename) + if rValue == 0: + os.rename(filename+".asc", filename) + else: + print "!!! gpg exited with '" + str(rValue) + "' status" + return rValue + + if myheaders or myupdates or myremoved or mynew: + myfiles=myheaders+myupdates+myremoved+mynew + for x in range(len(myfiles)-1, -1, -1): + if myfiles[x].count("/") < 4-repolevel: + del myfiles[x] + mydone=[] + if repolevel==3: # In a package dir + repoman_settings["O"]="./" + portage.digestgen([],repoman_settings,manifestonly=1) + elif repolevel==2: # In a category dir + for x in myfiles: + xs=string.split(x,"/") + if xs[0]==".": + xs=xs[1:] + if xs[0] in mydone: + continue + mydone.append(xs[0]) + repoman_settings["O"]="./"+xs[0] + portage.digestgen([],repoman_settings,manifestonly=1) + elif repolevel==1: # repo-cvsroot + print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n" + for x in myfiles: + xs=string.split(x,"/") + if xs[0]==".": + xs=xs[1:] + if string.join(xs[:2],"/") in mydone: + continue + mydone.append(string.join(xs[:2],"/")) + repoman_settings["O"]="./"+string.join(xs[:2],"/") + portage.digestgen([],repoman_settings,manifestonly=1) + else: + print red("I'm confused... I don't know where I am!") + sys.exit(1) + + if "--pretend" in myoptions: + print "(/usr/bin/cvs -q commit -F "+commitmessagefile+")" + else: + mymsg=open(commitmessagefile,"w") + mymsg.write(commitmessage) + mymsg.write("\n (Unsigned Manifest commit)") + mymsg.close() + retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile) + if retval: + print "!!! Exiting on cvs (shell) error code:",retval + sys.exit(retval) + + if "sign" in portage.features: + mydone=[] + if repolevel==3: # In a package dir + repoman_settings["O"]="./" + while(gpgsign(repoman_settings["O"]+"/Manifest")): + portage.writemsg("!!! YOU MUST sign the Manifest.\n") + portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'") + time.sleep(3) + elif repolevel==2: # In a category dir + for x in myfiles: + xs=string.split(x,"/") + if xs[0]==".": + xs=xs[1:] + if xs[0] in mydone: + continue + mydone.append(xs[0]) + repoman_settings["O"]="./"+xs[0] + while(gpgsign(repoman_settings["O"]+"/Manifest")): + portage.writemsg("!!! YOU MUST sign the Manifest.\n") + portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'") + time.sleep(3) + elif repolevel==1: # repo-cvsroot + print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n" + for x in myfiles: + xs=string.split(x,"/") + if xs[0]==".": + xs=xs[1:] + if string.join(xs[:2],"/") in mydone: + continue + mydone.append(string.join(xs[:2],"/")) + repoman_settings["O"]="./"+string.join(xs[:2],"/") + while(gpgsign(repoman_settings["O"]+"/Manifest")): + portage.writemsg("!!! YOU MUST sign the Manifest.\n") + portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'") + time.sleep(3) + + if "--pretend" in myoptions: + print "(/usr/bin/cvs -q commit -F "+commitmessagefile+")" + else: + mymsg=open(commitmessagefile,"w") + mymsg.write(commitmessage) + mymsg.write("\n (Signed Manifest commit)") + mymsg.close() + retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile) + if retval: + print "!!! Exiting on cvs (shell) error code:",retval + sys.exit(retval) + + if unlinkfile: + os.unlink(commitmessagefile) + print + if isCvs: + print "CVS commit complete." + else: + print "repoman was too scared by not seeing any familiar cvs file that he forgot to commit anything" + print green("RepoMan sez:"), "\"If everyone were like you, I'd be out of business!\"\n" +sys.exit(0) + diff --git a/bin/xpak b/bin/xpak new file mode 100755 index 000000000..03228c14a --- /dev/null +++ b/bin/xpak @@ -0,0 +1,14 @@ +#!/usr/bin/python -O +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-src/portage/bin/xpak,v 1.10 2004/10/04 13:56:50 vapier Exp $ + +import sys +if len(sys.argv)!=3: + print "xpak: expecting three arguments." + sys.exit(1) + +sys.path = ["/usr/lib/portage/pym"]+sys.path + +import xpak +xpak.xpak(sys.argv[1],sys.argv[2]) |