def list_available_extensions(index_url=None, show_details=False): index_data = get_index_extensions(index_url=index_url) if show_details: return index_data installed_extensions = get_extensions() installed_extension_names = [e.name for e in installed_extensions] results = [] for name, items in OrderedDict(sorted(index_data.items())).items(): # exclude extensions/versions incompatible with current CLI version items = [item for item in items if ext_compat_with_cli(item['metadata'])[0]] if not items: continue latest = max(items, key=lambda c: parse_version(c['metadata']['version'])) installed = False if name in installed_extension_names: installed = True ext_version = get_extension(name).version if ext_version and parse_version(latest['metadata']['version']) > parse_version(ext_version): installed = str(True) + ' (upgrade available)' results.append({ 'name': name, 'version': latest['metadata']['version'], 'summary': latest['metadata']['summary'], 'preview': latest['metadata'].get(EXT_METADATA_ISPREVIEW, False), 'installed': installed }) return results
def get_az_version_string(): import platform from azure.cli.core.extension import get_extensions, EXTENSIONS_DIR, DEV_EXTENSION_SOURCES output = six.StringIO() installed_dists = get_installed_cli_distributions() cli_info = None for dist in installed_dists: if dist.key == CLI_PACKAGE_NAME: cli_info = {'name': dist.key, 'version': dist.version} break def _print(val=''): print(val, file=output) if cli_info: _print('{} ({})'.format(cli_info['name'], cli_info['version'])) component_version_info = sorted([{'name': dist.key.replace(COMPONENT_PREFIX, ''), 'version': dist.version} for dist in installed_dists if dist.key.startswith(COMPONENT_PREFIX)], key=lambda x: x['name']) _print() _print('\n'.join(['{} ({})'.format(c['name'], c['version']) for c in component_version_info])) _print() extensions = get_extensions() if extensions: _print('Extensions:') for ext in extensions: if ext.ext_type == 'dev': _print('{} ({}) [{}]'.format(ext.name, ext.version, ext.path)) else: _print('{} ({})'.format(ext.name, ext.version)) _print() _print("Python location '{}'".format(sys.executable)) _print("Extensions directory '{}'".format(EXTENSIONS_DIR)) if DEV_EXTENSION_SOURCES: _print("Development extension sources:") for source in DEV_EXTENSION_SOURCES: _print(' {}'.format(source)) _print() _print('Python ({}) {}'.format(platform.system(), sys.version)) _print() _print('Legal docs and information: aka.ms/AzureCliLegal') _print() version_string = output.getvalue() return version_string
def _update_command_table_from_extensions(ext_suppressions): def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions extensions = get_extensions() if extensions: logger.debug("Found %s extensions: %s", len(extensions), [e.name for e in extensions]) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) for ext in allowed_extensions: ext_name = ext.name ext_dir = ext.path or get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning("Unable to load extension '%s'. Use --debug for more information.", ext_name) logger.debug(traceback.format_exc())
def get_extension_modules(): from importlib import import_module import pkgutil from azure.cli.core.extension import get_extensions, get_extension_path, get_extension_modname extension_whls = get_extensions() ext_modules = [] if extension_whls: for ext_name in [e.name for e in extension_whls]: ext_dir = get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) module = import_module(ext_mod) setattr(module, 'path', module.__path__[0]) ext_modules.append((module, ext_mod)) except Exception as ex: display("Error importing '{}' extension: {}".format(ext_mod, ex)) return ext_modules
def get_az_version_string(): import platform from azure.cli.core.extension import get_extensions, EXTENSIONS_DIR output = six.StringIO() installed_dists = get_installed_cli_distributions() cli_info = None for dist in installed_dists: if dist.key == CLI_PACKAGE_NAME: cli_info = {'name': dist.key, 'version': dist.version} break if cli_info: print('{} ({})'.format(cli_info['name'], cli_info['version']), file=output) component_version_info = sorted([{'name': dist.key.replace(COMPONENT_PREFIX, ''), 'version': dist.version} for dist in installed_dists if dist.key.startswith(COMPONENT_PREFIX)], key=lambda x: x['name']) print(file=output) print('\n'.join(['{} ({})'.format(c['name'], c['version']) for c in component_version_info]), file=output) print(file=output) extensions = get_extensions() if extensions: print('Extensions:', file=output) print('\n'.join(['{} ({})'.format(c.name, c.version) for c in extensions]), file=output) print(file=output) print("Python location '{}'".format(sys.executable), file=output) print("Extensions directory '{}'".format(EXTENSIONS_DIR), file=output) print(file=output) print('Python ({}) {}'.format(platform.system(), sys.version), file=output) print(file=output) print('Legal docs and information: aka.ms/AzureCliLegal', file=output) print(file=output) version_string = output.getvalue() return version_string
def list_available_extensions(index_url=None, show_details=False): index_data = get_index_extensions(index_url=index_url) if show_details: return index_data installed_extensions = get_extensions() installed_extension_names = [e.name for e in installed_extensions] results = [] for name, items in OrderedDict(sorted(index_data.items())).items(): latest = sorted(items, key=lambda c: parse_version(c['metadata']['version']), reverse=True)[0] installed = False if name in installed_extension_names: installed = True ext_version = get_extension(name).version if ext_version and parse_version(latest['metadata']['version']) > parse_version(ext_version): installed = str(True) + ' (upgrade available)' results.append({ 'name': name, 'version': latest['metadata']['version'], 'summary': latest['metadata']['summary'], 'preview': latest['metadata'].get(EXT_METADATA_ISPREVIEW, False), 'installed': installed }) return results
def get_az_version_string(): from azure.cli.core.extension import get_extensions, EXTENSIONS_DIR, DEV_EXTENSION_SOURCES output = six.StringIO() versions = {} # get locally installed versions for dist in get_installed_cli_distributions(): if dist.key == CLI_PACKAGE_NAME: versions[CLI_PACKAGE_NAME] = {'local': dist.version} elif dist.key.startswith(COMPONENT_PREFIX): comp_name = dist.key.replace(COMPONENT_PREFIX, '') versions[comp_name] = {'local': dist.version} # get the versions from pypi versions, success = _update_latest_from_pypi(versions) updates_available = 0 def _print(val=''): print(val, file=output) def _get_version_string(name, version_dict): from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module local = version_dict['local'] pypi = version_dict.get('pypi', None) if pypi and LooseVersion(pypi) > LooseVersion(local): return name.ljust(25) + local.rjust(15) + ' *' return name.ljust(25) + local.rjust(15) ver_string = _get_version_string(CLI_PACKAGE_NAME, versions.pop(CLI_PACKAGE_NAME)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() for name in sorted(versions.keys()): ver_string = _get_version_string(name, versions.pop(name)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() extensions = get_extensions() if extensions: _print('Extensions:') for ext in extensions: if ext.ext_type == 'dev': _print( ext.name.ljust(20) + ext.version.rjust(20) + ' (dev) ' + ext.path) else: _print( ext.name.ljust(20) + (ext.version or 'Unknown').rjust(20)) _print() _print("Python location '{}'".format(sys.executable)) _print("Extensions directory '{}'".format(EXTENSIONS_DIR)) if DEV_EXTENSION_SOURCES: _print("Development extension sources:") for source in DEV_EXTENSION_SOURCES: _print(' {}'.format(source)) _print() _print('Python ({}) {}'.format(platform.system(), sys.version)) _print() _print('Legal docs and information: aka.ms/AzureCliLegal') _print() version_string = output.getvalue() # if unable to query PyPI, use sentinel value to flag that # we couldn't check for updates if not success: updates_available = -1 return version_string, updates_available
def list_extensions(): return [{OUT_KEY_NAME: ext.name, OUT_KEY_VERSION: ext.version, OUT_KEY_TYPE: ext.ext_type} for ext in get_extensions()]
def get_az_version_string(): import platform from azure.cli.core.extension import get_extensions, EXTENSIONS_DIR, DEV_EXTENSION_SOURCES output = six.StringIO() versions = {} # get locally installed versions for dist in get_installed_cli_distributions(): if dist.key == CLI_PACKAGE_NAME: versions[CLI_PACKAGE_NAME] = {'local': dist.version} elif dist.key.startswith(COMPONENT_PREFIX): comp_name = dist.key.replace(COMPONENT_PREFIX, '') versions[comp_name] = {'local': dist.version} # get the versions from pypi versions, success = _update_latest_from_pypi(versions) updates_available = 0 def _print(val=''): print(val, file=output) def _get_version_string(name, version_dict): from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module local = version_dict['local'] pypi = version_dict.get('pypi', None) if pypi and LooseVersion(pypi) > LooseVersion(local): return name.ljust(20) + local.rjust(20) + ' *' return name.ljust(20) + local.rjust(20) ver_string = _get_version_string(CLI_PACKAGE_NAME, versions.pop(CLI_PACKAGE_NAME)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() for name in sorted(versions.keys()): ver_string = _get_version_string(name, versions.pop(name)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() extensions = get_extensions() if extensions: _print('Extensions:') for ext in extensions: if ext.ext_type == 'dev': _print(ext.name.ljust(20) + ext.version.rjust(20) + ' (dev) ' + ext.path) else: _print(ext.name.ljust(20) + (ext.version or 'Unknown').rjust(20)) _print() _print("Python location '{}'".format(sys.executable)) _print("Extensions directory '{}'".format(EXTENSIONS_DIR)) if DEV_EXTENSION_SOURCES: _print("Development extension sources:") for source in DEV_EXTENSION_SOURCES: _print(' {}'.format(source)) _print() _print('Python ({}) {}'.format(platform.system(), sys.version)) _print() _print('Legal docs and information: aka.ms/AzureCliLegal') _print() version_string = output.getvalue() # if unable to query PyPI, use sentinel value to flag that # we couldn't check for updates if not success: updates_available = -1 return version_string, updates_available
def test_extension_list(self): _install_test_extension1() actual = get_extensions() self.assertEqual(len(actual), 1)
def test_other_files_in_extensions_dir(self): tempfile.mkstemp(dir=self.ext_dir) actual = get_extensions() self.assertEqual(len(actual), 0)
def test_no_extensions_in_dir(self): """ Directory exists but there are no extensions """ actual = get_extensions() self.assertEqual(len(actual), 0)
def test_no_extensions_dir(self): """ Extensions directory doesn't exist """ shutil.rmtree(self.ext_dir) actual = get_extensions() self.assertEqual(len(actual), 0)
def _update_command_table_from_extensions(ext_suppressions): from azure.cli.core.extension.operations import check_version_compatibility def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions extensions = get_extensions() if extensions: logger.debug("Found %s extensions: %s", len(extensions), [e.name for e in extensions]) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) for ext in allowed_extensions: try: check_version_compatibility(ext.get_metadata()) except CLIError as ex: # issue warning and skip loading extensions that aren't compatible with the CLI core logger.warning(ex) continue ext_name = ext.name ext_dir = ext.path or get_extension_path(ext_name) logger.debug("Extensions directory: '%s'", ext_dir) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview, experimental=ext.experimental) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug("Loaded extension '%s' in %.3f seconds.", ext_name, elapsed_time) except Exception as ex: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning( "Unable to load extension '%s: %s'. Use --debug for more information.", ext_name, ex) logger.debug(traceback.format_exc())
def _update_command_table_from_extensions(ext_suppressions, extension_modname=None): """Loads command tables from extensions and merge into the main command table. :param ext_suppressions: Extension suppression information. :param extension_modname: Command modules to load, in the format like ['azext_timeseriesinsights']. If None, will do extension discovery and load all extensions. If [], only ALWAYS_LOADED_EXTENSIONS will be loaded. Otherwise, the list will be extended using ALWAYS_LOADED_EXTENSIONS. If the extensions in the list are not installed, it will be skipped. """ def _handle_extension_suppressions(extensions): filtered_extensions = [] for ext in extensions: should_include = True for suppression in ext_suppressions: if should_include and suppression.handle_suppress(ext): should_include = False if should_include: filtered_extensions.append(ext) return filtered_extensions def _filter_modname(extensions): # Extension's name may not be the same as its modname. eg. name: virtual-wan, modname: azext_vwan filtered_extensions = [] for ext in extensions: ext_mod = get_extension_modname(ext.name, ext.path) # Filter the extensions according to the index if ext_mod in extension_modname: filtered_extensions.append(ext) extension_modname.remove(ext_mod) if extension_modname: logger.debug("These extensions are not installed and will be skipped: %s", extension_modname) return filtered_extensions extensions = get_extensions() if extensions: if extension_modname is not None: extension_modname.extend(ALWAYS_LOADED_EXTENSIONS) extensions = _filter_modname(extensions) allowed_extensions = _handle_extension_suppressions(extensions) module_commands = set(self.command_table.keys()) count = 0 cumulative_elapsed_time = 0 cumulative_group_count = 0 cumulative_command_count = 0 logger.debug("Loading extensions:") logger.debug(self.header_ext) for ext in allowed_extensions: try: # Import in the `for` loop because `allowed_extensions` can be []. In such case we # don't need to import `check_version_compatibility` at all. from azure.cli.core.extension.operations import check_version_compatibility check_version_compatibility(ext.get_metadata()) except CLIError as ex: # issue warning and skip loading extensions that aren't compatible with the CLI core logger.warning(ex) continue ext_name = ext.name ext_dir = ext.path or get_extension_path(ext_name) sys.path.append(ext_dir) try: ext_mod = get_extension_modname(ext_name, ext_dir=ext_dir) # Add to the map. This needs to happen before we load commands as registering a command # from an extension requires this map to be up-to-date. # self._mod_to_ext_map[ext_mod] = ext_name start_time = timeit.default_timer() extension_command_table, extension_group_table = \ _load_extension_command_loader(self, args, ext_mod) for cmd_name, cmd in extension_command_table.items(): cmd.command_source = ExtensionCommandSource( extension_name=ext_name, overrides_command=cmd_name in module_commands, preview=ext.preview, experimental=ext.experimental) self.command_table.update(extension_command_table) self.command_group_table.update(extension_group_table) elapsed_time = timeit.default_timer() - start_time logger.debug(self.item_ext_format_string, ext_name, elapsed_time, len(extension_group_table), len(extension_command_table), ext_dir) count += 1 cumulative_elapsed_time += elapsed_time cumulative_group_count += len(extension_group_table) cumulative_command_count += len(extension_command_table) except Exception as ex: # pylint: disable=broad-except self.cli_ctx.raise_event(EVENT_FAILED_EXTENSION_LOAD, extension_name=ext_name) logger.warning("Unable to load extension '%s: %s'. Use --debug for more information.", ext_name, ex) logger.debug(traceback.format_exc()) # Summary line logger.debug(self.item_ext_format_string, "Total ({})".format(count), cumulative_elapsed_time, cumulative_group_count, cumulative_command_count, "")
def upgrade_version(cmd, update_all=None, yes=None): # pylint: disable=too-many-locals, too-many-statements, too-many-branches, no-member, unused-argument import os import platform import sys import subprocess import azure.cli.core.telemetry as telemetry from azure.cli.core import __version__ as local_version from azure.cli.core._environment import _ENV_AZ_INSTALLER from azure.cli.core.extension import get_extensions, WheelExtension from distutils.version import LooseVersion from knack.util import CLIError update_cli = True from azure.cli.core.util import get_latest_from_github try: latest_version = get_latest_from_github() if latest_version and LooseVersion(latest_version) <= LooseVersion( local_version): logger.warning("You already have the latest azure-cli version: %s", local_version) update_cli = False if not update_all: return except Exception as ex: # pylint: disable=broad-except logger.debug("Failed to get the latest version. %s", str(ex)) exts = [ext.name for ext in get_extensions( ext_type=WheelExtension)] if update_all else [] exit_code = 0 installer = os.getenv(_ENV_AZ_INSTALLER) or '' installer = installer.upper() if update_cli: latest_version_msg = 'It will be updated to {}.'.format(latest_version) if yes \ else 'Latest version available is {}.'.format(latest_version) logger.warning("Your current Azure CLI version is %s. %s", local_version, latest_version_msg) from knack.prompting import prompt_y_n, NoTTYException if not yes: logger.warning( "Please check the release notes first: https://docs.microsoft.com/" "cli/azure/release-notes-azure-cli") try: confirmation = prompt_y_n("Do you want to continue?", default='y') except NoTTYException: from azure.cli.core.azclierror import UnclassifiedUserFault raise UnclassifiedUserFault("No tty available.", "Please run command with --yes.") if not confirmation: telemetry.set_success("Upgrade stopped by user") return if installer == 'DEB': from azure.cli.core.util import in_cloud_console if in_cloud_console(): raise CLIError("az upgrade is not supported in Cloud Shell.") apt_update_cmd = 'apt-get update'.split() az_update_cmd = 'apt-get install --only-upgrade -y azure-cli'.split( ) if os.geteuid() != 0: # pylint: disable=no-member apt_update_cmd.insert(0, 'sudo') az_update_cmd.insert(0, 'sudo') exit_code = subprocess.call(apt_update_cmd) if exit_code == 0: logger.debug("Update azure cli with '%s'", " ".join(apt_update_cmd)) exit_code = subprocess.call(az_update_cmd) elif installer == 'RPM': from azure.cli.core.util import get_linux_distro distname, _ = get_linux_distro() if not distname: logger.warning(UPGRADE_MSG) else: distname = distname.lower().strip() if any(x in distname for x in ['centos', 'rhel', 'red hat', 'fedora']): update_cmd = 'yum update -y azure-cli'.split() if os.geteuid() != 0: # pylint: disable=no-member update_cmd.insert(0, 'sudo') logger.debug("Update azure cli with '%s'", " ".join(update_cmd)) exit_code = subprocess.call(update_cmd) elif any(x in distname for x in ['opensuse', 'suse', 'sles']): zypper_refresh_cmd = ['zypper', 'refresh'] az_update_cmd = 'zypper update -y azure-cli'.split() if os.geteuid() != 0: # pylint: disable=no-member zypper_refresh_cmd.insert(0, 'sudo') az_update_cmd.insert(0, 'sudo') exit_code = subprocess.call(zypper_refresh_cmd) if exit_code == 0: logger.debug("Update azure cli with '%s'", " ".join(az_update_cmd)) exit_code = subprocess.call(az_update_cmd) else: logger.warning(UPGRADE_MSG) elif installer == 'HOMEBREW': logger.debug("Update homebrew formulae") exit_code = subprocess.call(['brew', 'update']) if exit_code == 0: update_cmd = ['brew', 'upgrade', 'azure-cli'] logger.debug("Update azure cli with '%s'", " ".join(update_cmd)) exit_code = subprocess.call(update_cmd) elif installer == 'PIP': pip_args = [ sys.executable, '-m', 'pip', 'install', '--upgrade', 'azure-cli', '-vv', '--disable-pip-version-check', '--no-cache-dir' ] logger.debug("Update azure cli with '%s'", " ".join(pip_args)) exit_code = subprocess.call(pip_args, shell=platform.system() == 'Windows') elif installer == 'DOCKER': logger.warning( "Exit the container to pull latest image with 'docker pull mcr.microsoft.com/azure-cli' " "or run 'pip install --upgrade azure-cli' in this container") elif installer == 'MSI': logger.debug( "Update azure cli with MSI from https://aka.ms/installazurecliwindows" ) exit_code = subprocess.call(['powershell.exe', '-NoProfile', "Start-Process msiexec.exe -Wait -ArgumentList '/i https://aka.ms/installazurecliwindows'"]) # pylint: disable=line-too-long else: logger.warning(UPGRADE_MSG) if exit_code: err_msg = "CLI upgrade failed." logger.warning(err_msg) telemetry.set_failure(err_msg) sys.exit(exit_code) import azure.cli.core import importlib importlib.reload(azure.cli.core) new_version = azure.cli.core.__version__ if update_cli and new_version == local_version: err_msg = "CLI upgrade failed or aborted." logger.warning(err_msg) telemetry.set_failure(err_msg) sys.exit(1) # Python is reinstalled in another versioned directory with Homebrew, subprocess needs to be reloaded if installer == 'HOMEBREW' and exts: importlib.reload(subprocess) if exts: logger.warning("Upgrading extensions") for ext_name in exts: try: logger.warning("Checking update for %s", ext_name) subprocess.call(['az', 'extension', 'update', '-n', ext_name], shell=platform.system() == 'Windows') except Exception as ex: # pylint: disable=broad-except msg = "Extension {} update failed during az upgrade. {}".format( ext_name, str(ex)) raise CLIError(msg) auto_upgrade_msg = "You can enable auto-upgrade with 'az config set auto-upgrade.enable=yes'. " \ "More details in https://docs.microsoft.com/cli/azure/update-azure-cli#automatic-update" logger.warning( "Upgrade finished.%s", "" if cmd.cli_ctx.config.getboolean( 'auto-upgrade', 'enable', False) else auto_upgrade_msg)
def test_extension_list(self): _install_test_extension1() actual = get_extensions(ext_type=WheelExtension) self.assertEqual(len(actual), 1)
def get_az_version_string(use_cache=False): # pylint: disable=too-many-statements from azure.cli.core.extension import get_extensions, EXTENSIONS_DIR, DEV_EXTENSION_SOURCES, EXTENSIONS_SYS_DIR output = six.StringIO() versions = _get_local_versions() # get the versions from pypi versions, success = get_cached_latest_versions(versions) if use_cache else _update_latest_from_pypi(versions) updates_available = 0 def _print(val=''): print(val, file=output) def _get_version_string(name, version_dict): from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module local = version_dict['local'] pypi = version_dict.get('pypi', None) if pypi and LooseVersion(pypi) > LooseVersion(local): return name.ljust(25) + local.rjust(15) + ' *' return name.ljust(25) + local.rjust(15) ver_string = _get_version_string(CLI_PACKAGE_NAME, versions.pop(CLI_PACKAGE_NAME)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() for name in sorted(versions.keys()): ver_string = _get_version_string(name, versions.pop(name)) if '*' in ver_string: updates_available += 1 _print(ver_string) _print() extensions = get_extensions() if extensions: _print('Extensions:') for ext in extensions: if ext.ext_type == 'dev': _print(ext.name.ljust(20) + (ext.version or 'Unknown').rjust(20) + ' (dev) ' + ext.path) else: _print(ext.name.ljust(20) + (ext.version or 'Unknown').rjust(20)) _print() _print("Python location '{}'".format(sys.executable)) _print("Extensions directory '{}'".format(EXTENSIONS_DIR)) import os if os.path.isdir(EXTENSIONS_SYS_DIR) and os.listdir(EXTENSIONS_SYS_DIR): _print("Extensions system directory '{}'".format(EXTENSIONS_SYS_DIR)) if DEV_EXTENSION_SOURCES: _print("Development extension sources:") for source in DEV_EXTENSION_SOURCES: _print(' {}'.format(source)) _print() _print('Python ({}) {}'.format(platform.system(), sys.version)) _print() _print('Legal docs and information: aka.ms/AzureCliLegal') _print() version_string = output.getvalue() # if unable to query PyPI, use sentinel value to flag that # we couldn't check for updates if not success: updates_available = -1 return version_string, updates_available
def list_extensions(): return [{ OUT_KEY_NAME: ext.name, OUT_KEY_VERSION: ext.version, OUT_KEY_TYPE: ext.ext_type } for ext in get_extensions()]