Mini Shell
"""
Manage cygwin packages.
Module file to accompany the cyg state.
"""
import bz2
import logging
import os
import re
import urllib.request
import salt.utils.files
import salt.utils.platform
import salt.utils.stringutils
from salt.exceptions import SaltInvocationError
LOG = logging.getLogger(__name__)
DEFAULT_MIRROR = "ftp://mirrors.kernel.org/sourceware/cygwin/"
DEFAULT_MIRROR_KEY = ""
# Define the module's virtual name
__virtualname__ = "cyg"
def __virtual__():
"""
Only works on Windows systems
"""
if salt.utils.platform.is_windows():
return __virtualname__
return (False, "Module cyg: module only works on Windows systems.")
__func_alias__ = {"list_": "list"}
def _get_cyg_dir(cyg_arch="x86_64"):
"""
Return the cygwin install directory based on the architecture.
"""
if cyg_arch == "x86_64":
return "cygwin64"
elif cyg_arch == "x86":
return "cygwin"
raise SaltInvocationError(f"Invalid architecture {cyg_arch}")
def _check_cygwin_installed(cyg_arch="x86_64"):
"""
Return True or False if cygwin is installed.
Use the cygcheck executable to check install. It is installed as part of
the base package, and we use it to check packages
"""
path_to_cygcheck = os.sep.join(
["C:", _get_cyg_dir(cyg_arch), "bin", "cygcheck.exe"]
)
LOG.debug("Path to cygcheck.exe: %s", path_to_cygcheck)
if not os.path.exists(path_to_cygcheck):
LOG.debug("Could not find cygcheck.exe")
return False
return True
def _get_all_packages(mirror=DEFAULT_MIRROR, cyg_arch="x86_64"):
"""
Return the list of packages based on the mirror provided.
"""
if "cyg.all_packages" not in __context__:
__context__["cyg.all_packages"] = {}
if mirror not in __context__["cyg.all_packages"]:
__context__["cyg.all_packages"][mirror] = []
if not __context__["cyg.all_packages"][mirror]:
pkg_source = "/".join([mirror, cyg_arch, "setup.bz2"])
file_data = urllib.request.urlopen(pkg_source).read()
file_lines = (
bz2.decompress(file_data).decode("utf_8", errors="replace").splitlines()
)
packages = [
re.search("^@ ([^ ]+)", line).group(1)
for line in file_lines
if re.match("^@ [^ ]+", line)
]
__context__["cyg.all_packages"][mirror] = packages
return __context__["cyg.all_packages"][mirror]
def check_valid_package(package, cyg_arch="x86_64", mirrors=None):
"""
Check if the package is valid on the given mirrors.
Args:
package: The name of the package
cyg_arch: The cygwin architecture
mirrors: any mirrors to check
Returns (bool): True if Valid, otherwise False
CLI Example:
.. code-block:: bash
salt '*' cyg.check_valid_package <package name>
"""
if mirrors is None:
mirrors = [{DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}]
LOG.debug("Checking Valid Mirrors: %s", mirrors)
for mirror in mirrors:
for mirror_url, key in mirror.items():
if package in _get_all_packages(mirror_url, cyg_arch):
return True
return False
def _run_silent_cygwin(cyg_arch="x86_64", args=None, mirrors=None):
"""
Retrieve the correct setup.exe.
Run it with the correct arguments to get the bare minimum cygwin
installation up and running.
"""
cyg_cache_dir = os.sep.join(["c:", "cygcache"])
cyg_setup = f"setup-{cyg_arch}.exe"
cyg_setup_path = os.sep.join([cyg_cache_dir, cyg_setup])
cyg_setup_source = f"http://cygwin.com/{cyg_setup}"
# cyg_setup_source_hash = 'http://cygwin.com/{0}.sig'.format(cyg_setup)
# until a hash gets published that we can verify the newest setup against
# just go ahead and download a new one.
if not os.path.exists(cyg_cache_dir):
os.mkdir(cyg_cache_dir)
elif os.path.exists(cyg_setup_path):
os.remove(cyg_setup_path)
file_data = urllib.request.urlopen(cyg_setup_source)
with salt.utils.files.fopen(cyg_setup_path, "wb") as fhw:
fhw.write(file_data.read())
setup_command = cyg_setup_path
options = []
options.append(f"--local-package-dir {cyg_cache_dir}")
if mirrors is None:
mirrors = [{DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}]
for mirror in mirrors:
for mirror_url, key in mirror.items():
options.append(f"--site {mirror_url}")
if key:
options.append(f"--pubkey {key}")
options.append("--no-desktop")
options.append("--quiet-mode")
options.append("--disable-buggy-antivirus")
if args is not None:
for arg in args:
options.append(arg)
cmdline_args = " ".join(options)
setup_command = " ".join([cyg_setup_path, cmdline_args])
ret = __salt__["cmd.run_all"](setup_command)
if ret["retcode"] == 0:
return ret["stdout"]
else:
return False
def _cygcheck(args, cyg_arch="x86_64"):
"""
Run the cygcheck executable.
"""
cmd = " ".join(
[os.sep.join(["c:", _get_cyg_dir(cyg_arch), "bin", "cygcheck"]), "-c", args]
)
ret = __salt__["cmd.run_all"](cmd)
if ret["retcode"] == 0:
return ret["stdout"]
else:
return False
def install(packages=None, cyg_arch="x86_64", mirrors=None):
"""
Install one or several packages.
packages : None
The packages to install
cyg_arch : x86_64
Specify the architecture to install the package under
Current options are x86 and x86_64
CLI Example:
.. code-block:: bash
salt '*' cyg.install dos2unix
salt '*' cyg.install dos2unix mirrors="[{'http://mirror': 'http://url/to/public/key}]'
"""
args = []
# If we want to install packages
if packages is not None:
args.append(f"--packages {packages}")
# but we don't have cygwin installed yet
if not _check_cygwin_installed(cyg_arch):
# install just the base system
_run_silent_cygwin(cyg_arch=cyg_arch)
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def uninstall(packages, cyg_arch="x86_64", mirrors=None):
"""
Uninstall one or several packages.
packages
The packages to uninstall.
cyg_arch : x86_64
Specify the architecture to remove the package from
Current options are x86 and x86_64
CLI Example:
.. code-block:: bash
salt '*' cyg.uninstall dos2unix
salt '*' cyg.uninstall dos2unix mirrors="[{'http://mirror': 'http://url/to/public/key}]"
"""
args = []
if packages is not None:
args.append(f"--remove-packages {packages}")
LOG.debug("args: %s", args)
if not _check_cygwin_installed(cyg_arch):
LOG.debug("We're convinced cygwin isn't installed")
return True
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def update(cyg_arch="x86_64", mirrors=None):
"""
Update all packages.
cyg_arch : x86_64
Specify the cygwin architecture update
Current options are x86 and x86_64
CLI Example:
.. code-block:: bash
salt '*' cyg.update
salt '*' cyg.update dos2unix mirrors="[{'http://mirror': 'http://url/to/public/key}]"
"""
args = []
args.append("--upgrade-also")
# Can't update something that isn't installed
if not _check_cygwin_installed(cyg_arch):
LOG.debug("Cygwin (%s) not installed, could not update", cyg_arch)
return False
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def list_(package="", cyg_arch="x86_64"):
"""
List locally installed packages.
package : ''
package name to check. else all
cyg_arch :
Cygwin architecture to use
Options are x86 and x86_64
CLI Example:
.. code-block:: bash
salt '*' cyg.list
"""
pkgs = {}
args = " ".join(["-c", "-d", package])
stdout = _cygcheck(args, cyg_arch=cyg_arch)
lines = []
if isinstance(stdout, str):
lines = salt.utils.stringutils.to_unicode(stdout).splitlines()
for line in lines:
match = re.match(r"^([^ ]+) *([^ ]+)", line)
if match:
pkg = match.group(1)
version = match.group(2)
pkgs[pkg] = version
return pkgs
Zerion Mini Shell 1.0