def test_get_distro_name(self, _): """Very basic test cases for `get_distro_name` static method""" self.assertEqual( Distributions.get_distro_name(), 'Debian GNU/Linux 10 (buster)' ) self.assertIsNone(Distributions.get_distro_name())
def test_darwin_detection(self, _, __, ___, ____): """Test OS detection for Darwin""" # Detection based on `distro`. self.assertEqual(Distributions.get_local(), Distributions.DARWIN) # Detection based on `platform`. self.assertEqual(Distributions.get_local(), Distributions.DARWIN)
def test_get_ansi_color(self, _): """Very basic test cases for `get_ansi_color` static method""" self.assertEqual( Distributions.get_ansi_color(), '33;1', ) self.assertIsNone(Distributions.get_ansi_color())
def __init__(self): # First we check whether the Kernel has been compiled as a WSL. if 'microsoft' in check_output(['uname', '-r'], universal_newlines=True).lower(): self._distribution = Distributions.WINDOWS else: try: self._distribution = Distributions(distro.id()) except ValueError: # See <https://www.freedesktop.org/software/systemd/man/os-release.html#ID_LIKE=>. for distro_like in distro.like().split(' '): try: self._distribution = Distributions(distro_like) except ValueError: continue break else: # Well, we didn't match anything so let's fall-back to default `Linux`. self._distribution = Distributions.LINUX # Fetch the colors palette related to this distribution. self._colors_palette = COLOR_DICT[self._distribution] # If `os-release`'s `ANSI_COLOR` option is set, honor it. # See <https://www.freedesktop.org/software/systemd/man/os-release.html#ANSI_COLOR=>. ansi_color = distro.os_release_attr('ansi_color') if ansi_color and Configuration().get( 'colors_palette')['honor_ansi_color']: # Replace each Archey integrated colors by `ANSI_COLOR`. self._colors_palette = len(self._colors_palette) * \ [Colors.escape_code_from_attrs(ansi_color)] # Each class output will be added in the list below afterwards self._results = []
def __init__(self, **kwargs): # Fetches passed arguments. self._format_to_json = kwargs.get('format_to_json') # type: int try: # If set, force the distribution to `preferred_distribution` argument. self._distribution = Distributions(kwargs.get('preferred_distribution')) except ValueError: # If not (or unknown), run distribution detection. self._distribution = Distributions.run_detection() # Retrieve distribution's logo module before copying and DRY-ing its attributes. logo_module = lazy_load_logo_module(self._distribution.value) self._logo, self._colors = logo_module.LOGO.copy(), logo_module.COLORS.copy() # If `os-release`'s `ANSI_COLOR` option is set, honor it. ansi_color = Distributions.get_ansi_color() if ansi_color and Configuration().get('honor_ansi_color'): # Replace each Archey integrated colors by `ANSI_COLOR`. self._colors = len(self._colors) * [Colors.escape_code_from_attrs(ansi_color)] # Each entry will be added to this list self._entries = [] # Each class output will be added in the list below afterwards self._results = []
def __init__(self, **kwargs): # Fetches passed arguments. self._format_to_json = kwargs.get('format_to_json') try: # If set, force the distribution to `preferred_distribution` argument. self._distribution = Distributions( kwargs.get('preferred_distribution')) except ValueError: # If not (or unknown), run distribution detection. self._distribution = Distributions.run_detection() # Fetch the colors palette related to this distribution. self._colors_palette = COLORS_DICT[self._distribution] # If `os-release`'s `ANSI_COLOR` option is set, honor it. ansi_color = Distributions.get_ansi_color() if ansi_color and Configuration().get( 'colors_palette')['honor_ansi_color']: # Replace each Archey integrated colors by `ANSI_COLOR`. self._colors_palette = len(self._colors_palette) * \ [Colors.escape_code_from_attrs(ansi_color)] # Each entry will be added to this list self._entries = [] # Each class output will be added in the list below afterwards self._results = []
def test_constant_values(self): """Test enumeration member instantiation from value""" self.assertEqual(Distributions('debian'), Distributions.DEBIAN) self.assertRaises(ValueError, Distributions, 'unknown') # Check `get_distribution_identifiers` consistency. distribution_identifiers = Distributions.get_distribution_identifiers() self.assertTrue(isinstance(distribution_identifiers, list)) self.assertTrue(all(isinstance(i, str) for i in distribution_identifiers))
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for packages_tool in PACKAGES_TOOLS: if 'only_on' in packages_tool \ and Distributions.get_local() not in packages_tool['only_on']: continue try: results = check_output( packages_tool['cmd'], stderr=DEVNULL, env={ 'LANG': 'C', # Alpine Linux: We have to manually propagate `PATH`. # `apk` wouldn't be found otherwise. 'PATH': os.getenv('PATH') }, universal_newlines=True) except (OSError, CalledProcessError): continue # Here we *may* use `\n` as `universal_newlines` has been set. if self.value: self.value += results.count('\n') else: self.value = results.count('\n') # If any, deduct output skew present due to the packages tool itself. if 'skew' in packages_tool: self.value -= packages_tool['skew'] # For DPKG only, remove any not purged package. if packages_tool['cmd'][0] == 'dpkg': self.value -= results.count('deinstall')
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) distro_name = Distributions.get_distro_name() if not distro_name: distro_name = self._fetch_android_release() self.value = {'name': distro_name, 'arch': platform.machine()}
def __init__(self, **kwargs): # Fetches passed arguments. self._format_to_json = kwargs.get('format_to_json') preferred_logo_style = (kwargs.get('preferred_logo_style') or '').upper() try: # If set, force the distribution to `preferred_distribution` argument. self._distribution = Distributions( kwargs.get('preferred_distribution')) except ValueError: # If not (or unknown), run distribution detection. self._distribution = Distributions.get_local() # Retrieve distribution's logo module before copying and DRY-ing its attributes. logo_module = lazy_load_logo_module(self._distribution.value) # If set and available, fetch an alternative logo style from module. if preferred_logo_style and hasattr(logo_module, f"LOGO_{preferred_logo_style}"): self._logo = getattr(logo_module, f"LOGO_{preferred_logo_style}").copy() self._colors = getattr(logo_module, f"COLORS_{preferred_logo_style}").copy() else: self._logo, self._colors = logo_module.LOGO.copy( ), logo_module.COLORS.copy() configuration = Configuration() # If `os-release`'s `ANSI_COLOR` option is set, honor it. ansi_color = Distributions.get_ansi_color() if ansi_color and configuration.get("honor_ansi_color"): # Replace each Archey integrated colors by `ANSI_COLOR`. self._colors = len( self._colors) * [Colors.escape_code_from_attrs(ansi_color)] entries_color = configuration.get("entries_color") self._entries_color = (Colors.escape_code_from_attrs(entries_color) if entries_color else self._colors[0]) # Each entry will be added to this list self._entries = [] # Each class output will be added in the list below afterwards self._results = []
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if platform.system() == 'Darwin': distro_name = self._fetch_darwin_release() else: distro_name = Distributions.get_distro_name() or \ self._fetch_android_release() self.value = {'name': distro_name, 'arch': platform.machine()}
def args_parsing() -> argparse.Namespace: """Simple wrapper to `argparse`""" parser = argparse.ArgumentParser(prog='archey') parser.add_argument( '-c', '--config-path', metavar='PATH', help= 'path to a configuration file, or a directory containing a `config.json`' ) parser.add_argument( '-d', '--distribution', metavar='IDENTIFIER', choices=Distributions.get_identifiers(), help= 'supported distribution identifier to show the logo of, pass `unknown` to list them' ) parser.add_argument( '-j', '--json', action='count', help= 'output entries data to JSON format, use multiple times to increase indentation' ) parser.add_argument( '-l', '--logo-style', metavar='IDENTIFIER', help= "alternative logo style identifier to show instead of the distribution default one. " "For instance, you can try 'retro' to prefer old Apple's logo on Darwin platforms" ) parser.add_argument( '-s', '--screenshot', metavar='PATH', nargs='?', const=False, help= 'take a screenshot once execution is done, optionally specify a target path' ) parser.add_argument('-v', '--version', action='version', version=__version__) return parser.parse_args()
def json_serialization(self, indent: int = 0) -> str: """ JSON serialization of entries. Set `indent` to the number of wanted output indentation tabs (2-space long). """ document = { 'data': {entry.name: entry.value for entry in self.entries}, 'meta': { 'version': Utility.version_to_semver_segments(__version__), 'date': datetime.now().isoformat(), 'count': len(self.entries), 'distro': Distributions.get_local().value, } } return json.dumps(document, indent=((indent * 2) or None))
def args_parsing(): """Simple wrapper to `argparse`""" parser = argparse.ArgumentParser(prog='archey') parser.add_argument( '-c', '--config-path', metavar='PATH', help= 'path to a configuration file, or a directory containing a `config.json`' ) parser.add_argument( '-d', '--distribution', metavar='IDENTIFIER', choices=Distributions.get_distribution_identifiers(), help= 'supported distribution identifier to show the logo of, pass `unknown` to list them' ) parser.add_argument( '-j', '--json', action='count', help= 'output entries data to JSON format, use multiple times to increase indentation' ) parser.add_argument( '-s', '--screenshot', metavar='PATH', nargs='?', const=False, help= 'take a screenshot once execution is done, optionally specify a target path' ) parser.add_argument('-v', '--version', action='version', version=__version__) return parser.parse_args()
def test_distribution_logos_consistency(self): """ Verify each distribution identifier got a logo module. Verify each distribution logo module contain `LOGO` & `COLORS` ("truthy") attributes. Also check they got _consistent_ widths across their respective lines. Additionally verify they don't contain any (useless) empty line. This test also indirectly checks `lazy_load_logo_module` behavior! """ distributions_identifiers = Distributions.get_identifiers() for i, logo_module_info in enumerate(pkgutil.iter_modules( logos.__path__), start=1): # Check each logo module name corresponds to a distribution identifier. self.assertIn( logo_module_info.name, distributions_identifiers, msg=f'No distribution identifier for [{logo_module_info.name}]' ) logo_module = lazy_load_logo_module(logo_module_info.name) # Attributes checks. self.assertTrue( getattr(logo_module, 'LOGO', []), msg= f'[{logo_module_info.name}] logo module missing `LOGO` attribute' ) self.assertTrue( getattr(logo_module, 'COLORS', []), msg= f'[{logo_module_info.name}] logo module missing `COLORS` attribute' ) # Compute once and for all the number of defined colors for this logo. nb_colors = len(logo_module.COLORS) # Make Archey compute the logo (effective) width. logo_width = get_logo_width(logo_module.LOGO, nb_colors) # Then, check that each logo line got the same effective width. for j, line in enumerate(logo_module.LOGO[1:], start=1): # Here we gotta trick the `get_logo_width` call. # We actually pass each logo line as if it was a "complete" logo. line_width = get_logo_width([line], nb_colors) # Width check. self.assertEqual( line_width, logo_width, msg= '[{}] line index {}, got an unexpected width {} (expected {})' .format(logo_module_info.name, j, line_width, logo_width)) # Non-empty line check. self.assertTrue( Colors.remove_colors(line.format(c=[''] * nb_colors)).strip(), msg= f'[{logo_module_info.name}] line index {j}, got an useless empty line' ) # Finally, check each distributions identifier got a logo! # pylint: disable=undefined-loop-variable self.assertEqual(i, len(distributions_identifiers), msg='[{}] Expected {} logo modules, got {}'.format( logo_module_info.name, len(distributions_identifiers), i))
def test_distribution_logos_consistency(self): """ Verify each distribution identifier got a logo module. Verify each distribution logo module contain `LOGO` & `COLORS` ("truthy") attributes. Also check they got _consistent_ widths across their respective lines. Additionally verify they don't contain any (useless) empty line. This test also indirectly checks `lazy_load_logo_module` behavior! """ distributions_identifiers = Distributions.get_distribution_identifiers( ) for i, logo_module_info in enumerate(pkgutil.iter_modules( logos.__path__), start=1): # `iter_modules` yields `pkgutil.ModuleInfo` named tuple starting with Python 3.6. # So we manually extract the module name from `(module_finder, name, ispkg)` tuple. logo_module_name = logo_module_info[1] # Check each logo module name corresponds to a distribution identifier. self.assertIn(logo_module_name, distributions_identifiers, msg='No distribution identifier for [{0}]'.format( logo_module_name)) logo_module = lazy_load_logo_module(logo_module_name) # Attributes checks. self.assertTrue( getattr(logo_module, 'LOGO', []), msg='[{0}] logo module missing `LOGO` attribute'.format( logo_module_name)) self.assertTrue( getattr(logo_module, 'COLORS', []), msg='[{0}] logo module missing `COLORS` attribute'.format( logo_module_name)) # Make Archey compute the logo width. logo_width = get_logo_width(logo_module.LOGO) # Then, check that each logo line got the same effective width. for j, line in enumerate(logo_module.LOGO[1:], start=1): # Here we gotta trick the `get_logo_width` call. # We actually pass each logo line as if it was a "complete" logo. line_width = get_logo_width([line]) # Width check. self.assertEqual( line_width, logo_width, msg= '[{0}] line index {1}, got an unexpected width {2} (expected {3})' .format(logo_module_name, j, line_width, logo_width)) # Non-empty line check. self.assertTrue( Colors.remove_colors(line).strip(), msg='[{0}] line index {1}, got an useless empty line'. format(logo_module_name, j)) # Finally, check each distributions identifier got a logo! # pylint: disable=undefined-loop-variable self.assertEqual(i, len(distributions_identifiers), msg='[{0}] Expected {1} logo modules, got {2}'.format( logo_module_name, len(distributions_identifiers), i))
def test_run_detection_distro_like_second(self, _, __, ___): """Test distribution matching from the `os-release`'s `ID_LIKE` option (second candidate)""" self.assertEqual(Distributions.run_detection(), Distributions.ARCH)
def test_run_detection_known_distro_like(self, _, __, ___): """Test distribution matching from the `os-release`'s `ID_LIKE` option""" self.assertEqual(Distributions.run_detection(), Distributions.UBUNTU)
def test_run_detection_unknown_distro_id(self, _, __, ___, ____): """Test unknown distribution output""" self.assertEqual(Distributions.run_detection(), Distributions.LINUX)
def test_run_detection_windows_subsystem(self, _): """Test output for Windows Subsystem Linux""" self.assertEqual(Distributions.run_detection(), Distributions.WINDOWS)
def test_run_detection_windows(self): """Test output for Windows""" self.assertEqual(Distributions.run_detection(), Distributions.WINDOWS)
def test_run_detection_specific_android(self, _, __): """Test Android specific detection""" self.assertEqual(Distributions.run_detection(), Distributions.ANDROID)
def test_run_detection_specific_crunchbang(self, _, __, ___): """Test CrunchBang specific detection""" self.assertEqual(Distributions.run_detection(), Distributions.CRUNCHBANG)
def test_run_detection_both_distro_calls_fail(self, _, __, ___, ____): """Test distribution fall-back when `distro` soft-fail two times""" self.assertEqual(Distributions.run_detection(), Distributions.LINUX)
def test_get_local_windows(self, _): """Test output for Windows""" self.assertEqual(Distributions.get_local(), Distributions.WINDOWS)
def test_get_local_windows_subsystem(self, _, __): """Test output for Windows Subsystem Linux""" self.assertEqual(Distributions.get_local(), Distributions.WINDOWS)
def test_get_local_unknown_distro_id(self, _, __, ___, ____, _____): """Test unknown distribution output""" self.assertEqual(Distributions.get_local(), Distributions.LINUX)