def cmd_build(ctx, verbose_build=False, fetch=True, prepare=True, progress=True, target=None, fast=False, force_build=False): """ Builds the Unikraft application for the target architecture and platform. """ kraft_list_preflight() try: kraft_build(workdir=ctx.obj.workdir, verbose=verbose_build, fetch=fetch, prepare=prepare, progress=progress, target=target, fast=fast, force_build=force_build) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_lib_add(ctx, workdir=None, lib=None, dumps_local=False): """ Add a library to the unikraft application project. """ if workdir is None: workdir = os.getcwd() try: if dumps_local: kraft_list_pull( name=lib, workdir=os.path.join(workdir, UNIKRAFT_WORKDIR) ) if not kraft_lib_add(workdir=workdir, lib=lib): sys.exit(1) except Exception as e: if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) else: logger.critical(str(e)) sys.exit(1)
def cmd_clean(ctx, workdir=None, proper=False, dist=False, progress=True, libs=None): """ Clean the build artifacts of a Unikraft unikernel application. """ if workdir is None: workdir = ctx.obj.workdir try: kraft_clean( workdir=workdir, proper=proper, dist=dist, progress=progress, libs=libs, ) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_list_pull(ctx, name=None, workdir=None, use_git=False, no_dependencies=False, skip_verify=False): """ Download a remote component to your working directory. You can additional syntax to specify the type of component and/or the version you wish to download. The name of a component is specified by either its unique name or by its type and name (e.g. [type]/[name] or [type]-[name]). The version can be specified using an equality operator: at the specific version/distribution (e.g. [name]==[version]) or equal and above the specific version (e.g. [name]>=[version]). To pull an application and its depedencies, simply call the specified name: $ kraft list pull python3 $ kraft list pull app-python3 $ kraft list pull app/python3 To simply pull a library: $ kraft list pull lib-python3 $ kraft list pull lib/python3 To pull a component at a specific version: $ kraft list pull lib/python3==stable $ kraft list pull lib-python3>=0.4 """ kraft_list_preflight() try: kraft_list_pull( name=name, workdir=workdir, use_git=use_git, pull_dependencies=not no_dependencies, skip_verify=skip_verify ) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_run(ctx, target=None, plat=None, arch=None, initrd=None, background=False, paused=False, gdb=4123, dbg=False, virtio_nic=None, bridge=None, interface=None, dry_run=False, args=None, memory=64, cpu_sockets=1, cpu_cores=1, workdir=None): if workdir is None: workdir = os.getcwd() try: kraft_run( appdir=workdir, target=target, plat=plat, arch=arch, initrd=initrd, background=background, paused=paused, dbg=dbg, gdb=gdb, virtio_nic=virtio_nic, bridge=bridge, interface=interface, dry_run=dry_run, args=args, memory=memory, cpu_sockets=cpu_sockets, cpu_cores=cpu_cores, ) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_list_remove(ctx, origin=None): """ Remove a remote repository to search for components. """ try: kraft_list_remove(list(origin)) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_list_add(ctx, update=False, origin=None): """ Add a remote repository to search for components. """ try: kraft_list_add(list(origin), update=update) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def kraft_update(ctx): origins = ctx.obj.settings.get(KRAFTRC_LIST_ORIGINS) if origins is None or len(origins) == 0: logger.error( "No source origins available. Please see: kraft list add --help") sys.exit(1) try: for origin in origins: manifest = ctx.obj.cache.get(origin) if manifest is None: manifest = Manifest(manifest=origin) threads, items = kraft_update_from_source_threads(origin) for thread in threads: thread.join() # Check thread's return value while not items.empty(): result = items.get() if result is not None: manifest.add_item(result) logger.info("Found %s/%s via %s..." % (click.style(result.type.shortname, fg="blue"), click.style(result.name, fg="blue"), manifest.manifest)) ctx.obj.cache.save(origin, manifest) except RateLimitExceededException: logger.error("".join([ "GitHub rate limit exceeded. You can tell kraft to use a ", "personal access token by setting the UK_KRAFT_GITHUB_TOKEN ", "environmental variable." ])) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def kconfig_enabled_flag(self): if self._kconfig_enabled_flag is None and self._core is not None: arch_config = UK_CORE_ARCH_DIR % (self._core.localdir, CONFIG_UK) if not os.path.isfile(arch_config): logger.critical("Could not find: %s" % arch_config) return None with open(arch_config, 'r+') as f: data = f.read() matches = CONFIG_UK_ARCH.findall(data) for match in matches: if match[2] == self._name: self._kconfig_enabled_flag = KCONFIG % KCONFIG_EQ % ( match[0], KCONFIG_Y) break return self._kconfig_enabled_flag
def cmd_prepare(ctx): """ Prepares """ kraft_list_preflight() try: kraft_prepare(workdir=ctx.obj.workdir) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_lib_remove(ctx, workdir=None, lib=None, purge=False): """ Remove a library from the unikraft application project. """ if workdir is None: workdir = os.getcwd() try: if not kraft_lib_remove(workdir=workdir, lib=lib, purge=purge): sys.exit(1) except Exception as e: if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) else: logger.critical(str(e)) sys.exit(1)
def localdir(ctx, self): if self._localdir is None and self._core is not None: arch_config = UK_CORE_ARCH_DIR % (self._core.localdir, CONFIG_UK) if not os.path.isfile(arch_config): logger.critical("Could not find: %s" % arch_config) return None with open(arch_config, 'r+') as f: data = f.read() matches = CONFIG_UK_ARCH.findall(data) for match in matches: if match[2] == self._name: path = match[1] # python is dumb: if path.startswith("/"): path = path[1:] self._localdir = os.path.join(self._core.localdir, path) break return self._localdir
def cmd_menuconfig(ctx, workdir=None): """ Opens the KConfig Menuconfig program for the selected application. """ if not sys.stdout.isatty(): logger.critical("Cannot open menuconfig in non-TTY environment") return if workdir is None: workdir = os.getcwd() try: app = Application.from_workdir(workdir) app.open_menuconfig() return except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def __init__(self, components=[], cls=None, **extra): # noqa:C901 if cls is not None: self._cls = cls if self._cls is None: logger.critical("Cannot instantiate manager, missing cls: %s", self) return if components is None: self._components = list() elif isinstance(components, list): for component in components: if isinstance(component, self.cls): self._components.append(component) else: self._components.append(self.cls( **component, **extra )) elif isinstance(components, dict): self._components = list() for component, config in components.items(): if isinstance(config, six.string_types): inst = self.cls( name=component, version=config, ) elif isinstance(config, dict): inst = self.cls( name=component, **config, **extra ) self._components.append(inst) elif isinstance(components, object): self._components = list() self._components.append(components)
def cmd_configure(ctx, target=None, plat=None, arch=None, force_configure=False, show_menuconfig=False, workdir=None, yes=[], no=[], opts=[], use_versions=[]): """ Configure the unikernel using the KConfig options set in the kraft.yaml file. Alternatively, you can use the -k|--menuconfig flag to open the TUI to manually select the configuration for this unikernel. When the unikernel is configured, a .config file is written to the working directory with the selected KConfig options. """ kraft_list_preflight() if workdir is None: workdir = os.getcwd() options = list() for y in yes: if not y.startswith(KCONFIG): y = KCONFIG % y options.append(KCONFIG_EQ % (y, KCONFIG_Y)) for n in no: if not n.startswith(KCONFIG): n = KCONFIG % n if n in options: logger.critical( 'Cannot specify same option with multiple values: %s' % n) sys.exit(1) options.append(KCONFIG_EQ % (n, KCONFIG_N)) for o in opts: if not o.startswith(KCONFIG): o = KCONFIG % o if '=' not in o: logger.critical('Missing value for --set option: %s' % o) sys.exit(1) options.append(o) try: kraft_configure( env=ctx.obj.env, workdir=workdir, target=target, plat=plat, arch=arch, force_configure=force_configure, show_menuconfig=show_menuconfig, options=options, use_versions=use_versions, ) except MissingComponent as e: if force_configure is False: logger.warn(e) if force_configure or \ click.confirm("Would you like to pull %s?" % e.component): # noqa try: kraft_list_pull(name=str(e.component), pull_dependencies=False, skip_app=True) except Exception: if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1) # Try to configure again ctx.forward(cmd_configure, force_configure=True) elif ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_up(ctx, workdir=None, name=None, plat=None, arch=None, initrd=None, background=False, paused=False, gdb=4123, dbg=False, virtio_nic=None, bridge=None, interface=None, dry_run=False, memory=64, cpu_sockets=1, cpu_cores=1, force=False, fast=False, create_makefile=False, template_app=None): """ Configures, builds and runs an application for a selected architecture and platform. """ kraft_list_preflight() if workdir is None and name is None: appdir = os.getcwd() name = os.path.basename(appdir) elif workdir is None: appdir = os.path.join(os.getcwd(), name) elif name is None: appdir = workdir name = os.path.basename(appdir) if arch is None: arch = ctx.obj.settings.get(KRAFTRC_CONFIGURE_ARCHITECTURE) if plat is None: plat = ctx.obj.settings.get(KRAFTRC_CONFIGURE_PLATFORM) # Check if the directory is non-empty and prompt for validation if util.is_dir_empty(appdir) is False and ctx.obj.assume_yes is False: if click.confirm( '%s is a non-empty directory, would you like to continue?' % appdir): # noqa: E501 force = True else: logger.critical("Cannot create directory: %s" % appdir) sys.exit(1) try: kraft_list_pull(name=template_app, pull_dependencies=True) kraft_app_init(name=name, appdir=appdir, plat=plat, arch=arch, template_app=template_app, create_makefile=create_makefile, force_init=force) kraft_configure(env=ctx.obj.env, workdir=appdir, plat=plat, arch=arch, force_configure=force, show_menuconfig=False) kraft_build(workdir=appdir, fetch=True, prepare=True, fast=fast) kraft_run( appdir=appdir, plat=plat, arch=arch, initrd=initrd, background=background, paused=paused, dbg=dbg, gdb=gdb, virtio_nic=virtio_nic, bridge=bridge, interface=interface, dry_run=dry_run, # args=args, memory=memory, cpu_sockets=cpu_sockets, cpu_cores=cpu_cores, ) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_init(ctx, name=None, plat=None, arch=None, template_app=None, workdir=None, create_makefile=False, no_dependencies=False, dumps_local=False, force_init=False): """ Initializes a new unikraft application. Start here if this is your first time using (uni)kraft. """ kraft_list_preflight() # kraft's init permutations: # # $ kraft init => $(pwd) # $ kraft init my_app => $(pwd)/my_app # $ kraft -w /path/to/app init => /path/to/app # $ kraft -w /path/to/app init my_app => /path/to/app/my_app if workdir is None and name is None: appdir = os.getcwd() name = os.path.basename(appdir) elif workdir is None: appdir = os.path.join(os.getcwd(), name) elif name is None: appdir = workdir name = os.path.basename(appdir) if arch is None: arch = ctx.obj.settings.get(KRAFTRC_CONFIGURE_ARCHITECTURE) if plat is None: plat = ctx.obj.settings.get(KRAFTRC_CONFIGURE_PLATFORM) # Check if the directory is non-empty and prompt for validation if util.is_dir_empty(appdir) is False and ctx.obj.assume_yes is False: if click.confirm( '%s is a non-empty directory, would you like to continue?' % appdir): # noqa: E501 force_init = True else: logger.critical("Cannot create directory: %s" % appdir) sys.exit(1) try: kraft_app_init(name=name, appdir=appdir, plat=plat, arch=arch, template_app=template_app, create_makefile=create_makefile, force_init=force_init, pull_dependencies=not no_dependencies, dumps_local=dumps_local) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)
def cmd_lib_init(ctx, name=None, author_name=None, author_email=None, origin_version=None, origin_url=None, provide_main=False, workdir=None, force_create=False, no_input=False, soft_pack=False, initial_branch=None): """ Initialize a new Unikraft library. """ # TODO: Implement adding dependencies at CLI dependencies = list() if workdir is None and name is None: libdir = os.getcwd() name = os.path.basename(libdir) elif workdir is None: libdir = os.path.join(os.getcwd(), name) elif name is None: libdir = workdir name = os.path.basename(libdir) # Check if the directory is non-empty and prompt for validation if util.is_dir_empty(libdir) is False and ctx.obj.assume_yes is False: if click.confirm( '%s is a non-empty directory, would you like to continue?' % libdir): # noqa: E501 force_create = True else: logger.critical("Cannot create directory: %s" % libdir) sys.exit(1) gitconfig = None try: if author_name is None or author_email is None: # Attempt reading author and email from .git/config if os.path.exists(os.path.join(libdir, '.git')): gitconfig = GitConfigParser( [os.path.normpath(os.path.join(libdir, GITCONFIG_LOCAL))], read_only=True) # Attempt reading default author and email from ~/.gitconfig else: gitconfig = GitConfigParser( [os.path.normpath(os.path.expanduser(GITCONFIG_GLOBAL))], read_only=True) if author_name is None: author_name = gitconfig.get("user", "name") if author_email is None: author_email = gitconfig.get("user", "email") except (NoSectionError, NoOptionError): pass if no_input is False: if origin_url is None: origin_url = click.prompt( "source (Use %s for automatic versioning)" % URL_VERSION) try: kraft_lib_init(name=name, libdir=libdir, author_name=author_name, author_email=author_email, origin_url=origin_url, origin_version=origin_version, dependencies=dependencies, provide_main=provide_main, force_create=force_create, no_input=no_input, soft_pack=soft_pack, initial_branch=initial_branch) except Exception as e: logger.critical(str(e)) if ctx.obj.verbose: import traceback logger.critical(traceback.format_exc()) sys.exit(1)