Merged from trunk 6868:6889
authorFabian Groffen <grobian@gentoo.org>
Fri, 22 Jun 2007 08:42:54 +0000 (08:42 -0000)
committerFabian Groffen <grobian@gentoo.org>
Fri, 22 Jun 2007 08:42:54 +0000 (08:42 -0000)
   +------------------------------------------------------------------------+
   | 6869    | Add PORTAGE_BIN_PATH to the environment since it's used by   |
   | zmedico | dobin to locate isolated-functions.sh.                       |
   |---------+--------------------------------------------------------------|
   | 6870    | Add a test case for the logfile functionality of             |
   | zmedico | portage.spawn().                                             |
   |---------+--------------------------------------------------------------|
   | 6871    | For bug #182428, make quickpkg use a more secure umask by    |
   | zmedico | default and allow it to be overridden by a --umask option.   |
   |         | Add support for QUICKPKG_DEFAULT_OPTS so that default        |
   |         | options can be set in make.conf.                             |
   |---------+--------------------------------------------------------------|
   | 6873    | For bug #182571, handle curses.error if it's thrown inside   |
   | zmedico | get_term_size().                                             |
   |---------+--------------------------------------------------------------|
   | 6875    | Return early from get_term_size() is stdout is not a tty.    |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 6877    | For bug #143340, give an appropriate message when there is   |
   | zmedico | no read access to a binary package.                          |
   |---------+--------------------------------------------------------------|
   | 6879    | Fix cacheddir() to behave properly if os.listdir() raises    |
   | zmedico | errno.EACCES (Permission denied).                            |
   |---------+--------------------------------------------------------------|
   | 6881    | For bug #180165, make portageq print a "Permission denied"   |
   | zmedico | error when appropriate. A PermissionDenied exception is      |
   |         | raised from portage.listdir() enven when EmptyOnError is     |
   |         | True since errno.EACCES is very likely to indicate a         |
   |         | condition that should be reported in any case.               |
   |---------+--------------------------------------------------------------|
   | 6882    | For bug #180165, make has_version dir if portageq has an     |
   | zmedico | unexpected exit code.                                        |
   |---------+--------------------------------------------------------------|
   | 6883    | If a package is in the world set but it's not installed, go  |
   | zmedico | ahead and install it if it's available (instead of telling   |
   |         | the user to run emaint).                                     |
   |---------+--------------------------------------------------------------|
   | 6886    | Make all the classes inherit from object.                    |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 6887    | Show a "world problems" warning for packages that aren't     |
   | zmedico | installed, even if they are available.                       |
   |---------+--------------------------------------------------------------|
   | 6889    | Make the progress bar percentage indicator stop at 100%      |
   | zmedico | instead of just 99%.                                         |
   +------------------------------------------------------------------------+

svn path=/main/branches/prefix/; revision=6943

16 files changed:
bin/ebuild.sh
bin/emerge
bin/portageq
bin/quickpkg
pym/emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/bintree.py
pym/portage/eclass_cache.py
pym/portage/exception.py
pym/portage/gpg.py
pym/portage/output.py
pym/portage/tests/__init__.py
pym/portage/tests/bin/setup_env.py
pym/portage/tests/ebuild/__init__.py [new file with mode: 0644]
pym/portage/tests/ebuild/test_spawn.py [new file with mode: 0644]
pym/portage/xpak.py

index 66d86818cc466d26a284b9edc338e0a5070c3679..bb17ad89aad8e4e38c987363d2118fcd38965793 100755 (executable)
@@ -67,7 +67,7 @@ unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE
 export PATH="${DEFAULT_PATH}:${PORTAGE_BIN_PATH}:${ROOTPATH}"
 [ ! -z "$PREROOTPATH" ] && export PATH="${PREROOTPATH%%:}:$PATH"
 
-source "@PORTAGE_BASE@"/bin/isolated-functions.sh &>/dev/null
+source "${PORTAGE_BIN_PATH}/isolated-functions.sh"  &>/dev/null
 
 OCC="$CC"
 OCXX="$CXX"
@@ -182,18 +182,26 @@ has_version() {
        fi
        # return shell-true/shell-false if exists.
        # Takes single depend-type atoms.
-       if "@PORTAGE_BASE@"/bin/portageq 'has_version' "${ROOT}" "$1"; then
-               return 0
-       else
-               return 1
-       fi
+       "${PORTAGE_BIN_PATH}"/portageq has_version "${ROOT}" "$1"
+       local retval=$?
+       case "${retval}" in
+               0)
+                       return 0
+                       ;;
+               1)
+                       return 1
+                       ;;
+               *)
+                       die "unexpected portageq exit code: ${retval}"
+                       ;;
+       esac
 }
 
 portageq() {
        if [ "${EBUILD_PHASE}" == "depend" ]; then
                die "portageq calls are not allowed in the global scope"
        fi
-       "@PORTAGE_BASE@"/bin/portageq "$@"
+       "${PORTAGE_BIN_PATH}/portageq" "$@"
 }
 
 
@@ -208,7 +216,7 @@ best_version() {
        fi
        # returns the best/most-current match.
        # Takes single depend-type atoms.
-       "@PORTAGE_BASE@"/bin/portageq 'best_version' "${ROOT}" "$1"
+       "${PORTAGE_BIN_PATH}/portageq" 'best_version' "${ROOT}" "$1"
 }
 
 use_with() {
@@ -499,7 +507,7 @@ econf() {
 
                if ! ${CONFCACHE} ${CONFCACHE_ARG} ${TMP_CONFCACHE_DIR} "${ECONF_SOURCE}/configure" \
                        --prefix="${EPREFIX}"/usr \
-                       --host="${CHOST}" \
+                       --host=${CHOST} \
                        --mandir="${EPREFIX}"/usr/share/man \
                        --infodir="${EPREFIX}"/usr/share/info \
                        --datadir="${EPREFIX}"/usr/share \
@@ -1650,9 +1658,9 @@ if [ -n "${myarg}" ] && \
        unset myarg
        # Save current environment and touch a success file. (echo for success)
        umask 002
-       set | @EGREP@ -v "^SANDBOX_" > "${T}/environment" 2>/dev/null
-       export | @EGREP@ -v "^declare -x SANDBOX_" | \
-               @SED@ 's:^declare -rx:declare -x:' >> "${T}/environment" 2>/dev/null
+       set | egrep -v "^SANDBOX_" > "${T}/environment" 2>/dev/null
+       export | egrep -v "^declare -x SANDBOX_" | \
+               sed 's:^declare -rx:declare -x:' >> "${T}/environment" 2>/dev/null
        chown ${PORTAGE_USER:-portage}:${PORTAGE_GROUP:-portage} "${T}/environment" &>/dev/null
        chmod g+w "${T}/environment" &>/dev/null
 fi
index 74262f11c92b618a31ad3c96beab99721acefb91..13bc5f3946ed81add9bb6f843884d1d510346307 100755 (executable)
@@ -13,4 +13,10 @@ except ImportError:
 
 if __name__ == "__main__":
        import sys
-       sys.exit(emerge_main())
+       from portage.exception import PermissionDenied
+       try:
+               retval = emerge_main()
+       except PermissionDenied, e:
+               sys.stderr.write("Permission denied: '%s'\n" % str(e))
+               sys.exit(e.errno)
+       sys.exit(retval)
index 16c0c67c61c57a20037e18e3302cc640f81e7aaa..653bcf229f40d58085196469ad5126cd131db5b1 100755 (executable)
@@ -373,6 +373,9 @@ def main():
        except KeyError:
                usage(sys.argv)
                sys.exit(os.EX_USAGE)
+       except portage.exception.PermissionDenied, e:
+               sys.stderr.write("Permission denied: '%s'\n" % str(e))
+               sys.exit(e.errno)
 
 main()
 
index ba311694159e3581c51e8378336d41fdb82370ce..0dd9c7fc824a7e05353e5b31a70d11b9cc915c48 100755 (executable)
@@ -121,11 +121,20 @@ if __name__ == "__main__":
        usage = "Usage: quickpkg [options] <list of package atoms>"
        from optparse import OptionParser
        parser = OptionParser(usage=usage)
-       options, args = parser.parse_args(sys.argv[1:])
+       parser.add_option("--umask",
+               default="0077",
+               help="umask used during package creation (default is 0077)")
+       from portage import settings
+       default_opts = settings.get("QUICKPKG_DEFAULT_OPTS","").split()
+       options, args = parser.parse_args(default_opts + sys.argv[1:])
        if not args:
                parser.error("no packages atoms given")
+       try:
+               umask = int(options.umask, 8)
+       except ValueError:
+               parser.error("invalid umask: %s" % options.umask)
        # We need to ensure a sane umask for the packages that will be created.
-       old_umask = os.umask(022)
+       old_umask = os.umask(umask)
        from portage.output import get_term_size, EOutput
        eout = EOutput()
        def sigwinch_handler(signum, frame):
index eab3fcd9ef11e03e2bf38ce403be79feeb53c40e..23d29c6bbbdda52339c0fa76c523a8f57a333e72 100644 (file)
@@ -363,7 +363,7 @@ def create_depgraph_params(myopts, myaction):
        return myparams
 
 # search functionality
-class search:
+class search(object):
 
        #
        # class constants
@@ -911,7 +911,7 @@ def show_invalid_depstring_notice(parent_node, depstring, error_msg):
                f.add_flowing_data(x)
        f.end_paragraph(1)
 
-class depgraph:
+class depgraph(object):
 
        pkg_tree_map = {
                "ebuild":"porttree",
@@ -2218,10 +2218,22 @@ class depgraph:
                        for x in worlddict.keys():
                                if not portage.isvalidatom(x):
                                        world_problems = True
-                               elif not self.trees[self.target_root]["vartree"].dbapi.match(x):
+                                       continue
+                               elif not vardb.match(x):
                                        world_problems = True
-                               else:
-                                       mylist.append(x)
+                                       available = False
+                                       if "--usepkgonly" not in self.myopts and \
+                                               portdb.match(x):
+                                               available = True
+                                       elif "--usepkg" in self.myopts:
+                                               mymatches = bindb.match(x)
+                                               if "--usepkgonly" not in self.myopts:
+                                                       mymatches = visible(mymatches)
+                                               if mymatches:
+                                                       available = True
+                                       if not available:
+                                               continue
+                               mylist.append(x)
 
                newlist = []
                for atom in mylist:
index ec84a80b4be3860f1852f850c02e64abf09ee6b5..bd27baa7caa43f207930e51a6369589944d2c262 100644 (file)
@@ -186,7 +186,14 @@ def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymli
                        mtime = pathstat[stat.ST_MTIME]
                else:
                        raise portage.exception.DirectoryNotFound(mypath)
-       except (IOError,OSError,portage.exception.PortageException):
+       except EnvironmentError, e:
+               if e.errno == portage.exception.PermissionDenied.errno:
+                       raise portage.exception.PermissionDenied(mypath)
+               del e
+               if EmptyOnError:
+                       return [], []
+               return None, None
+       except portage.exception.PortageException:
                if EmptyOnError:
                        return [], []
                return None, None
@@ -194,7 +201,13 @@ def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymli
        if mtime != cached_mtime or time.time() - mtime < 4:
                if dircache.has_key(mypath):
                        cacheStale += 1
-               list = os.listdir(mypath)
+               try:
+                       list = os.listdir(mypath)
+               except EnvironmentError, e:
+                       if e.errno != errno.EACCES:
+                               raise
+                       del e
+                       raise portage.exception.PermissionDenied(mypath)
                ftype = []
                for x in list:
                        try:
@@ -304,7 +317,7 @@ def flatten(mytokens):
 
 #beautiful directed graph object
 
-class digraph:
+class digraph(object):
        def __init__(self):
                """Create an empty digraph"""
                
@@ -806,10 +819,10 @@ def autouse(myvartree, use_cache=1, mysettings=None):
        return myusevars
 
 def check_config_instance(test):
-       if not test or (str(test.__class__) != 'portage.config'):
-               raise TypeError, "Invalid type for config object: %s" % test.__class__
+       if not isinstance(test, config):
+               raise TypeError("Invalid type for config object: %s" % test.__class__)
 
-class config:
+class config(object):
        """
        This class encompasses the main portage configuration.  Data is pulled from
        ROOT/PORTDIR/profiles/, from ROOT/etc/make.profile incrementally through all 
index 7fb58748f0b40c0486e84fdf5524fb93b4e4b22e..713a8c612738e0098197af460be2193574487132 100644 (file)
@@ -429,6 +429,12 @@ class binarytree(object):
                                                                        aux_cache[k] = d[k]
                                                                self.dbapi._aux_cache[mycpv] = aux_cache
                                                        continue
+                                       if not os.access(full_path, os.R_OK):
+                                               writemsg("!!! Permission denied to read " + \
+                                                       "binary package: '%s'\n" % full_path,
+                                                       noiselevel=-1)
+                                               self.invalids.append(myfile[:-5])
+                                               continue
                                        mytbz2 = portage.xpak.tbz2(full_path)
                                        # For invalid packages, mycat could be None.
                                        mycat = mytbz2.getfile("CATEGORY")
index 40d4e360f46f6936cde2d4f674332198ae70ae33..5a0d3c3ad0d2a48ce653b827e96d71dbc8274fbf 100644 (file)
@@ -7,7 +7,7 @@ from portage.util import normalize_path, writemsg
 import os, sys
 from portage.data import portage_gid
 
-class cache:
+class cache(object):
        """
        Maintains the cache information about eclasses used in ebuild.
        """
index 7d5ca82c2c8c231b0c48652c037bde42d21ba22b..11b455e97a89d7619b7d9712a3d5c81e4dde4e40 100644 (file)
@@ -53,6 +53,7 @@ class OperationNotPermitted(PortageException):
        """An operation was not permitted operating system"""
 
 class PermissionDenied(PortageException):
+       from errno import EACCES as errno
        """Permission denied"""
 
 class ReadOnlyFileSystem(PortageException):
index d3061c5f959085e20522258c57e124334c03b282..5c8a856b16bd2f4011059a52dfd7251858b46c2f 100644 (file)
@@ -30,7 +30,7 @@ def fileStats(filepath):
        return mya
 
 
-class FileChecker:
+class FileChecker(object):
        def __init__(self,keydir=None,keyring=None,requireSignedRing=False,minimumTrust=EXISTS):
                self.minimumTrust     = TRUSTED  # Default we require trust. For rings.
                self.keydir           = None
index 7efde92a957741d2b5d77afe33a70631ed05389f..33223d5b4ac598913d55b409d509ff6d6ae1c84b 100644 (file)
@@ -256,10 +256,15 @@ def get_term_size():
        occurs. The curses module is used if available, otherwise the output of
        `stty size` is parsed.
        """
+       if not sys.stdout.isatty():
+               return -1, -1
        try:
                import curses
-               curses.setupterm()
-               return curses.tigetnum('lines'), curses.tigetnum('cols')
+               try:
+                       curses.setupterm()
+                       return curses.tigetnum('lines'), curses.tigetnum('cols')
+               except curses.error:
+                       pass
        except ImportError:
                pass
        st, out = commands.getstatusoutput('stty size')
@@ -281,7 +286,7 @@ def set_term_size(lines, columns, fd):
        cmd = ["stty", "rows", str(lines), "columns", str(columns)]
        spawn(cmd, env=os.environ, fd_pipes={0:fd})
 
-class EOutput:
+class EOutput(object):
        """
        Performs fancy terminal formatting for status and informational messages.
 
@@ -518,9 +523,11 @@ class TermProgressBar(ProgressBar):
                curval = self._curval
                maxval = self._maxval
                position = self._position
-               if cols < 3:
+               percentage_str_width = 4
+               square_brackets_width = 2
+               if cols < percentage_str_width:
                        return ""
-               bar_space = cols - 6
+               bar_space = cols - percentage_str_width - square_brackets_width
                if maxval == 0:
                        max_bar_width = bar_space-3
                        image = "    "
@@ -545,11 +552,12 @@ class TermProgressBar(ProgressBar):
                                "<=>" + ((max_bar_width - bar_width) * " ") + "]"
                        return image
                else:
-                       max_bar_width = bar_space-1
                        percentage = int(100 * float(curval) / maxval)
                        if percentage == 100:
-                               percentage = 99
-                       image = ("%d%% " % percentage).rjust(4)
+                               percentage_str_width += 1
+                               bar_space -= 1
+                       max_bar_width = bar_space - 1
+                       image = ("%d%% " % percentage).rjust(percentage_str_width)
                        if cols < min_columns:
                                return image
                        offset = float(curval) / maxval
index 60a19de6c4ad88cb5ed56745b1c7642dff68803b..e3702e08e9e1937bfff4cfdcbb7a873fa9c2f332 100644 (file)
@@ -7,7 +7,8 @@ import os, sys, time, unittest
 import portage.tests
 
 def main():
-       testDirs = ["bin", "util","versions", "dep", "xpak", "env/config"]
+       testDirs = ["bin", "dep", "ebuild",
+               "env/config", "util", "versions", "xpak"]
        suite = unittest.TestSuite()
        basedir = os.path.dirname(__file__)
        for mydir in testDirs:
index 1f249170176bf92fe2619acf11e5ac7b2e244686..274d7265486394f942295cab7162dc677fc983da 100644 (file)
@@ -7,6 +7,7 @@ import os, shutil, sys
 from os.path import dirname, abspath, join
 from portage.tests import TestCase
 from portage.process import spawn
+from portage.const import PORTAGE_BIN_PATH
 
 bindir = join(dirname(dirname(abspath(__file__))), "..", "..", "..", "bin")
 basedir = join(dirname(dirname(abspath(__file__))), "bin", "root")
@@ -15,6 +16,7 @@ os.environ["T"] = os.path.join(basedir, "temp")
 os.environ["S"] = os.path.join(basedir, "workdir")
 os.environ["PF"] = "portage-tests-0.09-r1"
 os.environ["PATH"] = bindir + ":" + os.environ["PATH"]
+os.environ["PORTAGE_BIN_PATH"] = PORTAGE_BIN_PATH
 
 def binTestsCleanup():
        if os.access(basedir, os.W_OK):
diff --git a/pym/portage/tests/ebuild/__init__.py b/pym/portage/tests/ebuild/__init__.py
new file mode 100644 (file)
index 0000000..d67b0cd
--- /dev/null
@@ -0,0 +1,3 @@
+# Copyright 1998-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
diff --git a/pym/portage/tests/ebuild/test_spawn.py b/pym/portage/tests/ebuild/test_spawn.py
new file mode 100644 (file)
index 0000000..66e8f9e
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright 1998-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+import errno, os, sys
+from portage.tests import TestCase
+
+class SpawnTestCase(TestCase):
+
+       def testLogfile(self):
+               from portage import settings, spawn
+               from tempfile import mkstemp
+               logfile = None
+               try:
+                       fd, logfile = mkstemp()
+                       os.close(fd)
+                       null_fd = os.open('/dev/null', os.O_RDWR)
+                       test_string = 2 * "blah blah blah\n"
+                       spawn("echo -n '%s'" % test_string, settings, logfile=logfile,
+                               fd_pipes={0:sys.stdin.fileno(), 1:null_fd, 2:null_fd})
+                       os.close(null_fd)
+                       f = open(logfile, 'r')
+                       log_content = f.read()
+                       f.close()
+                       # When logging passes through a pty, it's lines will be separated
+                       # by '\r\n', so use splitlines before comparing results.
+                       self.assertEqual(test_string.splitlines(),
+                               log_content.splitlines())
+               finally:
+                       if logfile:
+                               try:
+                                       os.unlink(logfile)
+                               except EnvironmentError, e:
+                                       if e.errno != errno.ENOENT:
+                                               raise
+                                       del e
index 2700bef09b908c00ed5a20225490458997f78810..e3588ab728f085ca0ea909f7eeb0091cb8e636c2 100644 (file)
@@ -224,7 +224,7 @@ def xpand(myid,mydest):
                startpos=startpos+namelen+12
        os.chdir(origdir)
 
-class tbz2:
+class tbz2(object):
        def __init__(self,myfile):
                self.file=myfile
                self.filestat=None