Allows binpkgs to be deleted if they are not usable due to IUSE changes.
---
Just kind of spitballing. I'm not sure about what USE flags we should
ignore or whether it should be configurable, etc. On one hand, deleting
binpkgs that don't have a newly added PYTHON_TARGET option might make
sense if your binhost is configured to rebuild the package. On the
other, you probably don't want to throw out amd64 binpkgs because
abi_riscv_* was added.

 pym/gentoolkit/eclean/cli.py    |  8 ++++-
 pym/gentoolkit/eclean/search.py | 62 +++++++++++++++++++++++++--------
 2 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/pym/gentoolkit/eclean/cli.py b/pym/gentoolkit/eclean/cli.py
index e31fde9..910296b 100644
--- a/pym/gentoolkit/eclean/cli.py
+++ b/pym/gentoolkit/eclean/cli.py
@@ -146,6 +146,8 @@ def printUsage(_error=None, help=None):
                                green("packages"),"action:", file=out)
                print( yellow("     --changed-deps")+
                        "               - delete packages for which ebuild 
dependencies have changed", file=out)
+               print( yellow("     --changed-iuse")+
+                       "               - delete packages for which IUSE have 
changed", file=out)
                print( yellow(" -i, --ignore-failure")+
                        "             - ignore failure to locate PKGDIR", 
file=out)
                print( file=out)
@@ -264,6 +266,8 @@ def parseArgs(options={}):
                                        options['verbose'] = True
                        elif o in ("--changed-deps"):
                                options['changed-deps'] = True
+                       elif o in ("--changed-iuse"):
+                               options['changed-iuse'] = True
                        elif o in ("-i", "--ignore-failure"):
                                options['ignore-failure'] = True
                        else:
@@ -291,7 +295,8 @@ def parseArgs(options={}):
        getopt_options['short']['distfiles'] = "fs:"
        getopt_options['long']['distfiles'] = ["fetch-restricted", 
"size-limit="]
        getopt_options['short']['packages'] = "i"
-       getopt_options['long']['packages'] = ["ignore-failure", "changed-deps"]
+       getopt_options['long']['packages'] = ["ignore-failure", "changed-deps",
+                                             "changed-iuse"]
        # set default options, except 'nocolor', which is set in main()
        options['interactive'] = False
        options['pretend'] = False
@@ -305,6 +310,7 @@ def parseArgs(options={}):
        options['size-limit'] = 0
        options['verbose'] = False
        options['changed-deps'] = False
+       options['changed-iuse'] = False
        options['ignore-failure'] = False
        # if called by a well-named symlink, set the action accordingly:
        action = None
diff --git a/pym/gentoolkit/eclean/search.py b/pym/gentoolkit/eclean/search.py
index 8f6e52f..8344e15 100644
--- a/pym/gentoolkit/eclean/search.py
+++ b/pym/gentoolkit/eclean/search.py
@@ -498,6 +498,47 @@ def _deps_equal(deps_a, eapi_a, deps_b, eapi_b, 
uselist=None):
        return deps_a == deps_b
 
 
+def _changed_deps(cpv, options, port_dbapi, bin_dbapi):
+       if not options['changed-deps']:
+               return False
+
+       dep_keys = ('RDEPEND', 'PDEPEND')
+       keys = ('EAPI', 'USE') + dep_keys
+       binpkg_metadata = dict(zip(keys, bin_dbapi.aux_get(cpv, keys)))
+       ebuild_metadata = dict(zip(keys, port_dbapi.aux_get(cpv, keys)))
+
+       return _deps_equal(' '.join(binpkg_metadata[key] for key in dep_keys),
+                                          binpkg_metadata['EAPI'], ' 
'.join(ebuild_metadata[key] for key in dep_keys),
+                                          ebuild_metadata['EAPI'],
+                                          
frozenset(binpkg_metadata['USE'].split()))
+
+
+# IUSE flags to be ignored for purposes of invalidating binpkgs
+def ignore(iuse):
+       return iuse.startswith('abi_')
+
+
+# Prune the + characters from USE flags (e.g. '+cxx' -> 'cxx')
+def prune_plus(iuse):
+       if iuse.startswith('+'):
+               return iuse[1:]
+       return iuse
+
+
+def _changed_iuse(cpv, options, port_dbapi, bin_dbapi):
+       if not options['changed-iuse']:
+               return False
+
+       keys = ('IUSE',)
+       binpkg_metadata = [prune_plus(x) for x in  bin_dbapi.aux_get(cpv, 
keys)[0].split(' ') if not ignore(x)]
+       ebuild_metadata = [prune_plus(x) for x in port_dbapi.aux_get(cpv, 
keys)[0].split(' ') if not ignore(x)]
+
+       if binpkg_metadata == ['']: binpkg_metadata = []
+       if ebuild_metadata == ['']: ebuild_metadata = []
+
+       return binpkg_metadata != ebuild_metadata
+
+
 def findPackages(
                options,
                exclude=None,
@@ -570,21 +611,6 @@ def findPackages(
                        if mtime >= time_limit:
                                continue
 
-               # Exclude if binpkg exists in the porttree and not --deep
-               if not destructive and port_dbapi.cpv_exists(cpv):
-                       if not options['changed-deps']:
-                               continue
-
-                       dep_keys = ('RDEPEND', 'PDEPEND')
-                       keys = ('EAPI', 'USE') + dep_keys
-                       binpkg_metadata = dict(zip(keys, bin_dbapi.aux_get(cpv, 
keys)))
-                       ebuild_metadata = dict(zip(keys, 
port_dbapi.aux_get(cpv, keys)))
-
-                       if _deps_equal(' '.join(binpkg_metadata[key] for key in 
dep_keys), binpkg_metadata['EAPI'],
-                               ' '.join(ebuild_metadata[key] for key in 
dep_keys), ebuild_metadata['EAPI'],
-                               frozenset(binpkg_metadata['USE'].split())):
-                               continue
-
                if destructive and var_dbapi.cpv_exists(cpv):
                        # Exclude if an instance of the package is installed 
due to
                        # the --package-names option.
@@ -596,6 +622,12 @@ def findPackages(
                        if buildtime == bin_dbapi.aux_get(cpv, 
['BUILD_TIME'])[0]:
                                continue
 
+               # Exclude if binpkg exists in the porttree and not --deep
+               if not destructive and port_dbapi.cpv_exists(cpv):
+                       if not _changed_deps(cpv, options, port_dbapi, 
bin_dbapi) and \
+                          not _changed_iuse(cpv, options, port_dbapi, 
bin_dbapi):
+                               continue
+
                binpkg_path = bin_dbapi.bintree.getname(cpv)
                dead_binpkgs.setdefault(cpv, []).append(binpkg_path)
 
-- 
2.26.2


Reply via email to