PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/version.py |
""" Set up the version of Salt """ import argparse import operator import os import platform import re import sys from collections import namedtuple from functools import total_ordering MAX_SIZE = sys.maxsize VERSION_LIMIT = MAX_SIZE - 200 # ----- ATTENTION ---------------------------------------------------------------------------------------------------> # # ALL major version bumps, new release codenames, MUST be defined in the SaltStackVersion.NAMES dictionary, i.e.: # # class SaltStackVersion: # # NAMES = { # 'Hydrogen': (2014, 1), # <- This is the tuple to bump versions # ( ... ) # } # # # ONLY UPDATE CODENAMES AFTER BRANCHING # # As an example, The Helium codename must only be properly defined with "(2014, 7)" after Hydrogen, "(2014, 1)", has # been branched out into its own branch. # # ALL OTHER VERSION INFORMATION IS EXTRACTED FROM THE GIT TAGS # # <---- ATTENTION ---------------------------------------------------------------------------------------------------- @total_ordering class SaltVersion(namedtuple("SaltVersion", "name, info, released")): __slots__ = () def __new__(cls, name, info, released=False): if isinstance(info, int): info = (info,) return super().__new__(cls, name, info, released) def __eq__(self, other): return self.info == other.info def __gt__(self, other): return self.info > other.info class SaltVersionsInfo(type): _sorted_versions = () _current_release = None _previous_release = None _next_release = None # pylint: disable=bad-whitespace # ----- Please refrain from fixing whitespace ----------------------------------> # The idea is to keep this readable. # ------------------------------------------------------------------------------- # fmt: off HYDROGEN = SaltVersion("Hydrogen" , info=(2014, 1), released=True) HELIUM = SaltVersion("Helium" , info=(2014, 7), released=True) LITHIUM = SaltVersion("Lithium" , info=(2015, 5), released=True) BERYLLIUM = SaltVersion("Beryllium" , info=(2015, 8), released=True) BORON = SaltVersion("Boron" , info=(2016, 3), released=True) CARBON = SaltVersion("Carbon" , info=(2016, 11), released=True) NITROGEN = SaltVersion("Nitrogen" , info=(2017, 7), released=True) OXYGEN = SaltVersion("Oxygen" , info=(2018, 3), released=True) FLUORINE = SaltVersion("Fluorine" , info=(2019, 2), released=True) NEON = SaltVersion("Neon" , info=3000, released=True) SODIUM = SaltVersion("Sodium" , info=3001, released=True) MAGNESIUM = SaltVersion("Magnesium" , info=3002, released=True) ALUMINIUM = SaltVersion("Aluminium" , info=3003, released=True) SILICON = SaltVersion("Silicon" , info=3004, released=True) PHOSPHORUS = SaltVersion("Phosphorus" , info=3005, released=True) SULFUR = SaltVersion("Sulfur" , info=3006, released=True) CHLORINE = SaltVersion("Chlorine" , info=3007) ARGON = SaltVersion("Argon" , info=3008) POTASSIUM = SaltVersion("Potassium" , info=3009) CALCIUM = SaltVersion("Calcium" , info=3010) SCANDIUM = SaltVersion("Scandium" , info=3011) TITANIUM = SaltVersion("Titanium" , info=3012) VANADIUM = SaltVersion("Vanadium" , info=3013) CHROMIUM = SaltVersion("Chromium" , info=3014) MANGANESE = SaltVersion("Manganese" , info=3015) IRON = SaltVersion("Iron" , info=3016) COBALT = SaltVersion("Cobalt" , info=3017) NICKEL = SaltVersion("Nickel" , info=3018) COPPER = SaltVersion("Copper" , info=3019) ZINC = SaltVersion("Zinc" , info=3020) GALLIUM = SaltVersion("Gallium" , info=3021) GERMANIUM = SaltVersion("Germanium" , info=3022) ARSENIC = SaltVersion("Arsenic" , info=3023) SELENIUM = SaltVersion("Selenium" , info=3024) BROMINE = SaltVersion("Bromine" , info=3025) KRYPTON = SaltVersion("Krypton" , info=3026) RUBIDIUM = SaltVersion("Rubidium" , info=3027) STRONTIUM = SaltVersion("Strontium" , info=3028) YTTRIUM = SaltVersion("Yttrium" , info=3029) ZIRCONIUM = SaltVersion("Zirconium" , info=3030) NIOBIUM = SaltVersion("Niobium" , info=3031) MOLYBDENUM = SaltVersion("Molybdenum" , info=3032) TECHNETIUM = SaltVersion("Technetium" , info=3033) RUTHENIUM = SaltVersion("Ruthenium" , info=3034) RHODIUM = SaltVersion("Rhodium" , info=3035) PALLADIUM = SaltVersion("Palladium" , info=3036) SILVER = SaltVersion("Silver" , info=3037) CADMIUM = SaltVersion("Cadmium" , info=3038) INDIUM = SaltVersion("Indium" , info=3039) TIN = SaltVersion("Tin" , info=3040) ANTIMONY = SaltVersion("Antimony" , info=3041) TELLURIUM = SaltVersion("Tellurium" , info=3042) IODINE = SaltVersion("Iodine" , info=3043) XENON = SaltVersion("Xenon" , info=3044) CESIUM = SaltVersion("Cesium" , info=3045) BARIUM = SaltVersion("Barium" , info=3046) LANTHANUM = SaltVersion("Lanthanum" , info=3047) CERIUM = SaltVersion("Cerium" , info=3048) PRASEODYMIUM = SaltVersion("Praseodymium" , info=3049) NEODYMIUM = SaltVersion("Neodymium" , info=3050) PROMETHIUM = SaltVersion("Promethium" , info=3051) SAMARIUM = SaltVersion("Samarium" , info=3052) EUROPIUM = SaltVersion("Europium" , info=3053) GADOLINIUM = SaltVersion("Gadolinium" , info=3054) TERBIUM = SaltVersion("Terbium" , info=3055) DYSPROSIUM = SaltVersion("Dysprosium" , info=3056) HOLMIUM = SaltVersion("Holmium" , info=3057) ERBIUM = SaltVersion("Erbium" , info=3058) THULIUM = SaltVersion("Thulium" , info=3059) YTTERBIUM = SaltVersion("Ytterbium" , info=3060) LUTETIUM = SaltVersion("Lutetium" , info=3061) HAFNIUM = SaltVersion("Hafnium" , info=3062) TANTALUM = SaltVersion("Tantalum" , info=3063) TUNGSTEN = SaltVersion("Tungsten" , info=3064) RHENIUM = SaltVersion("Rhenium" , info=3065) OSMIUM = SaltVersion("Osmium" , info=3066) IRIDIUM = SaltVersion("Iridium" , info=3067) PLATINUM = SaltVersion("Platinum" , info=3068) GOLD = SaltVersion("Gold" , info=3069) MERCURY = SaltVersion("Mercury" , info=3070) THALLIUM = SaltVersion("Thallium" , info=3071) LEAD = SaltVersion("Lead" , info=3072) BISMUTH = SaltVersion("Bismuth" , info=3073) POLONIUM = SaltVersion("Polonium" , info=3074) ASTATINE = SaltVersion("Astatine" , info=3075) RADON = SaltVersion("Radon" , info=3076) FRANCIUM = SaltVersion("Francium" , info=3077) RADIUM = SaltVersion("Radium" , info=3078) ACTINIUM = SaltVersion("Actinium" , info=3079) THORIUM = SaltVersion("Thorium" , info=3080) PROTACTINIUM = SaltVersion("Protactinium" , info=3081) URANIUM = SaltVersion("Uranium" , info=3082) NEPTUNIUM = SaltVersion("Neptunium" , info=3083) PLUTONIUM = SaltVersion("Plutonium" , info=3084) AMERICIUM = SaltVersion("Americium" , info=3085) CURIUM = SaltVersion("Curium" , info=3086) BERKELIUM = SaltVersion("Berkelium" , info=3087) CALIFORNIUM = SaltVersion("Californium" , info=3088) EINSTEINIUM = SaltVersion("Einsteinium" , info=3089) FERMIUM = SaltVersion("Fermium" , info=3090) MENDELEVIUM = SaltVersion("Mendelevium" , info=3091) NOBELIUM = SaltVersion("Nobelium" , info=3092) LAWRENCIUM = SaltVersion("Lawrencium" , info=3093) RUTHERFORDIUM = SaltVersion("Rutherfordium", info=3094) DUBNIUM = SaltVersion("Dubnium" , info=3095) SEABORGIUM = SaltVersion("Seaborgium" , info=3096) BOHRIUM = SaltVersion("Bohrium" , info=3097) HASSIUM = SaltVersion("Hassium" , info=3098) MEITNERIUM = SaltVersion("Meitnerium" , info=3099) DARMSTADTIUM = SaltVersion("Darmstadtium" , info=3100) ROENTGENIUM = SaltVersion("Roentgenium" , info=3101) COPERNICIUM = SaltVersion("Copernicium" , info=3102) NIHONIUM = SaltVersion("Nihonium" , info=3103) FLEROVIUM = SaltVersion("Flerovium" , info=3104) MOSCOVIUM = SaltVersion("Moscovium" , info=3105) LIVERMORIUM = SaltVersion("Livermorium" , info=3106) TENNESSINE = SaltVersion("Tennessine" , info=3107) OGANESSON = SaltVersion("Oganesson" , info=3108) # <---- Please refrain from fixing whitespace ----------------------------------- # The idea is to keep this readable. # ------------------------------------------------------------------------------- # pylint: enable=bad-whitespace # fmt: on @classmethod def versions(cls): if not cls._sorted_versions: cls._sorted_versions = sorted( (getattr(cls, name) for name in dir(cls) if name.isupper()), key=operator.attrgetter("info"), ) return cls._sorted_versions @classmethod def current_release(cls): if cls._current_release is None: for version in cls.versions(): if version.released is False: cls._current_release = version break return cls._current_release @classmethod def next_release(cls): if cls._next_release is None: next_release_ahead = False for version in cls.versions(): if next_release_ahead: cls._next_release = version break if version == cls.current_release(): next_release_ahead = True return cls._next_release @classmethod def previous_release(cls): if cls._previous_release is None: previous = None for version in cls.versions(): if version == cls.current_release(): break previous = version cls._previous_release = previous return cls._previous_release class SaltStackVersion: """ Handle SaltStack versions class. Knows how to parse ``git describe`` output, knows about release candidates and also supports version comparison. """ __slots__ = ( "name", "major", "minor", "bugfix", "mbugfix", "pre_type", "pre_num", "noc", "sha", ) git_sha_regex = r"(?P<sha>g?[a-f0-9]{7,40})" git_describe_regex = re.compile( r"(?:[^\d]+)?(?P<major>[\d]{1,4})" r"(?:\.(?P<minor>[\d]{1,2}))?" r"(?:\.(?P<bugfix>[\d]{0,2}))?" r"(?:\.(?P<mbugfix>[\d]{0,2}))?" r"(?:(?P<pre_type>rc|a|b|alpha|beta|nb)(?P<pre_num>[\d]+))?" r"(?:(?:.*)(?:\+|-)(?P<noc>(?:0na|[\d]+|n/a))(?:-|\.)" + git_sha_regex + r")?" ) git_sha_regex = r"^" + git_sha_regex git_sha_regex = re.compile(git_sha_regex) NAMES = {v.name: v.info for v in SaltVersionsInfo.versions()} LNAMES = {k.lower(): v for (k, v) in iter(NAMES.items())} VNAMES = {v: k for (k, v) in iter(NAMES.items())} RMATCH = {v[:2]: k for (k, v) in iter(NAMES.items())} def __init__( self, # pylint: disable=C0103 major, minor=None, bugfix=None, mbugfix=0, pre_type=None, pre_num=None, noc=0, sha=None, ): if isinstance(major, str): major = int(major) if isinstance(minor, str): if not minor: # Empty string minor = None else: minor = int(minor) if self.can_have_dot_zero(major): minor = minor if minor else 0 if bugfix is None and not self.new_version(major=major): bugfix = 0 elif isinstance(bugfix, str): if not bugfix: bugfix = None else: bugfix = int(bugfix) if mbugfix is None: mbugfix = 0 elif isinstance(mbugfix, str): mbugfix = int(mbugfix) if pre_type is None: pre_type = "" if pre_num is None: pre_num = 0 elif isinstance(pre_num, str): pre_num = int(pre_num) if noc is None: noc = 0 elif isinstance(noc, str) and noc in ("0na", "n/a"): noc = -1 elif isinstance(noc, str): noc = int(noc) self.major = major self.minor = minor self.bugfix = bugfix self.mbugfix = mbugfix self.pre_type = pre_type self.pre_num = pre_num if self.new_version(major): vnames_key = (major,) else: vnames_key = (major, minor) self.name = self.VNAMES.get(vnames_key) self.noc = noc self.sha = sha def new_version(self, major): """ determine if using new versioning scheme """ return bool(int(major) >= 3000 and int(major) < VERSION_LIMIT) def can_have_dot_zero(self, major): """ determine if using new versioning scheme """ return bool(int(major) >= 3006 and int(major) < VERSION_LIMIT) @classmethod def parse(cls, version_string): if version_string.lower() in cls.LNAMES: return cls.from_name(version_string) vstr = ( version_string.decode() if isinstance(version_string, bytes) else version_string ) match = cls.git_describe_regex.match(vstr) if not match: raise ValueError(f"Unable to parse version string: '{version_string}'") return cls(*match.groups()) @classmethod def from_name(cls, name): if name.lower() not in cls.LNAMES: raise ValueError(f"Named version '{name}' is not known") return cls(*cls.LNAMES[name.lower()]) @classmethod def from_last_named_version(cls): import salt.utils.versions salt.utils.versions.warn_until( SaltVersionsInfo.SULFUR, "The use of SaltStackVersion.from_last_named_version() is " "deprecated and set to be removed in {version}. Please use " "SaltStackVersion.current_release() instead.", ) return cls.current_release() @classmethod def current_release(cls): return cls(*SaltVersionsInfo.current_release().info) @classmethod def next_release(cls): return cls(*SaltVersionsInfo.next_release().info) @property def sse(self): # Higher than 0.17, lower than first date based return 0 < self.major < 2014 def min_info(self): info = [self.major] if self.new_version(self.major): if self.minor: info.append(self.minor) elif self.can_have_dot_zero(self.major): info.append(self.minor) else: info.extend([self.minor, self.bugfix, self.mbugfix]) return info @property def info(self): return tuple(self.min_info()) @property def pre_info(self): info = self.min_info() info.extend([self.pre_type, self.pre_num]) return tuple(info) @property def noc_info(self): info = self.min_info() info.extend([self.pre_type, self.pre_num, self.noc]) return tuple(info) @property def full_info(self): info = self.min_info() info.extend([self.pre_type, self.pre_num, self.noc, self.sha]) return tuple(info) @property def full_info_all_versions(self): """ Return the full info regardless of which versioning scheme we are using. """ info = [ self.major, self.minor, self.bugfix, self.mbugfix, self.pre_type, self.pre_num, self.noc, self.sha, ] return tuple(info) @property def string(self): if self.new_version(self.major): version_string = f"{self.major}" if self.minor: version_string = f"{self.major}.{self.minor}" if not self.minor and self.can_have_dot_zero(self.major): version_string = f"{self.major}.{self.minor}" else: version_string = f"{self.major}.{self.minor}.{self.bugfix}" if self.mbugfix: version_string += f".{self.mbugfix}" if self.pre_type: version_string += f"{self.pre_type}{self.pre_num}" if self.noc and self.sha: noc = self.noc if noc < 0: noc = "0na" version_string += f"+{noc}.{self.sha}" return version_string @property def formatted_version(self): if self.name and self.major > 10000: version_string = self.name if self.sse: version_string += " Enterprise" version_string += " (Unreleased)" return version_string version_string = self.string if self.sse: version_string += " Enterprise" if self.new_version(self.major): rmatch_key = (self.major,) else: rmatch_key = (self.major, self.minor) if rmatch_key in self.RMATCH: version_string += f" ({self.RMATCH[rmatch_key]})" return version_string @property def pre_index(self): if self.new_version(self.major): pre_type = 2 if not isinstance(self.minor, int): pre_type = 1 else: pre_type = 4 return pre_type def __str__(self): return self.string def __compare__(self, other, method): if not isinstance(other, SaltStackVersion): if isinstance(other, str): other = SaltStackVersion.parse(other) elif isinstance(other, (list, tuple)): other = SaltStackVersion(*other) else: raise ValueError( f"Cannot instantiate Version from type '{type(other)}'" ) pre_type = self.pre_index other_pre_type = other.pre_index other_noc_info = list(other.noc_info) noc_info = list(self.noc_info) if self.new_version(self.major): if self.minor and not other.minor: # We have minor information, the other side does not if self.minor > 0: other_noc_info[1] = 0 if not self.minor and other.minor: # The other side has minor information, we don't if other.minor > 0: noc_info[1] = 0 if self.pre_type and not other.pre_type: # We have pre-release information, the other side doesn't other_noc_info[other_pre_type] = "zzzzz" if not self.pre_type and other.pre_type: # The other side has pre-release information, we don't noc_info[pre_type] = "zzzzz" return method(tuple(noc_info), tuple(other_noc_info)) def __lt__(self, other): return self.__compare__(other, lambda _self, _other: _self < _other) def __le__(self, other): return self.__compare__(other, lambda _self, _other: _self <= _other) def __eq__(self, other): return self.__compare__(other, lambda _self, _other: _self == _other) def __ne__(self, other): return self.__compare__(other, lambda _self, _other: _self != _other) def __ge__(self, other): return self.__compare__(other, lambda _self, _other: _self >= _other) def __gt__(self, other): return self.__compare__(other, lambda _self, _other: _self > _other) def __repr__(self): parts = [] if self.name: parts.append(f"name='{self.name}'") parts.extend([f"major={self.major}", f"minor={self.minor}"]) if self.new_version(self.major): if not self.can_have_dot_zero(self.major) and not self.minor: parts.remove("".join([x for x in parts if re.search("^minor*", x)])) else: parts.extend([f"bugfix={self.bugfix}"]) if self.mbugfix: parts.append(f"minor-bugfix={self.mbugfix}") if self.pre_type: parts.append(f"{self.pre_type}={self.pre_num}") noc = self.noc if noc == -1: noc = "0na" if noc and self.sha: parts.extend([f"noc={noc}", f"sha={self.sha}"]) return "<{} {}>".format(self.__class__.__name__, " ".join(parts)) # ----- Hardcoded Salt Codename Version Information -----------------------------------------------------------------> # # There's no need to do anything here. The last released codename will be picked up # -------------------------------------------------------------------------------------------------------------------- __saltstack_version__ = SaltStackVersion.current_release() # <---- Hardcoded Salt Version Information --------------------------------------------------------------------------- # ----- Dynamic/Runtime Salt Version Information --------------------------------------------------------------------> def __discover_version(saltstack_version): # This might be a 'python setup.py develop' installation type. Let's # discover the version information at runtime. import subprocess if "SETUP_DIRNAME" in globals(): # This is from the exec() call in Salt's setup.py cwd = SETUP_DIRNAME # pylint: disable=E0602 if not os.path.exists(os.path.join(cwd, ".git")): # This is not a Salt git checkout!!! Don't even try to parse... return saltstack_version else: cwd = os.path.abspath(os.path.dirname(__file__)) if not os.path.exists(os.path.join(os.path.dirname(cwd), ".git")): # This is not a Salt git checkout!!! Don't even try to parse... return saltstack_version try: kwargs = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) if not sys.platform.startswith("win"): # Let's not import `salt.utils` for the above check kwargs["close_fds"] = True process = subprocess.Popen( [ "git", "describe", "--tags", "--long", "--match", "v[0-9]*", "--always", ], **kwargs, ) out, err = process.communicate() out = out.decode().strip() err = err.decode().strip() if not out or err: return saltstack_version if SaltStackVersion.git_sha_regex.match(out): # We only define the parsed SHA and set NOC as ??? (unknown) saltstack_version.sha = out.strip() saltstack_version.noc = -1 return saltstack_version return SaltStackVersion.parse(out) except OSError as os_err: if os_err.errno != 2: # If the errno is not 2(The system cannot find the file # specified), raise the exception so it can be catch by the # developers raise return saltstack_version def __get_version(saltstack_version): """ If we can get a version provided at installation time or from Git, use that instead, otherwise we carry on. """ _hardcoded_version_file = os.path.join( os.path.dirname(os.path.abspath(__file__)), "_version.txt" ) if not os.path.exists(_hardcoded_version_file): return __discover_version(saltstack_version) with open( # pylint: disable=resource-leakage _hardcoded_version_file, encoding="utf-8" ) as rfh: return SaltStackVersion.parse(rfh.read().strip()) # Get additional version information if available __saltstack_version__ = __get_version(__saltstack_version__) if __saltstack_version__.name: # Set SaltVersionsInfo._current_release to avoid lookups when finding previous and next releases SaltVersionsInfo._current_release = getattr( SaltVersionsInfo, __saltstack_version__.name.upper() ) # This function has executed once, we're done with it. Delete it! del __get_version # <---- Dynamic/Runtime Salt Version Information --------------------------------------------------------------------- # ----- Common version related attributes - NO NEED TO CHANGE -------------------------------------------------------> __version_info__ = __saltstack_version__.info __version__ = __saltstack_version__.string # <---- Common version related attributes - NO NEED TO CHANGE -------------------------------------------------------- def salt_information(): """ Report version of salt. """ yield "Salt", __version__ def package_information(): """ Report package type """ import salt.utils.package yield "Package Type", salt.utils.package.pkg_type() def dependency_information(include_salt_cloud=False): """ Report versions of library dependencies. """ libs = [ ("Jinja2", "jinja2", "__version__"), ("M2Crypto", "M2Crypto", "version"), ("msgpack", "msgpack", "version"), ("msgpack-pure", "msgpack_pure", "version"), ("pycrypto", "Crypto", "__version__"), ("pycryptodome", "Cryptodome", "version_info"), ("PyYAML", "yaml", "__version__"), ("PyZMQ", "zmq", "__version__"), ("ZMQ", "zmq", "zmq_version"), ("Mako", "mako", "__version__"), ("Tornado", "tornado", "version"), ("timelib", "timelib", "version"), ("dateutil", "dateutil", "__version__"), ("pygit2", "pygit2", "__version__"), ("libgit2", "pygit2", "LIBGIT2_VERSION"), ("smmap", "smmap", "__version__"), ("cffi", "cffi", "__version__"), ("pycparser", "pycparser", "__version__"), ("gitdb", "gitdb", "__version__"), ("gitpython", "git", "__version__"), ("python-gnupg", "gnupg", "__version__"), ("mysql-python", "MySQLdb", "__version__"), ("cherrypy", "cherrypy", "__version__"), ("docker-py", "docker", "__version__"), ("packaging", "packaging", "__version__"), ("looseversion", "looseversion", None), ("relenv", "relenv", "__version__"), ] if include_salt_cloud: libs.append( ("Apache Libcloud", "libcloud", "__version__"), ) def _sort_by_lowercased_name(entry): return entry[0].lower() for name, imp, attr in sorted(libs, key=_sort_by_lowercased_name): if imp is None: yield name, attr continue try: if attr is None: # Late import to reduce the needed available modules and libs # installed when running `python salt/version.py` from salt._compat import importlib_metadata version = importlib_metadata.version(imp) yield name, version continue imp = __import__(imp) version = getattr(imp, attr) if callable(version): version = version() if isinstance(version, (tuple, list)): version = ".".join(map(str, version)) yield name, version except Exception: # pylint: disable=broad-except yield name, None def system_information(): """ Report system versions. """ # Late import so that when getting called from setup.py does not break from salt.utils.platform import linux_distribution def system_version(): """ Return host system version. """ lin_ver = linux_distribution() mac_ver = platform.mac_ver() win_ver = platform.win32_ver() # linux_distribution() will return a # distribution on OS X and Windows. # Check mac_ver and win_ver first, # then lin_ver. if mac_ver[0]: if isinstance(mac_ver[1], (tuple, list)) and "".join(mac_ver[1]): return " ".join([mac_ver[0], ".".join(mac_ver[1]), mac_ver[2]]) else: return " ".join([mac_ver[0], mac_ver[2]]) elif win_ver[0]: return " ".join(win_ver) elif lin_ver[0]: return " ".join(lin_ver) else: return "" if platform.win32_ver()[0]: # Get the version and release info based on the Windows Operating # System Product Name. As long as Microsoft maintains a similar format # this should be future proof import win32api # pylint: disable=3rd-party-module-not-gated import win32con # pylint: disable=3rd-party-module-not-gated # Get the product name from the registry hkey = win32con.HKEY_LOCAL_MACHINE key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" value_name = "ProductName" reg_handle = win32api.RegOpenKey(hkey, key) # Returns a tuple of (product_name, value_type) product_name, _ = win32api.RegQueryValueEx(reg_handle, value_name) version = "Unknown" release = "" if "Server" in product_name: for item in product_name.split(" "): # If it's all digits, then it's version if re.match(r"\d+", item): version = item # If it starts with R and then numbers, it's the release # ie: R2 if re.match(r"^R\d+$", item): release = item release = f"{version}Server{release}" else: for item in product_name.split(" "): # If it's a number, decimal number, Thin or Vista, then it's the # version if re.match(r"^(\d+(\.\d+)?)|Thin|Vista$", item): version = item release = version _, ver, service_pack, extra = platform.win32_ver() version = " ".join([release, ver, service_pack, extra]) else: version = system_version() release = platform.release() system = [ ("system", platform.system()), ("dist", " ".join(linux_distribution(full_distribution_name=False))), ("release", release), ("machine", platform.machine()), ("version", version), ("locale", __salt_system_encoding__), ] for name, attr in system: yield name, attr continue def extensions_information(): """ Gather infomation about any installed salt extensions """ # Late import import salt.utils.entrypoints extensions = {} for entry_point in salt.utils.entrypoints.iter_entry_points("salt.loader"): dist_nv = salt.utils.entrypoints.name_and_version_from_entry_point(entry_point) if not dist_nv: continue if dist_nv.name in extensions: continue extensions[dist_nv.name] = dist_nv.version return extensions def versions_information(include_salt_cloud=False, include_extensions=True): """ Report the versions of dependent software. """ py_info = [ ("Python", sys.version.rsplit("\n", maxsplit=1)[0].strip()), ] salt_info = list(salt_information()) lib_info = list(dependency_information(include_salt_cloud)) sys_info = list(system_information()) package_info = list(package_information()) info = { "Salt Version": dict(salt_info), "Python Version": dict(py_info), "Dependency Versions": dict(lib_info), "System Versions": dict(sys_info), "Salt Package Information": dict(package_info), } if include_extensions: extensions_info = extensions_information() if extensions_info: info["Salt Extensions"] = extensions_info return info def versions_report(include_salt_cloud=False, include_extensions=True): """ Yield each version properly formatted for console output. """ ver_info = versions_information( include_salt_cloud=include_salt_cloud, include_extensions=include_extensions ) not_installed = "Not Installed" ns_pad = len(not_installed) lib_pad = max(len(name) for name in ver_info["Dependency Versions"]) sys_pad = max(len(name) for name in ver_info["System Versions"]) if include_extensions and "Salt Extensions" in ver_info: ext_pad = max(len(name) for name in ver_info["Salt Extensions"]) else: ext_pad = 1 padding = max(lib_pad, sys_pad, ns_pad, ext_pad) + 1 fmt = "{0:>{pad}}: {1}" info = [] for ver_type in ( "Salt Version", "Python Version", "Dependency Versions", "Salt Extensions", "Salt Package Information", "System Versions", ): if ver_type == "Salt Extensions" and ver_type not in ver_info: # No salt Extensions to report continue info.append(f"{ver_type}:") # List dependencies in alphabetical, case insensitive order for name in sorted(ver_info[ver_type], key=lambda x: x.lower()): ver = fmt.format( name, ver_info[ver_type][name] or not_installed, pad=padding ) info.append(ver) info.append(" ") yield from info def _parser(): parser = argparse.ArgumentParser() parser.add_argument( "--next-release", help="Return the next release", action="store_true" ) parser.add_argument("--parse", help="Parse the passed string as a salt version") # When pip installing we pass in other args to this script. # This allows us to catch those args but not use them parser.add_argument("unknown", nargs=argparse.REMAINDER) return parser.parse_args() if __name__ == "__main__": args = _parser() if args.next_release: print(__saltstack_version__.next_release()) elif args.parse: try: print(SaltStackVersion.parse(args.parse)) except Exception as exc: # pylint: disable=broad-except print(f"Failed to parse '{args.parse}' as a salt version: {exc}") sys.exit(1) else: print(__version__)