Exemplo n.º 1
0
 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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
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])
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
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
                )