Merge branch 'master' of git+ssh://git.overlays.gentoo.org/proj/portage into public_api
diff --git a/.gitignore b/.gitignore
index 539da74..808cc0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 *.py[co]
+/pym/portage/public_api.bz2
+/testpath
diff --git a/pym/portage/api/__init__.py b/pym/portage/api/__init__.py
new file mode 100644
index 0000000..8fbd38f
--- /dev/null
+++ b/pym/portage/api/__init__.py
@@ -0,0 +1,2 @@
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
diff --git a/pym/portage/api/actions.py b/pym/portage/api/actions.py
new file mode 100644
index 0000000..e8fa287
--- /dev/null
+++ b/pym/portage/api/actions.py
@@ -0,0 +1,7 @@
+#!/usr/bin/python
+#
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Portage API emerge actions for consumer apps."""
+
diff --git a/pym/portage/api/data_connect.py b/pym/portage/api/data_connect.py
new file mode 100644
index 0000000..825cb45
--- /dev/null
+++ b/pym/portage/api/data_connect.py
@@ -0,0 +1,643 @@
+#!/usr/bin/python
+#
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Portage API data connection for consumer apps.  """
+
+import os.path
+import logging
+
+import portage
+from portage import pkgsplit
+from portage.api.settings import default_settings
+from portage.dep import Atom
+from portage import manifest #, catpkgsplit
+from portage.api.flag import get_flags
+from portage.api.properties import Properties
+from portage.util import writemsg_level #, grabfile
+
+
+def ensure_settings(root, settings):
+    """Internal function to check  that root and settings
+    are not None and if so, then return their default values"""
+    if settings is None:
+        settings = default_settings
+    if root is None:
+        root = settings.settings["ROOT"]
+    return root, settings
+
+
+def get_path(cpv, file=None, vardb=True, root=None, settings=None):
+    """Returns a path to the specified category/package-version in
+    either the vardb or portdb
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type file: string
+    @param file:
+    @param vardb: bool, defaults to  True
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype string
+    @return '/path/to/file'
+    """
+    root, settings = ensure_settings(root, settings)
+    if vardb:
+        return settings.vardb[root].getpath(cpv, file)
+    else:
+        if '/' not in cpv:
+            return ''
+        try:
+            dir, ovl = settings.portdb[root].findname2(cpv)
+        except:
+            dir = ''
+        return dir
+
+
+def xmatch(root, settings, *args, **kwargs):
+    """Pass arguments on to portage's caching match function.
+    xmatch('match-all',package-name) returns all ebuilds of <package-name> in a list,
+    xmatch('match-visible',package-name) returns non-masked ebuilds,
+    xmatch('match-list',package-name,mylist=list) checks for <package-name> in <list>
+    There are more possible arguments.
+    package-name may be, for example:
+       gnome-base/control-center            ebuilds for gnome-base/control-center
+       control-center                       ebuilds for gnome-base/control-center
+       >=gnome-base/control-center-2.8.2    only ebuilds with version >= 2.8.2
+
+    @type root: string
+    @param root: tree root to use
+    @param settings: portage config settings instance.
+    @param args:  The arument to pass to the dbapi.xmatch()
+    @param kwargs: the extra arguments to pass to dbapi.xmatch()
+    @rtype list
+    @return: list of matches
+    """
+    results  =  settings.portdb[root].xmatch(*args, **kwargs)
+    return results
+
+
+def get_versions(cp, include_masked=True, root=None, settings=None):
+    """Returns all available ebuilds for the package
+
+    @type cp: string
+    @param cp:  'cat/pkg'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype
+    @return
+    """
+    root, settings = ensure_settings(root, settings)
+    # Note: this is slow, especially when include_masked is false
+    criterion = include_masked and 'match-all' or 'match-visible'
+    results = xmatch(root, settings, criterion, str(cp))
+    #writemsg_level("DATA_CONNECT: get_versions(); criterion = %s,
+        #package = %s, results = %s" %(str(criterion),cp,str(results)),
+        #level=logging.DEBUG)
+    return  results
+
+
+def get_hard_masked(cp, root=None, settings=None):
+    """
+
+    @type cp: string
+    @param cp:  'cat/pkg'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype tuple
+    @return (hard_masked_nocheck, hardmasked)
+    """
+    root, settings = ensure_settings(root, settings)
+    cp = str(cp)
+    hardmasked = []
+    try: # newer portage
+        pmaskdict = settings.portdb[root].settings.pmaskdict[cp]
+    except KeyError:
+        pmaskdict = {}
+    for x in pmaskdict:
+        m = xmatch(root, settings, "match-all", x)
+        for n in m:
+            if n not in hardmasked:
+                hardmasked.append(n)
+    hard_masked_nocheck = hardmasked[:]
+    try: # newer portage
+        punmaskdict = settings.portdb[root].settings.punmaskdict[cp]
+    except KeyError:
+        punmaskdict = {}
+    for x in punmaskdict:
+        m = xmatch(root, settings, "match-all", x)
+        for n in m:
+            while n in hardmasked: hardmasked.remove(n)
+    return hard_masked_nocheck, hardmasked
+
+
+def get_installed_files(cpv, root=None, settings=None):
+    """Get a list of installed files for an ebuild, assuming it has
+    been installed.
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype list of strings
+    """
+    root, settings = ensure_settings(root, settings)
+    cat, pv = portage.versions.catsplit(cpv)
+    db = portage.dblink(cat, pv, root,
+            settings.settings, treetype="vartree",
+            vartree=settings.vardb[root])
+    contents = db.getcontents()
+    if not contents:
+        return ["None"]
+    return sorted(contents)
+
+
+def best(versions):
+    """returns the best version in the list of supplied versions
+
+    @type versions: list of strings
+    @param versions: a list of cpv's
+    @rtype str
+    """
+    return portage.best(versions)
+
+
+def get_best_ebuild(cp, root=None, settings=None):
+    """returns the best available cpv
+
+    @type cp: string
+    @param cp: 'cat/pkg'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype str
+    """
+    root, settings = ensure_settings(root, settings)
+    return xmatch(root, settings, "bestmatch-visible", cp)
+
+
+def get_dep_ebuild(dep, root=None, settings=None):
+    """Progresively checks for available ebuilds that match the dependency.
+    returns what it finds as up to three options.
+
+    @type dep: string
+    @param dep: a valid dependency
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype set
+    @return  best_ebuild, keyworded_ebuild, masked_ebuild
+    """
+    root, settings = ensure_settings(root, settings)
+    #writemsg_level("DATA_CONNECT: get_dep_ebuild(); dep = " + \
+        #dep, level=logging.DEBUG)
+    best_ebuild = keyworded_ebuild = masked_ebuild = ''
+    best_ebuild = xmatch(root, settings, "bestmatch-visible", dep)
+    if best_ebuild == '':
+        #writemsg_level("DATA_CONNECT: get_dep_ebuild(); "
+            #"checking masked packages", level=logging.DEBUG)
+        atomized_dep = Atom(dep)
+        hardmasked_nocheck, hardmasked = get_hard_masked(atomized_dep.cpv)
+        matches = xmatch(root, settings, "match-all", dep)[:]
+        masked_ebuild = best(matches)
+        keyworded = []
+        for m in matches:
+            if m not in hardmasked:
+                keyworded.append(m)
+        keyworded_ebuild = best(keyworded)
+    #writemsg_level("DATA_CONNECT: get_dep_ebuild(); ebuilds = " + \
+        #str([best_ebuild, keyworded_ebuild, masked_ebuild]),
+        #level=logging.DEBUG)
+    return best_ebuild, keyworded_ebuild, masked_ebuild
+
+
+def get_virtual_dep(atom, settings=None):
+    """Returns the first (prefered) resolved virtual dependency
+    if there is more than 1 possible resolution
+
+    @param atom: dependency string
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtpye: string
+    @return 'cat/pkg-ver'
+    """
+    if settings is None:
+        settings = default_settings
+    return settings.settings.getvirtuals()[atom][0]
+
+
+def get_masking_status(cpv):
+    """Gets the current masking status
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @rtype str
+    """
+    try:
+        status = portage.getmaskingstatus(cpv)
+    except KeyError:
+        status = ['unavailable']
+    return status
+
+
+def get_masking_reason(cpv, root=None, settings=None):
+    """Strips trailing \n from, and returns the masking reason given by portage
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype str
+    """
+    root, settings = ensure_settings(root, settings)
+    reason, location = portage.getmaskingreason(
+        cpv, settings=settings.settings, portdb=settings.portdb[root],
+        return_location=True)
+    if not reason:
+        reason = 'No masking reason given.'
+        status =  get_masking_status(cpv)
+        if 'profile' in status:
+            reason = "Masked by the current profile."
+            status.remove('profile')
+        if status:
+            reason += " from " + ', '.join(status)
+    if location != None:
+        reason += "in file: " + location
+    if reason.endswith("\n"):
+        reason = reason[:-1]
+    return reason
+
+
+def get_size(cpv, formatted_string=True, root=None, settings=None):
+    """ Returns size of package to fetch.
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @param formatted_string: defaults to True
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype str, or int
+    """
+    root, settings = ensure_settings(root, settings)
+    #This code to calculate size of downloaded files
+    # was taken from /usr/bin/emerge - BB
+    #writemsg_level( "DATA_CONNECT: get_size; cpv = " + \
+        #cpv, level=logging.DEBUG)
+    total = [0,'']
+    ebuild = settings.portdb[root].findname(cpv)
+    pkgdir = os.path.dirname(ebuild)
+    mf = manifest.Manifest(pkgdir, settings.settings["DISTDIR"])
+    iuse, final_use = get_flags(cpv, final_setting=True,
+        root=root, settings=default_settings)
+    #writemsg_level( "DATA_CONNECT: get_size; Attempting to get "
+        #"fetchlist final use= " + str(final_use), level=logging.DEBUG)
+    try:
+        fetchlist = settings.portdb[root].getFetchMap(cpv, set(final_use))
+        #writemsg_level( "DATA_CONNECT: get_size; fetchlist= " + \
+            #str(fetchlist), level=logging.DEBUG)
+        #writemsg_level( "DATA_CONNECT: get_size; mf.getDistfilesSize()",
+            #level=logging.DEBUG)
+        total[0] = mf.getDistfilesSize(fetchlist)
+        if formatted_string:
+            total_str = str(total[0]/1024)
+            #writemsg_level( "DATA_CONNECT: get_size; total_str = " + \
+                #total_str, level=logging.DEBUG)
+            count = len(total_str)
+            while (count > 3):
+                count -= 3
+                total_str = total_str[:count]+","+total_str[count:]
+            total[1] = total_str+" kB"
+    except KeyError as e:
+        total[1] = "Unknown (missing digest)"
+        total[0] = 0
+        writemsg_level( "DATA_CONNECT: get_size; Exception: " + str(e),
+            level=logging.DEBUG)
+        writemsg_level( "DATA_CONNECT: get_size; cpv: " + str(cpv),
+            level=logging.DEBUG)
+        writemsg_level( "DATA_CONNECT: get_size; fetchlist = " + \
+            str(fetchlist), level=logging.DEBUG)
+    #writemsg_level( "DATA_CONNECT: get_size; returning total[1] = " \
+        #+ total[1], level=logging.DEBUG)
+    if formatted_string:
+        return total[1]
+    return total[0]
+
+
+def get_properties(cpv, want_dict=False, root=None, settings=None):
+    """Get all ebuild variables in one chunk.
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype
+    @return all properties of cpv
+    """
+    root, settings = ensure_settings(root, settings)
+    prop_dict = None
+    if settings.portdb[root].cpv_exists(cpv): # if in portage tree
+        try:
+            #writemsg_level(" * DATA_CONNECT: get_properties()", level=logging.DEBUG)
+            prop_dict = dict(zip(settings.keys,
+                settings.portdb[root].aux_get(cpv, portage.auxdbkeys)))
+        except IOError as e: # Sync being performed may delete files
+            writemsg_level(" * DATA_CONNECT: get_properties(): IOError: %s"
+                % str(e), level=logging.DEBUG)
+            #pass
+        except Exception as e:
+            writemsg_level(" * DATA_CONNECT: get_properties(): Exception: %s"
+                %str( e), level=logging.DEBUG)
+            #pass
+    else:
+        if settings.vardb[root].cpv_exists(cpv): # elif in installed pkg tree
+            prop_dict = dict(zip(settings.keys,
+                settings.vardb[root].aux_get(cpv, portage.auxdbkeys)))
+    if want_dict:
+        # return an empty dict instead of None
+        return prop_dict or {}
+    return Properties(prop_dict)
+
+
+def is_overlay(cpv, root=None, settings=None): # lifted from gentoolkit
+    """Returns true if the package is in an overlay.
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype bool
+    """
+    root, settings = ensure_settings(root, settings)
+    try:
+        dir, ovl = settings.portdb[root].findname2(cpv)
+    except:
+        return False
+    return ovl != settings.portdir
+
+
+def get_overlay(cpv, root=None, settings=None):
+    """Returns a portage overlay id
+
+    @type cpv: string
+    @param cpv: 'cat/pkg-ver'
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype str
+    @return portage overlay id. or 'Deprecated?
+    '"""
+    root, settings = ensure_settings(root, settings)
+    if '/' not in cpv:
+        return ''
+    try:
+        dir, ovl = settings.portdb[root].findname2(cpv)
+    except:
+        ovl = 'Deprecated?'
+    return ovl
+
+
+def get_overlay_name(ovl_path=None, cpv=None, root=None, settings=None):
+    """Returns the overlay name for either the overlay path or the cpv of a pkg
+
+    @param ovl_path: optional portage overlay path
+    @param cpv: optional cat/pkg-ver string
+    @type root: string
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @param root: tree root to use
+    @rtype str
+    """
+    root, settings = ensure_settings(root, settings)
+    if not ovl_path and cpv:
+        ovl_path = get_overlay(cpv, root)
+    name = None
+    name = settings.portdb[root].getRepositoryName(ovl_path)
+    return name or "????"
+
+
+def get_repositories(root=None, settings=None):
+    """Returns a list of all repositories for root
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].getRepositories()
+
+
+def get_system_pkgs(root=None, settings=None): # lifted from gentoolkit
+    """Returns a tuple of lists, first list is resolved system packages,
+    second is a list of unresolved packages.
+
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype: tuple
+    @return (resolved, unresolved) pkg lists
+    """
+    root, settings = ensure_settings(root, settings)
+    pkglist = settings.settings.packages
+    resolved = []
+    unresolved = []
+    for x in pkglist:
+        cpv = x.strip()
+        pkg = get_best_ebuild(cpv, root)
+        if pkg:
+            try:
+                resolved.append(Atom(pkg).cp)
+            except:
+                resolved.append(pkgsplit(pkg)[0])
+        else:
+            unresolved.append(pkgsplit(cpv)[0])
+    return (resolved, unresolved)
+
+
+def get_allnodes(root=None, settings=None):
+    """Returns a list of all availabe cat/pkg's available from the tree
+    and configured overlays. Subject to masking.
+
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtpye: list
+    @return: ['cat/pkg1', 'cat/pkg2',...]
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].cp_all()
+
+
+def get_installed_list(root=None, settings=None):
+    """Returns a list of all installed cat/pkg-ver available from the tree
+    and configured overlays. Subject to masking.
+
+    @type root: string
+    @param root: tree root to use
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtpye: list
+    @return: ['cat/pkg1-ver', 'cat/pkg2-ver',...]
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.vardb[root].cpv_all()
+
+
+def is_installed(cpv, root=None, settings=None):
+    root, settings = ensure_settings(root, settings)
+    if settings.vardb[root].cpv_exists(cpv):
+        return True
+    return False
+
+
+def get_cp_all(root=None, vardb=False, categories=None,
+        trees=None, settings=None):
+    """
+    This returns a list of all keys in our tree or trees
+    @param categories: optional list of categories to search or
+        defaults to settings.portdb[root].settings.categories
+    @param trees: optional list of trees to search the categories in or
+        defaults to settings.portdb[root].porttrees
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype list of [cat/pkg,...]
+    """
+    root, settings = ensure_settings(root, settings)
+    if vardb:
+        raise NotImplementedError
+        '''cp_all = settings.vardb[root].cp_all()
+        if categories:
+            d= {}
+            for cp in cp_all:
+                cp_split = catpkgsplit(cp)
+                if cp_split[0] in categories and cp_split[0] not in d:
+                    d[cp_split[0]] = []
+                d[cp_split[0]].append(p)
+            return sorted(d)
+        return cp_all'''
+    return settings.portdb[root].cp_all(categories, trees)
+
+
+def get_cp_list(root=None, cp=None, trees=None, settings=None):
+    """
+        @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].cp_list(cp, mytree=trees)
+
+
+def get_cpv_all(root=None, categories=None,
+        trees=None, settings=None):
+    """
+    This function returns all cpv's for a given tree or trees without
+    applying any repo priorities.  For a list of visible cpv's using proper
+    repo priorities and masking, use get_allnodes().
+    This returns a dictoinary of lists of all keys in our tree or trees
+    @param categories: optional list of categories to search or
+        defaults to settings.portdb[root].settings.categories
+    @param trees: optional list of trees to search the categories in or
+        defaults to settings.portdb[root].porttrees
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @rtype dict of lists of {tree:[cat/pkg-ver,...],}
+    """
+    root, settings = ensure_settings(root, settings)
+    if trees is None:
+        trees = settings.portdb[root].porttrees
+    cpvs = {}
+    for tree in trees:
+        cps = get_cp_all(root=root, categories=categories,
+            trees=[tree], settings=settings)
+        cpvs[tree] = []
+        for c_p in cps:
+            cpvs[tree].append(get_cp_list(root=root, cp=c_p,
+                trees=[tree], settings=settings))
+    return cpvs
+
+
+def findLicensePath(license_name, root=None, settings=None):
+    """@param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].findLicensePath(license_name)
+
+
+def getFetchMap(pkg, useflags=None, tree=None, root=None, settings=None):
+    """
+    Get the SRC_URI metadata as a dict which maps each file name to a
+    set of alternative URIs.
+
+    @param mypkg: cpv for an ebuild
+    @type pkg: String
+    @param useflags: a collection of enabled USE flags, for evaluation of
+        conditionals
+    @type useflags: set, or None to enable all conditionals
+    @param tree: The canonical path of the tree in which the ebuild
+        is located, or None for automatic lookup
+    @type pkg: String
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    @returns: A dict which maps each file name to a set of alternative
+        URIs.
+    @rtype: dict
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].getfetchsizes(pkg, useflags, tree)
+
+
+def getfetchsizes(pkg, useflags=None, root=None, settings=None):
+    """Returns a filename:size dictionnary of remaining downloads
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].getfetchsizes(pkg, useflags)
+
+
+def cpv_exists(cpv, root=None, settings=None):
+    """Tells us whether an actual ebuild exists on disk (no masking)
+    @param settings: optional portage config settings instance.
+        defaults to portage.api.settings.default_settings
+    """
+    root, settings = ensure_settings(root, settings)
+    return settings.portdb[root].cpv_exists(cpv)
+
+def get_category_description(category, root=None, settings=None):
+
+    root, settings = ensure_settings(root, settings)
+    from xml.dom import minidom
+    data = {}
+    portdir = settings.settings['PORTDIR']
+    myfile = os.path.join(portdir, category, "metadata.xml")
+    if os.access(myfile, os.R_OK) and os.path.isfile(myfile):
+        doc = minidom.parse(myfile)
+        longdescs = doc.getElementsByTagName("longdescription")
+        for longdesc in longdescs:
+            data[longdesc.getAttribute("lang").strip()] = \
+                ' '.join([x.strip() for x in \
+                    longdesc.firstChild.data.strip().split("\n")])
+
+    # Only return in plain English since Portage doesn't support i18n/l10n
+    return data.get('en', "No description")
+
diff --git a/pym/portage/api/flag.py b/pym/portage/api/flag.py
new file mode 100644
index 0000000..a83ee1d
--- /dev/null
+++ b/pym/portage/api/flag.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python
+#
+# Copyright(c) 2010, Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+
+
+"""Provides support functions for USE flag settings and analysis"""
+
+
+__all__ = (
+	'get_iuse',
+	'get_installed_use',
+	'reduce_flag',
+	'reduce_flags',
+	'filter_flags',
+	'get_all_cpv_use',
+	'get_flags'
+)
+
+
+#import sys
+
+from portage.api.settings import default_settings
+
+import portage
+
+
+def get_iuse(cpv, root=None, settings=default_settings):
+	"""Gets the current IUSE flags from the tree
+
+	To be used when a gentoolkit package object is not needed
+	@type: cpv: string 
+	@param cpv: cat/pkg-ver
+	@type root: string
+	@param root: tree root to use
+	@param settings: optional portage config settings instance.
+		defaults to portage.api.settings.default_settings
+	@rtype list
+	@returns [] or the list of IUSE flags
+	"""
+	if root is None:
+		root = settings.settings["ROOT"]
+	try:
+		return settings.portdb[root].aux_get(cpv, ["IUSE"])[0].split()
+	except:
+		return []
+
+
+def get_installed_use(cpv, use="USE", root=None, settings=default_settings):
+	"""Gets the installed USE flags from the VARDB
+
+	To be used when a gentoolkit package object is not needed
+	@type: cpv: string
+	@param cpv: cat/pkg-ver
+	@type use: string
+	@param use: 1 of ["USE", "PKGUSE"]
+	@type root: string
+	@param root: tree root to use
+	@param settings: optional portage config settings instance.
+		defaults to portage.api.settings.default_settings
+	@rtype list
+	@returns [] or the list of IUSE flags
+	"""
+	if root is None:
+		root = settings.settings["ROOT"]
+	return settings.vardb[root].aux_get(cpv, [use])[0].split()
+
+
+def reduce_flag(flag):
+	"""Absolute value function for a USE flag
+
+	@type flag: string
+	@param flag: the use flag to absolute.
+	@rtype: string
+	@return absolute USE flag
+	"""
+	if flag[0] in ["+","-"]:
+		return flag[1:]
+	else:
+		return flag
+
+
+def reduce_flags(the_list):
+	"""Absolute value function for a USE flag list
+
+	@type the_list: list
+	@param the_list: the use flags to absolute.
+	@rtype: list
+	@return absolute USE flags
+	"""
+	reduced = []
+	for member in the_list:
+		reduced.append(reduce_flag(member))
+	return reduced
+
+
+def filter_flags(use, use_expand_hidden, usemasked,
+		useforced, settings=default_settings):
+	"""Filter function to remove hidden or otherwise not normally
+	visible USE flags from a list.
+
+	@type use: list
+	@param use: the USE flag list to be filtered.
+	@type use_expand_hidden: list
+	@param  use_expand_hidden: list of flags hidden.
+	@type usemasked: list
+	@param usemasked: list of masked USE flags.
+	@type useforced: list
+	@param useforced: the forced USE flags.
+	@param settings: optional portage config settings instance.
+		defaults to portage.api.settings.default_settings
+	@rtype: list
+	@return the filtered USE flags.
+	"""
+	# clean out some environment flags, since they will most probably
+	# be confusing for the user
+	for flag in use_expand_hidden:
+		flag = flag.lower() + "_"
+		for expander in use:
+			if flag in expander:
+				use.remove(expander)
+	# clean out any arch's
+	archlist = settings.settings["PORTAGE_ARCHLIST"].split()
+	for key in use[:]:
+		if key in archlist:
+			use.remove(key)
+	# dbl check if any from usemasked  or useforced are still there
+	masked = usemasked + useforced
+	for flag in use[:]:
+		if flag in masked:
+			use.remove(flag)
+	return use
+
+
+def get_all_cpv_use(cpv, root=None, settings=default_settings):
+	"""Uses portage to determine final USE flags and settings for an emerge
+
+	@type cpv: string
+	@param cpv: eg cat/pkg-ver
+	@type root: string
+	@param root: tree root to use
+	@param settings: optional portage config settings instance.
+		defaults to portage.api.settings.default_settings
+	@rtype: lists
+	@return  use, use_expand_hidden, usemask, useforce
+	"""
+	if root is None:
+		root = settings.settings["ROOT"]
+	use = None
+	settings.portdb[root].settings.unlock()
+	try:
+		settings.portdb[root].settings.setcpv(cpv, mydb=settings.portdb[root])
+		use = settings.settings['PORTAGE_USE'].split()
+		use_expand_hidden = settings.settings["USE_EXPAND_HIDDEN"].split()
+		usemask = list(settings.portdb[root].settings.usemask)
+		useforce =  list(settings.portdb[root].settings.useforce)
+	except KeyError:
+		settings.portdb[root].settings.reset()
+		settings.portdb[root].settings.lock()
+		return [], [], [], []
+	# reset cpv filter
+	settings.portdb[root].settings.reset()
+	settings.portdb[root].settings.lock()
+	return use, use_expand_hidden, usemask, useforce
+
+
+def get_flags(cpv, final_setting=False, root=None, settings=default_settings):
+	"""Retrieves all information needed to filter out hidden, masked, etc.
+	USE flags for a given package.
+
+	@type cpv: string
+	@param cpv: eg. cat/pkg-ver
+	@type final_setting: boolean
+	@param final_setting: used to also determine the final
+		enviroment USE flag settings and return them as well.
+	@type root: string
+	@param root: pass through variable needed, tree root to use
+		for other function calls.
+	@param settings: optional portage config settings instance.
+		defaults to portage.api.settings.default_settings
+	@rtype: list or list, list
+	@return IUSE or IUSE, final_flags
+	"""
+	(final_use, use_expand_hidden, usemasked, useforced) = \
+		get_all_cpv_use(cpv, root, settings)
+	iuse_flags = filter_flags(get_iuse(cpv), use_expand_hidden,
+		usemasked, useforced, settings)
+	#flags = filter_flags(use_flags, use_expand_hidden,
+		#usemasked, useforced, settings)
+	if final_setting:
+		final_flags = filter_flags(final_use,  use_expand_hidden,
+			usemasked, useforced, settings)
+		return iuse_flags, final_flags
+	return iuse_flags
+
+
+def get_use_flag_dict(portdir):
+	""" Get all the use flags and return them as a dictionary
+	
+	@param portdir: the path to the repository
+	@rtype dictionary of:
+		key = use flag forced to lowercase
+		data = list[0] = 'local' or 'global'
+			   list[1] = 'package-name'
+			   list[2] = description of flag
+	"""
+	use_dict = {}
+
+	# process standard use flags
+
+	_list = portage.grabfile(portdir + '/profiles/use.desc')
+	for item in _list:
+		index = item.find(' - ')
+		use_dict[item[:index].strip().lower()] = ['global', '', item[index+3:]]
+
+	# process local (package specific) use flags
+
+	_list = portage.grabfile(portdir + '/profiles/use.local.desc')
+	for item in _list:
+		index = item.find(' - ')
+		data = item[:index].lower().split(':')
+		try: 
+			use_dict[data[1].strip()] = ['local', data[0].strip(), item[index+3:]]
+		except:
+			pass
+			#debug.dprint("FLAG: get_use_flag_dict();"
+				#"error in index??? data[0].strip, item[index:]")
+			#debug.dprint(data[0].strip())
+			#debug.dprint(item[index:])
+	return use_dict
diff --git a/pym/portage/api/properties.py b/pym/portage/api/properties.py
new file mode 100644
index 0000000..f282e76
--- /dev/null
+++ b/pym/portage/api/properties.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+#
+# Copyright(c) 2010, Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+
+
+"""Provides a properties class to hold ebuild variables"""
+
+from portage.api.settings import default_settings
+
+
+class Properties(object):
+	"""Contains all variables in an ebuild."""
+
+	__slots__ = default_settings.keys + ["_dict", "__doc__", "__str__"]
+
+
+	def __init__(self, _dict = None):
+		self._dict = _dict
+
+	def __getattr__(self, name):
+		try:
+			return self._dict[name]
+		except:
+			return ''
+
+	def __str__(self):
+		txt = []
+		for k in self.__slots__[:-3]:
+			txt.append( "	%s: %s" %(k, self.__getattr__(k)))
+		return '\n'.join(txt)
+
+	def keys(self):
+		"""Returns  the availabel dictionary keys"""
+		return self.__slots__[:-3]
+
+	def get(self, name):
+		"""Returns the value for the dictionary key"""
+		return getattr(self, name)
+
+	def get_slot(self):
+		"""Return ebuild slot"""
+		return self.slot
+
+	def get_keywords(self):
+		"""Returns a list of strings."""
+		return self.keywords.split()
+
+	def get_use_flags(self):
+		"""Returns a list of strings."""
+		return list(set(self.iuse.split()))
+
+	def get_homepages(self):
+		"""Returns a list of strings."""
+		return self.homepage.split()
diff --git a/pym/portage/api/settings.py b/pym/portage/api/settings.py
new file mode 100644
index 0000000..250917e
--- /dev/null
+++ b/pym/portage/api/settings.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+#
+# Copyright 1998-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+"""Portage API settings class for consumer apps."""
+
+import os
+
+from _emerge.actions import load_emerge_config
+import portage
+from portage import const
+
+
+class PortageSettings:
+	"""This class hold an instance of the portage settings as
+	well as some other commonly used data used in/from the  api.
+	"""
+
+	def __init__(self, config_root=None):
+		# declare some globals
+		self.portdir = None
+		self.portdir_overlay = None
+		self.portdb = None
+		self.vardb = None
+		self.trees = None
+		self.root_config = None
+		self.bindb = None
+		self.configured_roots = None
+		self.arch = None
+		self.mtimedb = None
+		self.ACCEPT_KEYWORDS = None
+		self.user_config_dir = None
+		self._world = None
+		self.SystemUseFlags = None
+		self.virtuals =  None
+		self.keys =  None
+		self.UseFlagDict = None
+		self.settings = None
+		if config_root is None:
+			self.reset()
+		else:
+			self.config_root = config_root
+
+
+
+	def reset_use_flags(self):
+		"""Resets the SystemUseFlags to any new
+		changes to their setting.
+		"""
+		#print("SETTINGS: Settings.reset_use_flags();")
+		self.SystemUseFlags = self.settings["USE"].split()
+		#print("SETTINGS: Settings.reset_use_flags(); SystemUseFlags = " +
+			#str(self.SystemUseFlags))
+
+
+	def reset(self):
+		"""Reset remaining run once variables after a sync or other mods
+		"""
+		#print("SETTINGS: reset_globals();")
+		self.settings, self.trees, self.mtimedb = load_emerge_config()
+		self._load_dbapis()
+		self.root_config = self.trees[self.settings['ROOT']]['root_config']
+		self.portdir = self.settings.environ()['PORTDIR']
+		self.config_root = self.settings['PORTAGE_CONFIGROOT']
+		# is PORTDIR_OVERLAY always defined?
+		self.portdir_overlay = self.settings.environ()['PORTDIR_OVERLAY']
+		self.ACCEPT_KEYWORDS = self.settings["ACCEPT_KEYWORDS"]
+		self.arch = self.settings['ARCH']
+		self.user_config_dir = const.USER_CONFIG_PATH
+		self.reload_world()
+		self.reset_use_flags()
+		self.virtuals = self.settings.getvirtuals()
+		# lower case is nicer
+		self.keys = [key.lower() for key in portage.auxdbkeys]
+		return
+
+
+	def _load_dbapis(self):
+		"""handles loading all the trees dbapi's"""
+		self.portdb, self.vardb, self.bindb = {}, {}, {}
+		self.configured_roots = sorted(self.trees)
+		for root in self.configured_roots:
+			self.portdb[root] = self.trees[root]["porttree"].dbapi
+			self.vardb[root] = self.trees[root]["vartree"].dbapi
+			self.bindb[root] = self.trees[root]["bintree"].dbapi
+
+
+	def reload_config(self):
+		"""Reload the whole config from scratch"""
+		self.settings, self.trees, self.mtimedb = load_emerge_config(self.trees)
+		self._load_dbapis()
+
+	def reload_world(self):
+		"""Reloads the world file into memory for quick access
+		@return boolean
+		"""
+		#print("SETTINGS: reset_world();")
+		world = []
+		try:
+			_file = open(os.path.join(portage.root, portage.WORLD_FILE), "r")
+			world = _file.read().split()
+			_file.close()
+		except:
+			print("SETTINGS: get_world(); Failure to locate file: '%s'"
+				%portage.WORLD_FILE)
+			return False
+		self._world = world
+		return True
+
+
+	def get_world(self):
+		"""Returns a copy of world's pkg list
+		@return list of world pkg strings
+		"""
+		return self._world[:]
+
+
+	def get_archlist(self):
+		"""Returns a list of the architectures accepted by portage as valid keywords.
+		@return: list of arch strings
+		"""
+		return self.settings["PORTAGE_ARCHLIST"].split()
+
+
+	def get_virtuals(self):
+		"""returns the virtual pkgs
+		@rtype dict
+		@return virtual pkgs dictionary
+		"""
+		return self.settings.virtuals
+
+
+default_settings = PortageSettings()
+
+
+def reload_portage(settings=None):
+	"""Convienence function to re-import portage after a portage update.
+	Caution, it may not always work correctly due to python caching if
+	program files are added/deleted between versions. In those cases the
+	consumer app may need to be closed and restarted."""
+	#print('SETTINGS: reloading portage')
+	#print("SETTINGS: old portage version = " + portage.VERSION)
+	try:
+		reload(portage)
+	except ImportError:
+		return False
+	#print("SETTINGS: new portage version = " + portage.VERSION)
+	if settings is None:
+		default_settings.reset()
+	else:
+		settings.reset()
+	return True