def destroy(buildname: str): """Destroy an existing build. Will always remove the existing configuration for build BUILDNAME. Optionally, may also remove existing an existing build, and the build's containers. BUILDNAME is the name of the build to be destroyed. """ if not config.build_exists(buildname): pinfo(f"build '{buildname}' does not exist") sys.exit(errno.ENOENT) if not click.confirm( swarn(f"Are you sure you want to remove build '{buildname}?"), default=False): sys.exit(0) remove_build = click.confirm( swarn("Do you want to remove the build directory?"), default=False) remove_containers = click.confirm( swarn("Do you want to remove the containers?"), default=False) success: bool = \ Build.destroy(config, buildname, remove_install=remove_build, remove_containers=remove_containers) if not success: perror(f"error destroying build '{buildname}'; aborted.") else: pinfo(f"destroyed build '{buildname}'")
def _is_alive_registry_url(url: str) -> bool: pinfo(f"Trying to reach registry at {url}...") try: conn = HTTPConnection(url, timeout=30) conn.request("GET", "/v2/") except Exception as e: perror(f"error: {str(e)}") return False return True
def shell(buildname: str): """Drop into shell of build's latest container. BUILDNAME is the name of the build for which we want a shell. """ if not config.build_exists(buildname): perror(f"build '{buildname}' does not exist.") sys.exit(errno.ENOENT) if not Images.run_shell(buildname): perror(f"unable to run shell for build '{buildname}'") sys.exit(errno.EINVAL)
def _init_tree() -> Tuple[Path, Path]: tree_root_dir = _prompt_directory("Builder tree directory", must_exist=False) if not tree_root_dir: perror("Must specify a directory") sys.exit(errno.EINVAL) tree_path = Path(tree_root_dir) installs_path = tree_path.joinpath("installs") ccache_path = tree_path.joinpath("ccache") return (installs_path, ccache_path)
def _prompt_directory(prompt_text: str, must_exist=True) -> Path: path = None while True: pathstr = click.prompt(sinfo(prompt_text), type=str, default=None) path = Path(pathstr).absolute() if must_exist and not path.exists(): perror("error: path must exist") continue if path.exists() and not path.is_dir(): perror("error: path is not a directory.") continue break return path
def build(buildname: str, nuke_install: bool, with_fresh_build: bool): """ Starts a new build. Will run a new build for the sources specified by BUILDNAME, and will create an image, either original or incremental. BUILDNAME is the name of the build being built. """ if not config.build_exists(buildname): perror(f"error: build '{buildname}' does not exist.") sys.exit(errno.ENOENT) if nuke_install: sure = click.confirm( swarn("Are you sure you want to remove the install directory?"), default=False) if not sure: sys.exit(1) if with_fresh_build: sure = click.confirm( swarn("Are you sure you want to run a fresh build?"), default=False) if not sure: sys.exit(1) build: Build = Build(config, buildname) assert build._vendor assert build._release assert build._sources if not ImageChecker.check_has_images(build._vendor, build._release): # create build images. pwarn("=> missing build images; creating...") vendor: str = build._vendor release: str = build._release sp: Path = Path(build._sources) if not check_create_images(vendor, release, sp): perror("=> error creating images for build") sys.exit(errno.ENOTRECOVERABLE) Build.build(config, buildname, nuke_install=nuke_install, with_fresh_build=with_fresh_build)
def _prompt_ccache_size() -> str: ccache_size = None while True: ccache_size = click.prompt(sinfo("ccache size (in G, T)"), type=str, default="10G") match = re.match(r'^[ ]*([0-9]+)[ ]*([GT])[ ]*$', ccache_size.upper()) if not match or len(match.groups()) != 2: perror("invalid size format.") continue size = int(match.group(1)) unit = match.group(2) if size <= 0: perror("invalid value for size; must be greater than zero.") continue elif size < 2 and unit == 'G': pwarn("size may be too small to cache one build.") ccache_size = f"{size}{unit}" break return ccache_size
def build_info(buildname: str): """Show build information, including images. Will show information about a given build, including its configuration and existing images. BUILDNAME name of build to show info for. """ if not config.build_exists(buildname): perror(f"build '{buildname}' does not exist.") sys.exit(errno.ENOENT) build = Build(config, buildname) build.print(with_prefix=True, verbose=True) images: List[ContainerImage] = Images.find_build_images(buildname) if len(images) == 0: perror(f"no images for build '{buildname}'") sys.exit(0) img: ContainerImage for img in images: img.print()
def create(buildname: str, vendor: str, release: str, sourcedir: str, with_debug: bool, with_tests: bool, build_base_image: bool, clone_from_repo: str = None, clone_from_branch: str = None): """Create a new build; does not build. BUILDNAME is the name for the build.\n VENDOR is the vendor to be used for this build.\n RELEASE is the release to be used for this build.\n SOURCEDIR is the directory where sources for this build are expected.\n """ if config.build_exists(buildname): perror(f"build '{buildname}' already exists.") sys.exit(errno.EEXIST) # check whether a build image for <vendor>:<release> exists do_build_image: bool = False if not ImageChecker.check_has_images(vendor, release): pwarn("=> required images not found, building at a later stage") do_build_image = True sourcepath: Path = Path(sourcedir).resolve() if clone_from_repo is not None: if len(clone_from_repo) == 0: perror("error: valid git repository required.") sys.exit(errno.EINVAL) extra_opts = "" if clone_from_branch is not None: if len(clone_from_branch) == 0: perror("error: valid branch required.") sys.exit(errno.EINVAL) extra_opts += f"-b {clone_from_branch}" if sourcepath.exists(): perror(f"error: SOURCEDIR exists at {sourcepath}.") perror("can't clone to an existing directory") sys.exit(errno.EEXIST) cmd = f"git clone {extra_opts} {clone_from_repo} {sourcedir}" proc = subprocess.run(shlex.split(cmd)) if proc.returncode != 0: perror("error: unable to clone repository") sys.exit(proc.returncode) elif clone_from_branch is not None: perror("error: --clone-from-branch requires --clone-from-repo") sys.exit(errno.EINVAL) # check whether sourcedir is a ceph repository if not sourcepath.exists() or not sourcepath.is_dir(): perror("error: sourcedir expected to exist as a directory") sys.exit(errno.ENOTDIR) specfile = sourcepath.joinpath('ceph.spec.in') if not specfile.exists(): perror("error: sourcedir is not a ceph git source tree") sys.exit(errno.EINVAL) if do_build_image: pinfo(f"=> building images for vendor {vendor} release {release}") if not check_create_images(vendor, release, sourcepath): perror("=> unable to create images; abort.") sys.exit(errno.ENOTRECOVERABLE) build = Build.create(config, buildname, vendor, release, sourcedir, with_debug=with_debug, with_tests=with_tests) build.print() pokay(f"created build '{buildname}'")