def is_downloaded(self): if self._core is not None: return self._core.is_downloaded() logger.warn( "Core has not been downloaded: Use: kraft list pull unikraft") return False
def probe(ctx, self, origin=None, items=None, return_threads=False): # TODO: There should be a work around to fix this import loop cycle from kraft.manifest import Manifest if self.is_type(origin) is False: return [] threads = list() if items is None: items = Queue() manifest = ctx.obj.cache.get(origin) if manifest is None: manifest = Manifest(manifest=origin) uri = urlparse(origin) # Is the origin from GitHub? if uri.netloc == GITHUB_ORIGIN: github_api = Github(ctx.obj.env.get('UK_KRAFT_GITHUB_TOKEN', None)) github_org = uri.path.split('/')[1] github_repo = uri.path.split('/')[2] if "*" in github_org: logger.warn( "Cannot use wildcard in GitHub organisation names!") return # Does the origin contain a wildcard in the repo name? if "*" in github_repo: logger.info("Populating via wildcard: %s" % origin) org = github_api.get_organization(github_org) repos = org.get_repos() for repo in repos: if return_threads: thread = ErrorPropagatingThread( target=lambda *arg: items.put( get_component_from_github(*arg)), args=( ctx, origin, github_org, repo.name, )) threads.append(thread) thread.start() else: items.put( get_component_from_github(ctx, origin, github_org, repo.name)) else: logger.info("Using direct repository: %s" % origin) if return_threads: thread = ErrorPropagatingThread( target=lambda *arg: items.put( get_component_from_github(*arg)), args=( ctx, origin, github_org, github_repo, )) threads.append(thread) thread.start() else: items.put( get_component_from_github(ctx, origin, github_org, github_repo)) return items, threads
def cmd_list(ctx, show_installed=False, show_core=False, show_plats=False, show_libs=False, show_apps=False, show_local=False, paginate=False, this=False, this_set=None, return_json=False): """ Retrieves lists of available architectures, platforms, libraries and applications supported by unikraft. Use this command if you wish to determine (and then later select) the possible targets for your unikraft application. By default, this subcommand will list all possible targets. """ if ctx.invoked_subcommand is None: kraft_list_preflight() show_archs = False # If no flags are set, show everything if (show_core is False and show_archs is False and show_plats is False and show_libs is False and show_apps is False): show_core = show_archs = show_plats = show_libs = show_apps = True # Populate a matrix with all relevant columns and rows for each # component. components = {} data = [] data_json = {} if this or this_set is not None: workdir = os.getcwd() if this_set is not None: workdir = this_set try: app = Application.from_workdir(workdir) for manifest in app.manifests: if manifest.type.shortname not in components: components[manifest.type.shortname] = [] components[manifest.type.shortname].append(manifest) except KraftError as e: logger.error(str(e)) sys.exit(1) else: for manifest_origin in ctx.obj.cache.all(): manifest = ctx.obj.cache.get(manifest_origin) for _, item in manifest.items(): if item.type.shortname not in components: components[item.type.shortname] = [] components[item.type.shortname].append(item) for type, member in ComponentType.__members__.items(): columns = [ click.style(member.plural.upper(), fg='white'), click.style('VERSION ', fg='white'), click.style('RELEASED', fg='white'), click.style('LAST CHECKED', fg='white') ] if show_local: columns.append(click.style('LOCATION', fg='white')) rows = [] components_showing = 0 if member.shortname in components and ( (show_core and member is ComponentType.CORE) or (show_archs and member is ComponentType.ARCH) or (show_plats and member is ComponentType.PLAT) or (show_libs and member is ComponentType.LIB) or (show_apps and member is ComponentType.APP)): rows = components[member.shortname] # if len(rows) > 0: data.append(columns) for row in rows: installed = False install_error = False localdir = row.localdir if os.path.isdir(localdir): installed = True if len(os.listdir(localdir)) == 0: install_error = True logger.warn("%s directory is empty: %s " % ( row.name, localdir )) latest_release = None if UNIKRAFT_RELEASE_STABLE in row.dists.keys(): latest_release = row.dists[UNIKRAFT_RELEASE_STABLE].latest elif UNIKRAFT_RELEASE_STAGING in row.dists.keys(): latest_release = row.dists[UNIKRAFT_RELEASE_STAGING].latest if return_json: if member.plural not in data_json: data_json[member.plural] = [] row_json = row.__getstate__() if not show_installed or (installed and show_installed): data_json[member.plural].append(row_json) components_showing += 1 else: line = [ click.style(row.name, fg='yellow' if install_error else 'green' if installed else 'red'), # noqa: E501 click.style(latest_release.version if latest_release is not None else "", fg='white'), # noqa: E501 click.style(prettydate(latest_release.timestamp) if latest_release is not None else "", fg='white'), # noqa: E501 click.style(prettydate(row.last_checked), fg='white'), ] if show_local: line.append(click.style(localdir if installed else '', fg='white')) # noqa: E501 if not show_installed or (installed and show_installed): data.append(line) components_showing += 1 # Delete component headers with no rows if components_showing == 0 and len(data) > 0: del data[-1] # Line break elif len(rows) > 0: data.append([click.style("", fg='white')] * len(columns)) if return_json: click.echo(json.dumps(data_json)) else: output = pretty_columns(data) if len(data) == 0: logger.info("Nothing to show") elif paginate: click.echo_via_pager(output) else: click.echo(output[:-1])
def bump(ctx, self, version=None, fast_forward=False, force_version=False): """ Change the Unikraft library's source origin version. Usually this involves updating the LIBNAME_VERSION variable in the Makefile.uk file. Args: version: The version to set. If None, the latest version will be set. fast_forward: If True, choose the latest version. force_version: Whatever the specified version is, use it. Raises: NonCompatibleUnikraftLibrary: Provided path is not a Unikraft library. UnknownLibraryOriginVersion: The provided version does not match known versions from the origin. BumpLibraryDowngrade: Attempting to downgrade a library. NoRemoteVersionsAvailable: No remote versions to select from. CannotDetermineRemoteVersion: Unable to determine which version to upgrade to. UnknownLibraryProvider: Undetermined origin provider. KraftError: Miscellaneous error. """ if self.origin_provider is None: raise UnknownLibraryProvider(self.name) # Retrieve known versions versions = self.origin_provider.probe_remote_versions() semversions = [] if len(versions) == 0: raise NoRemoteVersionsAvailable(self.origin_provider.source) # filter out non-semver versions for known_version in list(versions.keys()): found = SEMVER_PATTERN.search(known_version) if found is not None: semversions.append(known_version) current_version = self.origin_version if version is None: # Pick the highest listed verson if ctx.obj.assume_yes: # There are no semversions if len(semversions) == 0: raise CannotDetermineRemoteVersion(self.localdir) current_not_semver = False try: semver.VersionInfo.parse(current_version) except ValueError as e: logger.warn(e) current_not_semver = True # Remove non-semvers latest_version = None _semversions = semversions semversions = list() for checkv in _semversions: try: semver.VersionInfo.parse(checkv) semversions.append(checkv) except ValueError: continue latest_version = sorted(semversions, reverse=True)[0] # Pick the latest version if fast_forward or current_not_semver: version = latest_version # Check if we're already at the latest version elif semver.compare(current_version, latest_version) == 0: version = latest_version # Find the next version else: semversions = sorted(semversions) for i in range(len(semversions)): try: comparison = semver.compare( semversions[i], current_version) except ValueError as e: logger.warn(e) continue if comparison == 0: # We should have never made it this far, but because we # did, we're at the latest version. if i + 1 == len(semversions): version = latest_version break # Select the next version else: version = semversions[i + 1] break # Prompt user for a version else: version = read_user_choice( 'version', sorted(list(versions.keys()), reverse=True)) if version not in versions.keys(): if ctx.obj.assume_yes: logger.warn("Provided version '%s' not known in: {%s}" % (version, ', '.join(versions.keys()))) else: raise UnknownLibraryOriginVersion(version, versions.keys()) if VSEMVER_PATTERN.search(version): version = version[1:] # Are we dealing with a semver pattern? try: if semver.compare(current_version, version) == 0: logger.info("Library already latest version: %s" % version) return version if semver.compare(current_version, version) > 0: if force_version: logger.warn("Downgrading library from %s to %s..." % (current_version, version)) else: raise BumpLibraryDowngrade(current_version, version) except ValueError: if current_version == version: logger.info("Library already at version: %s" % version) return version # Actually perform the bump makefile_uk = os.path.join(self.localdir, MAKEFILE_UK) logger.debug("Reading %s..." % makefile_uk) makefile_vars = make_list_vars(makefile_uk)['makefile'] version_var = None for var in makefile_vars: if var.endswith(UNIKRAFT_LIB_MAKEFILE_VERSION_EXT): version_var = var break logger.info('Upgrading library from %s to %s...' % (current_version, version)) for line in fileinput.input(makefile_uk, inplace=1): if line.startswith(version_var) and current_version in line: print('%s = %s' % (version_var, version)) else: print(line, end='') return version
def kraft_list_pull(ctx, name=None, workdir=None, use_git=False, pull_dependencies=False, skip_verify=False, appdir=None, skip_app=False, force_pull=False): """ Pull a particular component from a known manifest. This will retrieve the contents to either the automatically determined directory or to an alternative working directory. Args: name (str): The name of the component(s) to pull. This can be the full qualifier, e.g.: lib/python3==0.4, partial, or the minimum: python3. workdir (str): The path to save the component(s). use_git (bool): Whether to use git to retrieve the components. pull_dependencies (bool): If an application is specified in name, this will signal to pull the listed libraries for this. appdir (str): Used in conjunction with pull_dependencies and used to specify the application from which the dependencies are determined and then pulled. """ manifests = list() names = list() if isinstance(name, tuple): names = list(name) elif name is not None: names.append(name) not_found = list() if isinstance(name, tuple): not_found = list(name) elif name is not None: not_found.append(name) # Pull the dependencies for the application at workdir or cwd if (pull_dependencies and (len(names) == 0 or (appdir is not None and len(names) == 1))): app = Application.from_workdir( appdir if appdir is not None else workdir if workdir is not None else os.getcwd(), force_pull ) for component in app.components: if component.manifest is not None: manifests.append(( component.manifest, ManifestVersionEquality.EQ, component.version.version )) # Pull the provided named components else: for manifest_origin in ctx.obj.cache.all(): manifest = ctx.obj.cache.get(manifest_origin) for _, manifest in manifest.items(): if len(names) == 0: manifests.append((manifest, 0, None)) else: for fullname in names: type, name, eq, version = \ break_component_naming_format(fullname) if (type is None or (type is not None and type == manifest.type)) \ and manifest.name == name: manifests.append((manifest, eq, version)) # Accomodate for multi-type names if fullname in not_found: not_found.remove(fullname) for name in not_found: logger.warn("Could not find manifest: %s" % name) if len(manifests) == 0: logger.error("No manifests to download") sys.exit(1) for manifest in manifests: if skip_app and manifest[0].type == ComponentType.APP: continue kraft_download_via_manifest( workdir=workdir, manifest=manifest[0], equality=manifest[1], version=manifest[2], use_git=use_git, skip_verify=skip_verify ) if pull_dependencies and len(names) > 0: for manifest in manifests: if manifest[0].type == ComponentType.APP: kraft_list_pull( appdir=manifest[0].localdir, workdir=workdir, use_git=use_git, pull_dependencies=True, skip_verify=skip_verify )