Mini Shell
"""
Support for Gentoolkit
"""
import os
HAS_GENTOOLKIT = False
try:
from gentoolkit.eclean import clean, cli
from gentoolkit.eclean import exclude as excludemod
from gentoolkit.eclean import search
HAS_GENTOOLKIT = True
except ImportError:
pass
# Define the module's virtual name
__virtualname__ = "gentoolkit"
def __virtual__():
"""
Only work on Gentoo systems with gentoolkit installed
"""
if __grains__["os"] == "Gentoo" and HAS_GENTOOLKIT:
return __virtualname__
return (
False,
"The gentoolkitmod execution module cannot be loaded: either the system is not"
" Gentoo or the gentoolkit.eclean python module not available",
)
def revdep_rebuild(lib=None):
"""
Fix up broken reverse dependencies
lib
Search for reverse dependencies for a particular library rather
than every library on the system. It can be a full path to a
library or basic regular expression.
CLI Example:
.. code-block:: bash
salt '*' gentoolkit.revdep_rebuild
"""
cmd = "revdep-rebuild -i --quiet --no-progress"
if lib is not None:
cmd += f" --library={lib}"
return __salt__["cmd.retcode"](cmd, python_shell=False) == 0
def _pretty_size(size):
"""
Print sizes in a similar fashion as eclean
"""
units = [" G", " M", " K", " B"]
while units and size >= 1000:
size = size / 1024.0
units.pop()
return f"{round(size, 1)}{units[-1]}"
def _parse_exclude(exclude_file):
"""
Parse an exclude file.
Returns a dict as defined in gentoolkit.eclean.exclude.parseExcludeFile
"""
if os.path.isfile(exclude_file):
exclude = excludemod.parseExcludeFile(exclude_file, lambda x: None)
else:
exclude = dict()
return exclude
def eclean_dist(
destructive=False,
package_names=False,
size_limit=0,
time_limit=0,
fetch_restricted=False,
exclude_file="/etc/eclean/distfiles.exclude",
):
"""
Clean obsolete portage sources
destructive
Only keep minimum for reinstallation
package_names
Protect all versions of installed packages. Only meaningful if used
with destructive=True
size_limit <size>
Don't delete distfiles bigger than <size>.
<size> is a size specification: "10M" is "ten megabytes",
"200K" is "two hundreds kilobytes", etc. Units are: G, M, K and B.
time_limit <time>
Don't delete distfiles files modified since <time>
<time> is an amount of time: "1y" is "one year", "2w" is
"two weeks", etc. Units are: y (years), m (months), w (weeks),
d (days) and h (hours).
fetch_restricted
Protect fetch-restricted files. Only meaningful if used with
destructive=True
exclude_file
Path to exclusion file. Default is /etc/eclean/distfiles.exclude
This is the same default eclean-dist uses. Use None if this file
exists and you want to ignore.
Returns a dict containing the cleaned, saved, and deprecated dists:
.. code-block:: python
{'cleaned': {<dist file>: <size>},
'deprecated': {<package>: <dist file>},
'saved': {<package>: <dist file>},
'total_cleaned': <size>}
CLI Example:
.. code-block:: bash
salt '*' gentoolkit.eclean_dist destructive=True
"""
if exclude_file is None:
exclude = None
else:
try:
exclude = _parse_exclude(exclude_file)
except excludemod.ParseExcludeFileException as e:
ret = {e: f"Invalid exclusion file: {exclude_file}"}
return ret
if time_limit != 0:
time_limit = cli.parseTime(time_limit)
if size_limit != 0:
size_limit = cli.parseSize(size_limit)
clean_size = 0
engine = search.DistfilesSearch(lambda x: None)
clean_me, saved, deprecated = engine.findDistfiles(
destructive=destructive,
package_names=package_names,
size_limit=size_limit,
time_limit=time_limit,
fetch_restricted=fetch_restricted,
exclude=exclude,
)
cleaned = dict()
def _eclean_progress_controller(size, key, *args):
cleaned[key] = _pretty_size(size)
return True
if clean_me:
cleaner = clean.CleanUp(_eclean_progress_controller)
clean_size = cleaner.clean_dist(clean_me)
ret = {
"cleaned": cleaned,
"saved": saved,
"deprecated": deprecated,
"total_cleaned": _pretty_size(clean_size),
}
return ret
def eclean_pkg(
destructive=False,
package_names=False,
time_limit=0,
exclude_file="/etc/eclean/packages.exclude",
):
"""
Clean obsolete binary packages
destructive
Only keep minimum for reinstallation
package_names
Protect all versions of installed packages. Only meaningful if used
with destructive=True
time_limit <time>
Don't delete distfiles files modified since <time>
<time> is an amount of time: "1y" is "one year", "2w" is
"two weeks", etc. Units are: y (years), m (months), w (weeks),
d (days) and h (hours).
exclude_file
Path to exclusion file. Default is /etc/eclean/packages.exclude
This is the same default eclean-pkg uses. Use None if this file
exists and you want to ignore.
Returns a dict containing the cleaned binary packages:
.. code-block:: python
{'cleaned': {<dist file>: <size>},
'total_cleaned': <size>}
CLI Example:
.. code-block:: bash
salt '*' gentoolkit.eclean_pkg destructive=True
"""
if exclude_file is None:
exclude = None
else:
try:
exclude = _parse_exclude(exclude_file)
except excludemod.ParseExcludeFileException as e:
ret = {e: f"Invalid exclusion file: {exclude_file}"}
return ret
if time_limit != 0:
time_limit = cli.parseTime(time_limit)
clean_size = 0
# findPackages requires one arg, but does nothing with it.
# So we will just pass None in for the required arg
clean_me = search.findPackages(
None,
destructive=destructive,
package_names=package_names,
time_limit=time_limit,
exclude=exclude,
pkgdir=search.pkgdir,
)
cleaned = dict()
def _eclean_progress_controller(size, key, *args):
cleaned[key] = _pretty_size(size)
return True
if clean_me:
cleaner = clean.CleanUp(_eclean_progress_controller)
clean_size = cleaner.clean_pkgs(clean_me, search.pkgdir)
ret = {"cleaned": cleaned, "total_cleaned": _pretty_size(clean_size)}
return ret
def _glsa_list_process_output(output):
"""
Process output from glsa_check_list into a dict
Returns a dict containing the glsa id, description, status, and CVEs
"""
ret = dict()
for line in output:
try:
glsa_id, status, desc = line.split(None, 2)
if "U" in status:
status += " Not Affected"
elif "N" in status:
status += " Might be Affected"
elif "A" in status:
status += " Applied (injected)"
if "CVE" in desc:
desc, cves = desc.rsplit(None, 1)
cves = cves.split(",")
else:
cves = list()
ret[glsa_id] = {"description": desc, "status": status, "CVEs": cves}
except ValueError:
pass
return ret
def glsa_check_list(glsa_list):
"""
List the status of Gentoo Linux Security Advisories
glsa_list
can contain an arbitrary number of GLSA ids, filenames
containing GLSAs or the special identifiers 'all' and 'affected'
Returns a dict containing glsa ids with a description, status, and CVEs:
.. code-block:: python
{<glsa_id>: {'description': <glsa_description>,
'status': <glsa status>,
'CVEs': [<list of CVEs>]}}
CLI Example:
.. code-block:: bash
salt '*' gentoolkit.glsa_check_list 'affected'
"""
cmd = "glsa-check --quiet --nocolor --cve --list "
if isinstance(glsa_list, list):
for glsa in glsa_list:
cmd += glsa + " "
elif glsa_list == "all" or glsa_list == "affected":
cmd += glsa_list
ret = dict()
out = __salt__["cmd.run"](cmd, python_shell=False).split("\n")
ret = _glsa_list_process_output(out)
return ret
Zerion Mini Shell 1.0