diff --git a/cachi2/core/models/input.py b/cachi2/core/models/input.py index 198a158e4..8b2843dd6 100644 --- a/cachi2/core/models/input.py +++ b/cachi2/core/models/input.py @@ -63,6 +63,27 @@ def _path_is_relative(cls, path: Path) -> Path: return check_sane_relpath(path) +class CargoPackageInput(_PackageInputBase): + """Accepted input for a cargo package.""" + + type: Literal["cargo"] + lock_file: Optional[Path] = None + pkg_name: str = None + pkg_version: str = None + + @pydantic.validator("lock_file", "pkg_name", "pkg_version") + def _no_explicit_none(cls, value): + """Fail if the user explicitly passes None.""" + if value is None: + # Note: same error message as pydantic's default + raise TypeError("none is not an allowed value") + return value + + @pydantic.validator("lock_file") + def _lock_file_path_is_relative(cls, path: Path) -> Path: + return check_sane_relpath(path) + + class GomodPackageInput(_PackageInputBase): """Accepted input for a gomod package.""" @@ -105,7 +126,7 @@ class YarnPackageInput(_PackageInputBase): PackageInput = Annotated[ - Union[GomodPackageInput, NpmPackageInput, PipPackageInput, YarnPackageInput], + Union[CargoPackageInput, GomodPackageInput, NpmPackageInput, PipPackageInput, YarnPackageInput], # https://pydantic-docs.helpmanual.io/usage/types/#discriminated-unions-aka-tagged-unions pydantic.Field(discriminator="type"), ] @@ -151,6 +172,11 @@ def _packages_not_empty(cls, packages: list[PackageInput]) -> list[PackageInput] raise ValueError("at least one package must be defined, got an empty list") return packages + @property + def cargo_packages(self) -> list[CargoPackageInput]: + """Get the cargo packages specified for this request.""" + return self._packages_by_type(CargoPackageInput) + @property def gomod_packages(self) -> list[GomodPackageInput]: """Get the gomod packages specified for this request.""" diff --git a/cachi2/core/package_managers/cargo.py b/cachi2/core/package_managers/cargo.py new file mode 100644 index 000000000..1828c5832 --- /dev/null +++ b/cachi2/core/package_managers/cargo.py @@ -0,0 +1,222 @@ +# SPDX-License-Identifier: GPL-3.0-or-later +from pathlib import Path +from textwrap import dedent +from typing import Any +import hashlib +import json +import logging +import tarfile +import urllib + +from packageurl import PackageURL +import tomli + +from cachi2.core.checksum import ChecksumInfo, must_match_any_checksum +from cachi2.core.models.input import CargoPackageInput, Request +from cachi2.core.models.output import Component, ProjectFile, RequestOutput +from cachi2.core.package_managers.general import download_binary_file +from cachi2.core.rooted_path import RootedPath +from cachi2.core.scm import get_repo_id + +log = logging.getLogger(__name__) + +DEFAULT_LOCK_FILE = "Cargo.lock" +DEFAULT_METADATA_FILE = "Cargo.toml" + + +def fetch_cargo_source(request: Request) -> RequestOutput: + """Resolve and fetch cargo dependencies for the given request.""" + components: list[Component] = [] + for package in request.cargo_packages: + info = _resolve_cargo(request.source_dir, request.output_dir, package) + components.append(Component.from_package_dict(info["package"])) + for dependency in info["dependencies"]: + dep_purl = _generate_purl_dependency(dependency) + components.append( + Component( + name=dependency["name"], + version=dependency["version"], + purl=dep_purl, + ) + ) + + cargo_config = ProjectFile( + abspath=Path(request.source_dir.join_within_root(".cargo/config.toml")), + template=dedent( + """ + [source.crates-io] + replace-with = "local" + + [source.local] + directory = "${output_dir}/deps/cargo" + """ + ), + ) + + return RequestOutput.from_obj_list( + components=components, + environment_variables=[], + project_files=[cargo_config], + ) + + +def _resolve_cargo(source_dir: Path, output_dir: Path, package: CargoPackageInput): + """ + Resolve and fetch cargo dependencies for the given cargo application. + """ + app_path = source_dir / package.path + pkg_name = package.pkg_name + pkg_version = package.pkg_version + if pkg_name is None and pkg_version is None: + pkg_name, pkg_version = _get_cargo_metadata(app_path) + assert pkg_name and pkg_version, "INVALID PACKAGE" + + purl = _generate_purl_main_package(pkg_name, pkg_version, source_dir) + + dependencies = [] + lock_file = app_path / (package.lock_file or DEFAULT_LOCK_FILE) + + cargo_lock_dict = tomli.load(lock_file.open("rb")) + for dependency in cargo_lock_dict["package"]: + # assuming packages w/o checksum/source are either sub-packages or the package + # itself + if {"checksum", "source"} <= dependency.keys(): + dependencies.append(dependency) + + dependencies = _download_cargo_dependencies(output_dir, dependencies) + return { + "package": {"name": pkg_name, "version": pkg_version, "type": "cargo", "purl": purl}, + "dependencies": dependencies, + "lock_file": lock_file, + } + + +def _get_cargo_metadata(package_dir: Path): + metadata_file = package_dir / DEFAULT_METADATA_FILE + metadata = tomli.load(metadata_file.open("rb")) + return metadata["package"]["name"], metadata["package"]["version"] + + +def _download_cargo_dependencies( + output_path: RootedPath, cargo_dependencies: list[dict] +) -> list[dict[str, Any]]: + downloads = [] + for dep in cargo_dependencies: + checksum_info = ChecksumInfo(algorithm="sha256", hexdigest=dep["checksum"]) + dep_name = dep["name"] + dep_version = dep["version"] + download_path = Path( + output_path.join_within_root(f"deps/cargo/{dep_name}-{dep_version}.crate") + ) + download_path.parent.mkdir(exist_ok=True, parents=True) + download_url = f"https://crates.io/api/v1/crates/{dep_name}/{dep_version}/download" + download_binary_file(download_url, download_path) + must_match_any_checksum(download_path, [checksum_info]) + vendored_dep = prepare_crate_as_vendored_dep(download_path) + downloads.append( + { + "package": dep_name, + "name": dep_name, + "version": dep_version, + "path": vendored_dep, + "type": "cargo", + "dev": False, + "kind": "cratesio", + } + ) + return downloads + + +def _calc_sha256(content: bytes): + return hashlib.sha256(content).hexdigest() + + +def generate_cargo_checksum(crate_path: Path): + """Generate Cargo checksums + + cargo requires vendored dependencies to have a ".cargo_checksum.json" BUT crates + downloaded from crates.io don't come with this file. This function generates + a dictionary compatible what cargo expects. + + Args: + crate_path (Path): crate tarball + + Returns: + dict: checksums expected by cargo + """ + checksums = {"package": _calc_sha256(crate_path.read_bytes()), "files": {}} + tarball = tarfile.open(crate_path) + for tarmember in tarball.getmembers(): + name = tarmember.name.split("/", 1)[1] # ignore folder name + checksums["files"][name] = _calc_sha256(tarball.extractfile(tarmember.name).read()) + tarball.close() + return checksums + + +def prepare_crate_as_vendored_dep(crate_path: Path) -> Path: + """Prepare crates as vendored dependencies + + Extracts contents from crate and add a ".cargo_checksum.json" file to it + + Args: + crate_path (Path): crate tarball + """ + checksums = generate_cargo_checksum(crate_path) + with tarfile.open(crate_path) as tarball: + folder_name = tarball.getnames()[0].split("/")[0] + tarball.extractall(crate_path.parent) + cargo_checksum = crate_path.parent / folder_name / ".cargo-checksum.json" + json.dump(checksums, cargo_checksum.open("w")) + return crate_path.parent / folder_name + + +def _generate_purl_main_package(name: str, version: str, package_path: RootedPath) -> str: + """Get the purl for this package.""" + type = "cargo" + url = get_repo_id(package_path.root).as_vcs_url_qualifier() + qualifiers = {"vcs_url": url} + if package_path.subpath_from_root != Path("."): + subpath = package_path.subpath_from_root.as_posix() + else: + subpath = None + + purl = PackageURL( + type=type, + name=name, + version=version, + qualifiers=qualifiers, + subpath=subpath, + ) + + return purl.to_string() + + +def _generate_purl_dependency(package: dict[str, Any]) -> str: + """Get the purl for this dependency.""" + type = "cargo" + name = package["name"] + dependency_kind = package.get("kind", None) + version = None + qualifiers = None + + if dependency_kind == "cratesio": + version = package["version"] + elif dependency_kind == "vcs": + qualifiers = {"vcs_url": package["version"]} + elif dependency_kind == "url": + parsed_url = urllib.parse.urldefrag(package["version"]) + fragments = urllib.parse.parse_qs(parsed_url.fragment) + checksum = fragments["cachito_hash"][0] + qualifiers = {"download_url": parsed_url.url, "checksum": checksum} + else: + # Should not happen + raise RuntimeError(f"Unexpected requirement kind: {dependency_kind}") + + purl = PackageURL( + type=type, + name=name, + version=version, + qualifiers=qualifiers, + ) + + return purl.to_string() diff --git a/cachi2/core/resolver.py b/cachi2/core/resolver.py index 7bbc8a9b0..03af85afc 100644 --- a/cachi2/core/resolver.py +++ b/cachi2/core/resolver.py @@ -4,7 +4,7 @@ from cachi2.core.errors import UnsupportedFeature from cachi2.core.models.input import PackageManagerType, Request from cachi2.core.models.output import RequestOutput -from cachi2.core.package_managers import gomod, npm, pip +from cachi2.core.package_managers import cargo, gomod, npm, pip Handler = Callable[[Request], RequestOutput] @@ -12,6 +12,7 @@ "gomod": gomod.fetch_gomod_source, "npm": npm.fetch_npm_source, "pip": pip.fetch_pip_source, + "cargo": cargo.fetch_cargo_source, } diff --git a/docs/usage.md b/docs/usage.md index c57d328cb..1352de555 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -15,6 +15,7 @@ The second section goes through each of these steps for the supported package ma * [Example with Go modules](#example-go-modules) * [Example with pip](#example-pip) * [Example with npm](#example-npm) + * [Example with cargo](#example-cargo) ## General Process @@ -496,3 +497,140 @@ podman build . \ --network none \ --tag sample-nodejs-app ``` + + +## Example: cargo + +### Prefetch dependencies (cargo) + +```shell +mkdir -p /tmp/playground/pure-rust +cd /tmp/playground/pure-rust +git clone git@github.com:sharkdp/bat.git --branch=v0.22.1 +cachi2 fetch-deps --source bat '{"type": "cargo"}' +``` + +### Generate environment variables (cargo) + +At the moment no env var is generated for cargo, but let's do this step for compatibility +with other integrations. + +```shell +cachi2 generate-env ./cachi2-output -o ./cachi2.env --for-output-dir /tmp/cachi2-output +``` + +### Inject project files (cargo) + +```shell +$ cachi2 inject-files $(realpath cachi2-output) --for-output-dir /tmp/cachi2-output +2023-10-18 14:51:01,936 INFO Creating /tmp/playground/pure-rust/bat/.cargo/config.toml +``` + +### Build the base image (cargo) + + +Containerfile.baseimage +```Dockerfile +FROM registry.access.redhat.com/ubi9/ubi + +RUN dnf install cargo rust rust-std-static -y &&\ + dnf clean all +``` + +```shell +podman build --tag bat-base-image -f Containerfile.baseimage . +``` + +### Build the application image (cargo) + +Containerfile +```Dockerfile +FROM bat-base-image:latest + +COPY bat /app +WORKDIR /app +RUN source /tmp/cachi2.env && \ + cargo install --locked --path . +ENV PATH="/root/.cargo/bin:$PATH" +CMD bat +``` + +```shell +podman build . \ + --volume "$(realpath ./cachi2-output)":/tmp/cachi2-output:Z \ + --volume "$(realpath ./cachi2.env)":/tmp/cachi2.env:Z \ + --network none \ + --tag bat +``` + +## Example: pip with indirect cargo dependencies + +### Prefetch dependencies (pip + cargo) + +```shell +mkdir -p /tmp/playground/python-cargo +cd /tmp/playground/python-cargo +git clone git@github.com:/bruno-fs/simple-python-rust-project --branch=0.0.1 dummy +cachi2 fetch-deps --source dummy '[{"type": "pip"}, {"type": "cargo", "lock_file": "merged-cargo.lock", "pkg_name": "dummy", "pkg_version": "0.0.1"}]' +``` + +### Generate environment variables (pip + cargo) + +```shell +cachi2 generate-env ./cachi2-output -o ./cachi2.env --for-output-dir /tmp/cachi2-output +``` + +### Inject project files (pip + cargo) + +```shell +$ cachi2 inject-files $(realpath cachi2-output) --for-output-dir /tmp/cachi2-output +2023-10-18 14:51:01,936 INFO Creating /tmp/playground/python-cargo/dummy/.cargo/config.toml +``` + +### Build the base image (pip + cargo) + + +Containerfile.baseimage +```Dockerfile +FROM quay.io/centos/centos:stream8 + +RUN dnf -y install \ + python3.11 \ + python3.11-pip \ + python3.11-devel \ + gcc \ + libffi-devel \ + openssl-devel \ + cargo \ + rust \ + rust-std-static &&\ + dnf clean all +``` + +```shell +podman build --tag dummy-base-image -f Containerfile.baseimage . +``` + +### Build the application image (pip + cargo) + +Containerfile +```Dockerfile +FROM dummy-base-image:latest + +COPY dummy /app +# we don't have a way to control where pip will build +# cargo dependencies, so we need to move cargo configuration +# to the place where python run builds +COPY dummy/.cargo/config.toml /tmp/.cargo/config.toml +WORKDIR /app +RUN source /tmp/cachi2.env && \ + pip3 install -r requirements.txt +``` + +```shell +podman build . \ + --volume "$(realpath ./cachi2-output)":/tmp/cachi2-output:Z \ + --volume "$(realpath ./cachi2.env)":/tmp/cachi2.env:Z \ + --network none \ + --tag dummy +``` \ No newline at end of file diff --git a/playground/python-and-rust/case-study-quipucords.ipynb b/playground/python-and-rust/case-study-quipucords.ipynb new file mode 100644 index 000000000..bbccb4295 --- /dev/null +++ b/playground/python-and-rust/case-study-quipucords.ipynb @@ -0,0 +1,1118 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A more complex example: python + rust\n", + "\n", + "Let's use current PoC to build a project that depends indirectly on rust since this seems\n", + "to be the most common use case (and, quite frankly, it's the use case I'm particularly\n", + "most interested).\n", + "\n", + "For this purpose I chose to use discovery upstream code (quipucords), since I'm familiar\n", + "with its build process. It's a python project that depends on cryptography and bcrypt -\n", + "libraries that have rust dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cloning into 'quipucords'...\n", + "remote: Enumerating objects: 460, done.\u001b[K\n", + "remote: Counting objects: 100% (460/460), done.\u001b[K\n", + "remote: Compressing objects: 100% (374/374), done.\u001b[K\n", + "remote: Total 460 (delta 51), reused 199 (delta 26), pack-reused 0\u001b[K\n", + "Receiving objects: 100% (460/460), 871.99 KiB | 1.82 MiB/s, done.\n", + "Resolving deltas: 100% (51/51), done.\n", + "Note: switching to '4d91ee52124fcf1d3a2b5d725043f57957e73356'.\n", + "\n", + "You are in 'detached HEAD' state. You can look around, make experimental\n", + "changes and commit them, and you can discard any commits you make in this\n", + "state without impacting any branches by switching back to a branch.\n", + "\n", + "If you want to create a new branch to retain commits you create, you may\n", + "do so (now or later) by using -c with the switch command. Example:\n", + "\n", + " git switch -c \n", + "\n", + "Or undo this operation with:\n", + "\n", + " git switch -\n", + "\n", + "Turn off this advice by setting config variable advice.detachedHead to false\n", + "\n" + ] + } + ], + "source": [ + "# lets start cloning both quipucords\n", + "!git clone git@github.com:quipucords/quipucords.git --depth 1 --branch=1.2.5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quipucords don't have it's rust dependencies listed like python dependencies. To fix \n", + "this, let's create a quick script to search it's requirements/requirements-build.\n", + "\n", + "In the future we could have a improved version of this script and recommend that users\n", + "run it (like `pip_find_builddeps.py` script)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import tarfile\n", + "\n", + "# this script requires you to pip install pybuild-deps, which I built as an alternative\n", + "# to pip_find_builddeps\n", + "from pybuild_deps.find_build_dependencies import find_build_dependencies\n", + "from pybuild_deps.get_package_source import get_package_source\n", + "\n", + "from cachi2.core.package_managers.pip import PipRequirementsFile\n", + "\n", + "LOCK_FILE = \"Cargo.lock\"\n", + "PACKAGE_FILE = \"Cargo.toml\"\n", + "\n", + "def depends_on_rust(deps: list) -> bool:\n", + " for d in deps:\n", + " if d.startswith(\"setuptools-rust\"):\n", + " return True\n", + " return False\n", + "\n", + "def _save_dep_file(tarball, full_file_name, path_to_dependencies_file):\n", + " file_handle = tarball.extractfile(full_file_name)\n", + " path_to_dependencies_file.parent.mkdir(exist_ok=True, parents=True)\n", + " path_to_dependencies_file.write_bytes(file_handle.read())\n", + "\n", + "def find_rust_deps(requirements_file):\n", + " req_file = PipRequirementsFile(Path(requirements_file))\n", + " for req in req_file.requirements:\n", + " package_name = req.package\n", + " version_qualifier, version = req.version_specs[0]\n", + " assert version_qualifier == \"==\", \"an EXACT match is required.\"\n", + " build_dependencies = find_build_dependencies(package_name, version)\n", + " if not depends_on_rust(build_dependencies):\n", + " continue\n", + " source_code = get_package_source(package_name, version)\n", + " with tarfile.open(fileobj=source_code.open(\"rb\")) as tarball:\n", + " for full_file_name in tarball.getnames():\n", + " # this is assuming a source code contains only one cargo.toml/lock, \n", + " # which might not be true - (for the packages used in this exercise it \n", + " # is OK)\n", + " if full_file_name.endswith((LOCK_FILE, PACKAGE_FILE)):\n", + " file_name = Path(full_file_name).name\n", + " path_to_dependencies_file = (\n", + " req_file.file_path.parent / \"dependencies\" / f\"{package_name}-rust\" / file_name\n", + " )\n", + " _save_dep_file(tarball, full_file_name, path_to_dependencies_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "find_rust_deps(\"quipucords/requirements.txt\")\n", + "find_rust_deps(\"quipucords/requirements-build.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[01;34mquipucords/dependencies\u001b[0m\n", + "├── \u001b[01;34mbcrypt-rust\u001b[0m\n", + "│   ├── \u001b[00mCargo.lock\u001b[0m\n", + "│   └── \u001b[00mCargo.toml\u001b[0m\n", + "└── \u001b[01;34mcryptography-rust\u001b[0m\n", + " ├── \u001b[00mCargo.lock\u001b[0m\n", + " └── \u001b[00mCargo.toml\u001b[0m\n", + "\n", + "3 directories, 4 files\n" + ] + } + ], + "source": [ + "!tree quipucords/dependencies" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pre-fetch dependencies\n", + "\n", + "Now with all requirements files in place we can use cachi2 to fetch dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2023-04-28 14:32:58,091 INFO Extracting metadata from setup.py\n", + "2023-04-28 14:32:58,093 INFO Found name in setup.py: 'quipucords'\n", + "2023-04-28 14:32:58,094 INFO Found version in setup.py: '0.0.0'\n", + "2023-04-28 14:32:58,094 INFO Resolved package name: 'quipucords'\n", + "2023-04-28 14:32:58,094 INFO Resolved package version: '0.0.0'\n", + "2023-04-28 14:32:58,126 INFO No hash options used, will not require hashes unless HTTP(S) dependencies are present.\n", + "2023-04-28 14:32:58,127 INFO Downloading amqp==5.1.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:32:58,307 INFO Successfully downloaded amqp==5.1.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/amqp-5.1.1.tar.gz\n", + "2023-04-28 14:32:58,307 INFO Downloading ansible-core==2.13.8 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:32:59,406 INFO Successfully downloaded ansible-core==2.13.8 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/ansible-core-2.13.8.tar.gz\n", + "2023-04-28 14:32:59,406 INFO Downloading ansible-runner==2.3.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:32:59,471 INFO Successfully downloaded ansible-runner==2.3.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/ansible-runner-2.3.2.tar.gz\n", + "2023-04-28 14:32:59,471 INFO Downloading ansible==6.7.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,154 INFO Successfully downloaded ansible==6.7.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/ansible-6.7.0.tar.gz\n", + "2023-04-28 14:33:01,154 INFO Downloading asgiref==3.6.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,180 INFO Successfully downloaded asgiref==3.6.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/asgiref-3.6.0.tar.gz\n", + "2023-04-28 14:33:01,180 INFO Downloading async-timeout==4.0.2 ; python_version >= \"3.9\" and python_version <= \"3.11.2\"\n", + "2023-04-28 14:33:01,201 INFO Successfully downloaded async-timeout==4.0.2 ; python_version >= \"3.9\" and python_version <= \"3.11.2\" to deps/pip/async-timeout-4.0.2.tar.gz\n", + "2023-04-28 14:33:01,201 INFO Downloading bcrypt==4.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,258 INFO Successfully downloaded bcrypt==4.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/bcrypt-4.0.1.tar.gz\n", + "2023-04-28 14:33:01,259 INFO Downloading billiard==3.6.4.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,299 INFO Successfully downloaded billiard==3.6.4.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/billiard-3.6.4.0.tar.gz\n", + "2023-04-28 14:33:01,299 INFO Downloading cachetools==5.3.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,326 INFO Successfully downloaded cachetools==5.3.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/cachetools-5.3.0.tar.gz\n", + "2023-04-28 14:33:01,326 INFO Downloading celery[redis]==5.2.7 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,427 INFO Successfully downloaded celery[redis]==5.2.7 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/celery-5.2.7.tar.gz\n", + "2023-04-28 14:33:01,427 INFO Downloading certifi==2022.12.7 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:01,460 INFO Successfully downloaded certifi==2022.12.7 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/certifi-2022.12.7.tar.gz\n", + "2023-04-28 14:33:01,460 INFO Downloading cffi==1.15.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,602 INFO Successfully downloaded cffi==1.15.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/cffi-1.15.1.tar.gz\n", + "2023-04-28 14:33:01,602 INFO Downloading charset-normalizer==3.1.0 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:01,673 INFO Successfully downloaded charset-normalizer==3.1.0 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/charset-normalizer-3.1.0.tar.gz\n", + "2023-04-28 14:33:01,673 INFO Downloading click-didyoumean==0.3.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,697 INFO Successfully downloaded click-didyoumean==0.3.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/click-didyoumean-0.3.0.tar.gz\n", + "2023-04-28 14:33:01,697 INFO Downloading click-plugins==1.1.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,717 INFO Successfully downloaded click-plugins==1.1.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/click-plugins-1.1.1.tar.gz\n", + "2023-04-28 14:33:01,717 INFO Downloading click-repl==0.2.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,738 INFO Successfully downloaded click-repl==0.2.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/click-repl-0.2.0.tar.gz\n", + "2023-04-28 14:33:01,738 INFO Downloading click==8.1.3 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:01,784 INFO Successfully downloaded click==8.1.3 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/click-8.1.3.tar.gz\n", + "2023-04-28 14:33:01,784 INFO Downloading colorama==0.4.6 ; python_version >= \"3.9\" and python_version < \"4.0\" and platform_system == \"Windows\"\n", + "2023-04-28 14:33:01,819 INFO Successfully downloaded colorama==0.4.6 ; python_version >= \"3.9\" and python_version < \"4.0\" and platform_system == \"Windows\" to deps/pip/colorama-0.4.6.tar.gz\n", + "2023-04-28 14:33:01,819 INFO Downloading cryptography==40.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,054 INFO Successfully downloaded cryptography==40.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/cryptography-40.0.1.tar.gz\n", + "2023-04-28 14:33:02,054 INFO Downloading django-environ==0.10.0 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:02,079 INFO Successfully downloaded django-environ==0.10.0 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/django-environ-0.10.0.tar.gz\n", + "2023-04-28 14:33:02,079 INFO Downloading django-filter==23.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,106 INFO Successfully downloaded django-filter==23.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/django-filter-23.1.tar.gz\n", + "2023-04-28 14:33:02,106 INFO Downloading django==4.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,659 INFO Successfully downloaded django==4.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/Django-4.2.tar.gz\n", + "2023-04-28 14:33:02,659 INFO Downloading djangorestframework==3.14.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,763 INFO Successfully downloaded djangorestframework==3.14.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/djangorestframework-3.14.0.tar.gz\n", + "2023-04-28 14:33:02,764 INFO Downloading docutils==0.19 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,873 INFO Successfully downloaded docutils==0.19 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/docutils-0.19.tar.gz\n", + "2023-04-28 14:33:02,873 INFO Downloading google-auth==2.17.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,921 INFO Successfully downloaded google-auth==2.17.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/google-auth-2.17.2.tar.gz\n", + "2023-04-28 14:33:02,921 INFO Downloading gunicorn==20.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:02,973 INFO Successfully downloaded gunicorn==20.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/gunicorn-20.1.0.tar.gz\n", + "2023-04-28 14:33:02,973 INFO Downloading idna==3.4 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:03,011 INFO Successfully downloaded idna==3.4 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/idna-3.4.tar.gz\n", + "2023-04-28 14:33:03,011 INFO Downloading jinja2==3.1.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,045 INFO Successfully downloaded jinja2==3.1.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/Jinja2-3.1.2.tar.gz\n", + "2023-04-28 14:33:03,045 INFO Downloading jmespath==1.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,140 INFO Successfully downloaded jmespath==1.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/jmespath-1.0.1.tar.gz\n", + "2023-04-28 14:33:03,141 INFO Downloading kombu==5.2.4 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,227 INFO Successfully downloaded kombu==5.2.4 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/kombu-5.2.4.tar.gz\n", + "2023-04-28 14:33:03,227 INFO Downloading kubernetes==26.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,288 INFO Successfully downloaded kubernetes==26.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/kubernetes-26.1.0.tar.gz\n", + "2023-04-28 14:33:03,288 INFO Downloading lockfile==0.12.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,303 INFO Successfully downloaded lockfile==0.12.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/lockfile-0.12.2.tar.gz\n", + "2023-04-28 14:33:03,303 INFO Downloading markupsafe==2.1.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,357 INFO Successfully downloaded markupsafe==2.1.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/MarkupSafe-2.1.2.tar.gz\n", + "2023-04-28 14:33:03,357 INFO Downloading oauthlib==3.2.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,396 INFO Successfully downloaded oauthlib==3.2.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/oauthlib-3.2.2.tar.gz\n", + "2023-04-28 14:33:03,396 INFO Downloading openshift==0.13.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,424 INFO Successfully downloaded openshift==0.13.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/openshift-0.13.1.tar.gz\n", + "2023-04-28 14:33:03,425 INFO Downloading packaging==23.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,467 INFO Successfully downloaded packaging==23.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/packaging-23.0.tar.gz\n", + "2023-04-28 14:33:03,467 INFO Downloading paramiko==3.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,579 INFO Successfully downloaded paramiko==3.1.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/paramiko-3.1.0.tar.gz\n", + "2023-04-28 14:33:03,580 INFO Downloading pexpect==4.8.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,615 INFO Successfully downloaded pexpect==4.8.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pexpect-4.8.0.tar.gz\n", + "2023-04-28 14:33:03,615 INFO Downloading prompt-toolkit==3.0.38 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,683 INFO Successfully downloaded prompt-toolkit==3.0.38 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/prompt_toolkit-3.0.38.tar.gz\n", + "2023-04-28 14:33:03,683 INFO Downloading psycopg2-binary==2.9.6 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,774 INFO Successfully downloaded psycopg2-binary==2.9.6 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/psycopg2-binary-2.9.6.tar.gz\n", + "2023-04-28 14:33:03,774 INFO Downloading ptyprocess==0.7.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,796 INFO Successfully downloaded ptyprocess==0.7.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/ptyprocess-0.7.0.tar.gz\n", + "2023-04-28 14:33:03,796 INFO Downloading pyasn1-modules==0.2.8 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,876 INFO Successfully downloaded pyasn1-modules==0.2.8 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pyasn1-modules-0.2.8.tar.gz\n", + "2023-04-28 14:33:03,876 INFO Downloading pyasn1==0.4.8 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,928 INFO Successfully downloaded pyasn1==0.4.8 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pyasn1-0.4.8.tar.gz\n", + "2023-04-28 14:33:03,928 INFO Downloading pycparser==2.21 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:03,993 INFO Successfully downloaded pycparser==2.21 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pycparser-2.21.tar.gz\n", + "2023-04-28 14:33:03,993 INFO Downloading pydantic==1.10.7 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,125 INFO Successfully downloaded pydantic==1.10.7 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pydantic-1.10.7.tar.gz\n", + "2023-04-28 14:33:04,125 INFO Downloading pynacl==1.5.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,299 INFO Successfully downloaded pynacl==1.5.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/PyNaCl-1.5.0.tar.gz\n", + "2023-04-28 14:33:04,299 INFO Downloading python-daemon==3.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,327 INFO Successfully downloaded python-daemon==3.0.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/python-daemon-3.0.1.tar.gz\n", + "2023-04-28 14:33:04,327 INFO Downloading python-dateutil==2.8.2 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,365 INFO Successfully downloaded python-dateutil==2.8.2 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/python-dateutil-2.8.2.tar.gz\n", + "2023-04-28 14:33:04,366 INFO Downloading python-string-utils==1.0.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,384 INFO Successfully downloaded python-string-utils==1.0.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/python-string-utils-1.0.0.tar.gz\n", + "2023-04-28 14:33:04,385 INFO Downloading pytz==2023.3 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,528 INFO Successfully downloaded pytz==2023.3 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pytz-2023.3.tar.gz\n", + "2023-04-28 14:33:04,529 INFO Downloading pyvmomi==7.0.3 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,588 INFO Successfully downloaded pyvmomi==7.0.3 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/pyvmomi-7.0.3.tar.gz\n", + "2023-04-28 14:33:04,588 INFO Downloading pyyaml==6.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,640 INFO Successfully downloaded pyyaml==6.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/PyYAML-6.0.tar.gz\n", + "2023-04-28 14:33:04,640 INFO Downloading redis==4.5.4 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,885 INFO Successfully downloaded redis==4.5.4 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/redis-4.5.4.tar.gz\n", + "2023-04-28 14:33:04,885 INFO Downloading requests-oauthlib==1.3.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:04,905 INFO Successfully downloaded requests-oauthlib==1.3.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/requests-oauthlib-1.3.1.tar.gz\n", + "2023-04-28 14:33:04,906 INFO Downloading requests==2.28.2 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:05,007 INFO Successfully downloaded requests==2.28.2 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/requests-2.28.2.tar.gz\n", + "2023-04-28 14:33:05,007 INFO Downloading resolvelib==0.8.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,032 INFO Successfully downloaded resolvelib==0.8.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/resolvelib-0.8.1.tar.gz\n", + "2023-04-28 14:33:05,032 INFO Downloading rsa==4.9 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:05,058 INFO Successfully downloaded rsa==4.9 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/rsa-4.9.tar.gz\n", + "2023-04-28 14:33:05,058 INFO Downloading setuptools==67.6.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,295 INFO Successfully downloaded setuptools==67.6.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/setuptools-67.6.1.tar.gz\n", + "2023-04-28 14:33:05,295 INFO Downloading six==1.16.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,316 INFO Successfully downloaded six==1.16.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/six-1.16.0.tar.gz\n", + "2023-04-28 14:33:05,316 INFO Downloading sqlparse==0.4.3 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,341 INFO Successfully downloaded sqlparse==0.4.3 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/sqlparse-0.4.3.tar.gz\n", + "2023-04-28 14:33:05,341 INFO Downloading typing-extensions==4.5.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,368 INFO Successfully downloaded typing-extensions==4.5.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/typing_extensions-4.5.0.tar.gz\n", + "2023-04-28 14:33:05,368 INFO Downloading tzdata==2023.3 ; python_version >= \"3.9\" and python_version < \"4.0\" and sys_platform == \"win32\"\n", + "2023-04-28 14:33:05,400 INFO Successfully downloaded tzdata==2023.3 ; python_version >= \"3.9\" and python_version < \"4.0\" and sys_platform == \"win32\" to deps/pip/tzdata-2023.3.tar.gz\n", + "2023-04-28 14:33:05,400 INFO Downloading urllib3==1.26.15 ; python_version >= \"3.9\" and python_version < \"4\"\n", + "2023-04-28 14:33:05,446 INFO Successfully downloaded urllib3==1.26.15 ; python_version >= \"3.9\" and python_version < \"4\" to deps/pip/urllib3-1.26.15.tar.gz\n", + "2023-04-28 14:33:05,446 INFO Downloading vine==5.0.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,484 INFO Successfully downloaded vine==5.0.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/vine-5.0.0.tar.gz\n", + "2023-04-28 14:33:05,485 INFO Downloading wcwidth==0.2.6 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,517 INFO Successfully downloaded wcwidth==0.2.6 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/wcwidth-0.2.6.tar.gz\n", + "2023-04-28 14:33:05,517 INFO Downloading websocket-client==1.5.1 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,550 INFO Successfully downloaded websocket-client==1.5.1 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/websocket-client-1.5.1.tar.gz\n", + "2023-04-28 14:33:05,550 INFO Downloading whitenoise==6.4.0 ; python_version >= \"3.9\" and python_version < \"4.0\"\n", + "2023-04-28 14:33:05,577 INFO Successfully downloaded whitenoise==6.4.0 ; python_version >= \"3.9\" and python_version < \"4.0\" to deps/pip/whitenoise-6.4.0.tar.gz\n", + "2023-04-28 14:33:05,580 INFO No hash options used, will not require hashes unless HTTP(S) dependencies are present.\n", + "2023-04-28 14:33:05,580 INFO Downloading calver==2022.6.26\n", + "2023-04-28 14:33:05,602 INFO Successfully downloaded calver==2022.6.26 to deps/pip/calver-2022.6.26.tar.gz\n", + "2023-04-28 14:33:05,602 INFO Downloading cffi==1.15.1 ; platform_python_implementation != \"PyPy\"\n", + "2023-04-28 14:33:05,768 INFO Successfully downloaded cffi==1.15.1 ; platform_python_implementation != \"PyPy\" to deps/pip/cffi-1.15.1.tar.gz\n", + "2023-04-28 14:33:05,768 INFO Downloading cython==0.29.34\n", + "2023-04-28 14:33:06,166 INFO Successfully downloaded cython==0.29.34 to deps/pip/Cython-0.29.34.tar.gz\n", + "2023-04-28 14:33:06,166 INFO Downloading docutils==0.19\n", + "2023-04-28 14:33:06,264 INFO Successfully downloaded docutils==0.19 to deps/pip/docutils-0.19.tar.gz\n", + "2023-04-28 14:33:06,264 INFO Downloading editables==0.3\n", + "2023-04-28 14:33:06,281 INFO Successfully downloaded editables==0.3 to deps/pip/editables-0.3.tar.gz\n", + "2023-04-28 14:33:06,281 INFO Downloading flit-core==3.8.0\n", + "2023-04-28 14:33:06,317 INFO Successfully downloaded flit-core==3.8.0 to deps/pip/flit_core-3.8.0.tar.gz\n", + "2023-04-28 14:33:06,317 INFO Downloading hatchling==1.14.0\n", + "2023-04-28 14:33:06,356 INFO Successfully downloaded hatchling==1.14.0 to deps/pip/hatchling-1.14.0.tar.gz\n", + "2023-04-28 14:33:06,356 INFO Downloading packaging==23.0\n", + "2023-04-28 14:33:06,415 INFO Successfully downloaded packaging==23.0 to deps/pip/packaging-23.0.tar.gz\n", + "2023-04-28 14:33:06,415 INFO Downloading pathspec==0.11.1\n", + "2023-04-28 14:33:06,452 INFO Successfully downloaded pathspec==0.11.1 to deps/pip/pathspec-0.11.1.tar.gz\n", + "2023-04-28 14:33:06,452 INFO Downloading pbr==5.11.1\n", + "2023-04-28 14:33:06,491 INFO Successfully downloaded pbr==5.11.1 to deps/pip/pbr-5.11.1.tar.gz\n", + "2023-04-28 14:33:06,491 INFO Downloading pluggy==1.0.0\n", + "2023-04-28 14:33:06,512 INFO Successfully downloaded pluggy==1.0.0 to deps/pip/pluggy-1.0.0.tar.gz\n", + "2023-04-28 14:33:06,512 INFO Downloading poetry-core==1.5.2\n", + "2023-04-28 14:33:06,628 INFO Successfully downloaded poetry-core==1.5.2 to deps/pip/poetry_core-1.5.2.tar.gz\n", + "2023-04-28 14:33:06,628 INFO Downloading pycparser==2.21\n", + "2023-04-28 14:33:06,659 INFO Successfully downloaded pycparser==2.21 to deps/pip/pycparser-2.21.tar.gz\n", + "2023-04-28 14:33:06,659 INFO Downloading semantic-version==2.10.0\n", + "2023-04-28 14:33:06,686 INFO Successfully downloaded semantic-version==2.10.0 to deps/pip/semantic_version-2.10.0.tar.gz\n", + "2023-04-28 14:33:06,686 INFO Downloading setuptools-rust==1.5.2\n", + "2023-04-28 14:33:06,729 INFO Successfully downloaded setuptools-rust==1.5.2 to deps/pip/setuptools-rust-1.5.2.tar.gz\n", + "2023-04-28 14:33:06,730 INFO Downloading setuptools-scm==7.1.0\n", + "2023-04-28 14:33:06,812 INFO Successfully downloaded setuptools-scm==7.1.0 to deps/pip/setuptools_scm-7.1.0.tar.gz\n", + "2023-04-28 14:33:06,812 INFO Downloading tomli==2.0.1\n", + "2023-04-28 14:33:06,840 INFO Successfully downloaded tomli==2.0.1 to deps/pip/tomli-2.0.1.tar.gz\n", + "2023-04-28 14:33:06,840 INFO Downloading trove-classifiers==2023.3.9\n", + "2023-04-28 14:33:06,900 INFO Successfully downloaded trove-classifiers==2023.3.9 to deps/pip/trove-classifiers-2023.3.9.tar.gz\n", + "2023-04-28 14:33:06,901 INFO Downloading typing-extensions==4.5.0\n", + "2023-04-28 14:33:06,925 INFO Successfully downloaded typing-extensions==4.5.0 to deps/pip/typing_extensions-4.5.0.tar.gz\n", + "2023-04-28 14:33:06,925 INFO Downloading wheel==0.40.0\n", + "2023-04-28 14:33:06,969 INFO Successfully downloaded wheel==0.40.0 to deps/pip/wheel-0.40.0.tar.gz\n", + "2023-04-28 14:33:06,969 INFO Downloading setuptools==66.1.1 ; python_version != \"3.3\"\n", + "2023-04-28 14:33:07,251 INFO Successfully downloaded setuptools==66.1.1 ; python_version != \"3.3\" to deps/pip/setuptools-66.1.1.tar.gz\n", + "2023-04-28 14:33:07,271 INFO All dependencies fetched successfully \\o/\n" + ] + } + ], + "source": [ + "!cachi2 fetch-deps --source quipucords '[{\"type\": \"pip\"},{\"type\": \"cargo\", \"path\": \"dependencies/cryptography-rust\"},{\"type\": \"cargo\", \"path\": \"dependencies/bcrypt-rust\"}]'" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate environment variables" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "export PIP_FIND_LINKS=/tmp/cachi2-output/deps/pip\n", + "export PIP_NO_INDEX=true\n" + ] + } + ], + "source": [ + "!cachi2 generate-env \"$(realpath ./cachi2-output)\" -o $(pwd)/cachi2.env --for-output-dir /tmp/cachi2-output\n", + "!cat cachi2.env" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inject project files\n", + "\n", + "This part is not implemented for the cargo integration yet.\n", + "We need a configuration file and a index directory so cargo can use the prefetched dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting cargo_config.toml\n" + ] + } + ], + "source": [ + "%%writefile cargo_config.toml\n", + "[source.crates-io]\n", + "replace-with = \"local\"\n", + "\n", + "[source.local]\n", + "local-registry = \"/tmp/cachi2-output\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cloning into 'cachi2-output/index'...\n", + "remote: Enumerating objects: 137868, done.\u001b[K\n", + "remote: Counting objects: 100% (137868/137868), done.\u001b[K\n", + "remote: Compressing objects: 100% (55464/55464), done.\u001b[K\n", + "remote: Total 137868 (delta 74911), reused 127894 (delta 68744), pack-reused 0\u001b[K\n", + "Receiving objects: 100% (137868/137868), 71.82 MiB | 10.32 MiB/s, done.\n", + "Resolving deltas: 100% (74911/74911), done.\n", + "Updating files: 100% (112641/112641), done.\n" + ] + } + ], + "source": [ + "# generating cargo indexes should be done only for the downloaded packages - \n", + "# but for now lets skip that (I still don't know how to do it XD) and just clone the \n", + "# whole thing\n", + "!git clone git@github.com:rust-lang/crates.io-index.git --depth 1 cachi2-output/index" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "!cachi2 inject-files \"$(realpath ./cachi2-output)\" --for-output-dir /tmp/cachi2-output" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build the base and UI images" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting Containerfile.baseimage\n" + ] + } + ], + "source": [ + "%%writefile Containerfile.baseimage\n", + "FROM registry.redhat.io/ubi8/ubi\n", + "\n", + "ARG BUILDREQUIRES='cargo gcc libffi-devel libpq-devel libtool openssl-devel patch python39-devel rust rust-std-static llvm-libs'\n", + "RUN dnf install \\\n", + " git \\\n", + " glibc-langpack-en \\\n", + " jq \\\n", + " libpq \\\n", + " make \\\n", + " openssh-clients \\\n", + " python39 \\\n", + " sshpass \\\n", + " tar \\\n", + " which \\\n", + " $BUILDREQUIRES \\\n", + " -y &&\\\n", + " dnf clean all" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "STEP 1/3: FROM registry.redhat.io/ubi8/ubi\n", + "STEP 2/3: ARG BUILDREQUIRES='cargo gcc libffi-devel libpq-devel libtool openssl-devel patch python39-devel rust rust-std-static llvm-libs'\n", + "--> Using cache fc1e4e9a054e934f33d2f078cfe908b95e3118189cf5cd9a42e1ae1825f44d3a\n", + "--> fc1e4e9a054e\n", + "STEP 3/3: RUN dnf install git glibc-langpack-en jq libpq make openssh-clients python39 sshpass tar which $BUILDREQUIRES -y && dnf clean all\n", + "--> Using cache a5454992f1fc76faa79b37b7a8d58109af1377496b44da84565a0d4894241bb4\n", + "COMMIT quipucords-base-image\n", + "--> a5454992f1fc\n", + "Successfully tagged localhost/quipucords-base-image:latest\n", + "a5454992f1fc76faa79b37b7a8d58109af1377496b44da84565a0d4894241bb4\n" + ] + } + ], + "source": [ + "!podman build --tag quipucords-base-image -f Containerfile.baseimage ." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "quipucords also has a UI. let's build it separately and ignore cachi2 for the sake \n", + "of simplicity" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cloning into 'quipucords-ui'...\n", + "remote: Enumerating objects: 543, done.\u001b[K\n", + "remote: Counting objects: 100% (543/543), done.\u001b[K\n", + "remote: Compressing objects: 100% (494/494), done.\u001b[K\n", + "remote: Total 543 (delta 98), reused 274 (delta 41), pack-reused 0\u001b[K\n", + "Receiving objects: 100% (543/543), 589.31 KiB | 1.24 MiB/s, done.\n", + "Resolving deltas: 100% (98/98), done.\n", + "Note: switching to '6ff43b4e466bd75de36f4533d4e0255f9a1b47b9'.\n", + "\n", + "You are in 'detached HEAD' state. You can look around, make experimental\n", + "changes and commit them, and you can discard any commits you make in this\n", + "state without impacting any branches by switching back to a branch.\n", + "\n", + "If you want to create a new branch to retain commits you create, you may\n", + "do so (now or later) by using -c with the switch command. Example:\n", + "\n", + " git switch -c \n", + "\n", + "Or undo this operation with:\n", + "\n", + " git switch -\n", + "\n", + "Turn off this advice by setting config variable advice.detachedHead to false\n", + "\n" + ] + } + ], + "source": [ + "!git clone git@github.com:quipucords/quipucords-ui.git --depth 1 --branch=1.2.0" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting Containerfile.quipucords-ui\n" + ] + } + ], + "source": [ + "%%writefile Containerfile.quipucords-ui\n", + "FROM registry.access.redhat.com/ubi8/nodejs-16\n", + "\n", + "USER root\n", + "RUN npm --userconfig .npmrc install --global yarn\n", + "# Install/build UI\n", + "COPY quipucords-ui /app\n", + "WORKDIR /app\n", + "\n", + "RUN yarn install &&\\\n", + " yarn build:brand" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "STEP 1/6: FROM registry.access.redhat.com/ubi8/nodejs-16\n", + "STEP 2/6: USER root\n", + "--> Using cache 2b5a30209585694c84a5eef77d9050d16c96e9cbd99cd3ccd5c5175855ed0fe4\n", + "--> 2b5a30209585\n", + "STEP 3/6: RUN npm --userconfig .npmrc install --global yarn\n", + "--> Using cache e3bdf0ef69c3de2a4f96f2596e52aee23b10ec928e7e8779374cd607713ffc58\n", + "--> e3bdf0ef69c3\n", + "STEP 4/6: COPY quipucords-ui /app\n", + "--> 01b3b4858943\n", + "STEP 5/6: WORKDIR /app\n", + "--> 283af5c87d65\n", + "STEP 6/6: RUN yarn install && yarn build:brand\n", + "yarn install v1.22.19\n", + "[1/5] Validating package.json...\n", + "[2/5] Resolving packages...\n", + "[3/5] Fetching packages...\n", + "[4/5] Linking dependencies...\n", + "warning \" > bootstrap@5.1.3\" has unmet peer dependency \"@popperjs/core@^2.10.2\".\n", + "warning \" > patternfly-react@2.40.0\" has incorrect peer dependency \"react@^16.3.2\".\n", + "warning \" > patternfly-react@2.40.0\" has incorrect peer dependency \"react-dom@^15.6.2 || ^16.2.0\".\n", + "warning \"patternfly-react > react-bootstrap-typeahead@3.4.3\" has incorrect peer dependency \"react@^0.14.0 || ^15.2.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-bootstrap-typeahead@3.4.3\" has incorrect peer dependency \"react-dom@^0.14.0 || ^15.2.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-c3js@0.1.20\" has incorrect peer dependency \"react@^15.5.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-c3js@0.1.20\" has incorrect peer dependency \"react-dom@^15.5.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-debounce-input@3.2.0\" has incorrect peer dependency \"react@^15.3.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-ellipsis-with-tooltip@1.0.8\" has incorrect peer dependency \"react@^15.6.2 || ^16.0.0\".\n", + "warning \"patternfly-react > react-ellipsis-with-tooltip@1.0.8\" has incorrect peer dependency \"react-dom@^15.6.2 || ^16.0.0\".\n", + "warning \"patternfly-react > react-ellipsis-with-tooltip@1.0.8\" has incorrect peer dependency \"react-bootstrap@0.31.x || 0.32.x\".\n", + "warning \"patternfly-react > react-motion@0.5.2\" has incorrect peer dependency \"react@^0.14.9 || ^15.3.0 || ^16.0.0\".\n", + "warning \"patternfly-react > reactabular-table@8.14.0\" has incorrect peer dependency \"react@>= 0.11.2 < 17.0.0\".\n", + "warning \"patternfly-react > sortabular@1.6.0\" has incorrect peer dependency \"react@>= 15.0.0 < 17.0.0\".\n", + "warning \"patternfly-react > table-resolver@3.3.0\" has incorrect peer dependency \"redux@>= 3.0.0 < 4.0.0\".\n", + "warning \"patternfly-react > react-bootstrap-typeahead > create-react-context@0.2.3\" has incorrect peer dependency \"react@^0.14.0 || ^15.0.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-bootstrap-typeahead > react-popper@1.3.3\" has incorrect peer dependency \"react@0.14.x || ^15.0.0 || ^16.0.0\".\n", + "warning \"patternfly-react > react-bootstrap-typeahead > react-popper > create-react-context@0.2.2\" has incorrect peer dependency \"react@^0.14.0 || ^15.0.0 || ^16.0.0\".\n", + "warning \"react-scripts > @typescript-eslint/eslint-plugin > tsutils@3.21.0\" has unmet peer dependency \"typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta\".\n", + "warning \"react-scripts > eslint-plugin-testing-library > @typescript-eslint/experimental-utils > @typescript-eslint/typescript-estree > tsutils@3.17.1\" has unmet peer dependency \"typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta\".\n", + "warning \"swagger-parser > @apidevtools/swagger-parser@10.0.3\" has unmet peer dependency \"openapi-types@>=7\".\n", + "[5/5] Building fresh packages...\n", + "Done in 79.31s.\n", + "yarn run v1.22.19\n", + "$ run-s -l 'build:pre -b' 'build:docs -b' test:docs build:template-css build:js build:post test:integration\n", + "[build:pre -b ] $ bash ./scripts/pre.sh -b\n", + "[build:pre -b ] Cleaning css directories...\n", + "[build:pre -b ] Cleaning build directories...\n", + "[build:pre -b ] rm: cannot remove '/app/.env.production.local': No such file or directory\n", + "[build:pre -b ] Version... UI_VERSION=1.2.0.6ff43b4\n", + "[build:pre -b ] Brand... UI_BRAND=true\n", + "[build:pre -b ] App name... UI_NAME=product discovery\n", + "[build:pre -b ] App short name... UI_SHORT_NAME=discovery\n", + "[build:pre -b ] App sentence start name... UI_SENTENCE_START_NAME=The product discovery tool\n", + "[build:docs -b ] $ node ./scripts/quipudocs.js -b\n", + "[build:docs -b ] Building docs... DOCS_BRAND=true...Complete\n", + "[build:docs -b ] Building locale files...Complete\n", + "[test:docs ] $ htmlhint ./public/docs; eslint --ext=json ./public/locales\n", + "[test:docs ] \n", + "[test:docs ] Scanned 2 files, no errors found (45 ms).\n", + "[build:template-css] $ run-s build:template-scss build:template-css-font\n", + "[build:template-css] $ sass --no-source-map --load-path ./src --load-path ./node_modules ./src/styles/template.scss ./src/styles/.css/index.css\n", + "[build:template-css] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:template-css] \n", + "[build:template-css] Recommendation: math.div(9 * $applauncher-pf-menu-link-icon-font-size, 14) or calc((9 * $applauncher-pf-menu-link-icon-font-size) / 14)\n", + "[build:template-css] \n", + "[build:template-css] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:template-css] \n", + "[build:template-css] ╷\n", + "[build:template-css] 30 │ $applauncher-pf-menu-link-icon-width: ((9 * $applauncher-pf-menu-link-icon-font-size) / 14) !default; //Numbers to imitate fa-fw class\n", + "[build:template-css] │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:template-css] ╵\n", + "[build:template-css] patternfly/dist/sass/patternfly/_variables.scss 30:70 @import\n", + "[build:template-css] src/styles/template.scss 13:9 root stylesheet\n", + "[build:template-css] \n", + "[build:template-css] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:template-css] \n", + "[build:template-css] Recommendation: math.div(5.5, 100) or calc(5.5 / 100)\n", + "[build:template-css] \n", + "[build:template-css] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:template-css] \n", + "[build:template-css] ╷\n", + "[build:template-css] 105 │ $login-container-bg-color-rgba: rgba($color-pf-white, (5.5/100)) !default;\n", + "[build:template-css] │ ^^^^^^^\n", + "[build:template-css] ╵\n", + "[build:template-css] patternfly/dist/sass/patternfly/_variables.scss 105:92 @import\n", + "[build:template-css] src/styles/template.scss 13:9 root stylesheet\n", + "[build:template-css] \n", + "[build:template-css] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:template-css] \n", + "[build:template-css] Recommendation: math.div($grid-gutter-width, 2) or calc($grid-gutter-width / 2)\n", + "[build:template-css] \n", + "[build:template-css] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:template-css] \n", + "[build:template-css] ╷\n", + "[build:template-css] 368 │ $navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default;\n", + "[build:template-css] │ ^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:template-css] ╵\n", + "[build:template-css] bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 368:43 @import\n", + "[build:template-css] src/styles/template.scss 17:9 root stylesheet\n", + "[build:template-css] \n", + "[build:template-css] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:template-css] \n", + "[build:template-css] Recommendation: math.div($navbar-height - $line-height-computed, 2) or calc(($navbar-height - $line-height-computed) / 2)\n", + "[build:template-css] \n", + "[build:template-css] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:template-css] \n", + "[build:template-css] ╷\n", + "[build:template-css] 369 │ $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default;\n", + "[build:template-css] │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:template-css] ╵\n", + "[build:template-css] bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 369:37 @import\n", + "[build:template-css] src/styles/template.scss 17:9 root stylesheet\n", + "[build:template-css] \n", + "[build:template-css] $ node ./scripts/templateCssPaths.js\n", + "[build:template-css] Update template CSS file paths...Complete\n", + "[build:js ] $ react-scripts build\n", + "[build:js ] Creating an optimized production build...\n", + "[build:js ] Browserslist: caniuse-lite is outdated. Please run:\n", + "[build:js ] npx browserslist@latest --update-db\n", + "[build:js ] Why you should do it regularly: https://github.com/browserslist/browserslist#browsers-data-updating\n", + "[build:js ] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:js ] \n", + "[build:js ] Recommendation: math.div(9 * $applauncher-pf-menu-link-icon-font-size, 14) or calc((9 * $applauncher-pf-menu-link-icon-font-size) / 14)\n", + "[build:js ] \n", + "[build:js ] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:js ] \n", + "[build:js ] ╷\n", + "[build:js ] 30 │ $applauncher-pf-menu-link-icon-width: ((9 * $applauncher-pf-menu-link-icon-font-size) / 14) !default; //Numbers to imitate fa-fw class\n", + "[build:js ] │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:js ] ╵\n", + "[build:js ] node_modules/patternfly/dist/sass/patternfly/_variables.scss 30:70 @import\n", + "[build:js ] src/styles/index.scss 11:9 root stylesheet\n", + "[build:js ] \n", + "[build:js ] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:js ] \n", + "[build:js ] Recommendation: math.div(5.5, 100) or calc(5.5 / 100)\n", + "[build:js ] \n", + "[build:js ] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:js ] \n", + "[build:js ] ╷\n", + "[build:js ] 105 │ $login-container-bg-color-rgba: rgba($color-pf-white, (5.5/100)) !default;\n", + "[build:js ] │ ^^^^^^^\n", + "[build:js ] ╵\n", + "[build:js ] node_modules/patternfly/dist/sass/patternfly/_variables.scss 105:92 @import\n", + "[build:js ] src/styles/index.scss 11:9 root stylesheet\n", + "[build:js ] \n", + "[build:js ] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:js ] \n", + "[build:js ] Recommendation: math.div($grid-gutter-width, 2) or calc($grid-gutter-width / 2)\n", + "[build:js ] \n", + "[build:js ] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:js ] \n", + "[build:js ] ╷\n", + "[build:js ] 368 │ $navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default;\n", + "[build:js ] │ ^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:js ] ╵\n", + "[build:js ] node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 368:43 @import\n", + "[build:js ] src/styles/index.scss 15:9 root stylesheet\n", + "[build:js ] \n", + "[build:js ] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:js ] \n", + "[build:js ] Recommendation: math.div($navbar-height - $line-height-computed, 2) or calc(($navbar-height - $line-height-computed) / 2)\n", + "[build:js ] \n", + "[build:js ] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:js ] \n", + "[build:js ] ╷\n", + "[build:js ] 369 │ $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default;\n", + "[build:js ] │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "[build:js ] ╵\n", + "[build:js ] node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 369:37 @import\n", + "[build:js ] src/styles/index.scss 15:9 root stylesheet\n", + "[build:js ] \n", + "[build:js ] DEPRECATION WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.\n", + "[build:js ] \n", + "[build:js ] Recommendation: math.div($tdWidth, 100) or calc($tdWidth / 100)\n", + "[build:js ] \n", + "[build:js ] More info and automated migrator: https://sass-lang.com/d/slash-div\n", + "[build:js ] \n", + "[build:js ] ╷\n", + "[build:js ] 6 │ width: percentage($tdWidth/100);\n", + "[build:js ] │ ^^^^^^^^^^^^\n", + "[build:js ] ╵\n", + "[build:js ] src/styles/app/_table.scss 6:27 @import\n", + "[build:js ] src/styles/index.scss 31:9 root stylesheet\n", + "[build:js ] \n", + "[build:js ] Compiled successfully.\n", + "[build:js ] \n", + "[build:js ] File sizes after gzip:\n", + "[build:js ] \n", + "[build:js ] 299.36 KB build/static/js/2.d422bd4e.chunk.js\n", + "[build:js ] 93.21 KB build/static/css/2.0ff61478.chunk.css\n", + "[build:js ] 45.31 KB build/static/js/main.3bc333fa.chunk.js\n", + "[build:js ] 5.61 KB build/static/css/47.a457c418.chunk.css\n", + "[build:js ] 4.05 KB build/static/css/24.4aabd037.chunk.css\n", + "[build:js ] 3.75 KB build/static/css/18.de62a81f.chunk.css\n", + "[build:js ] 3.73 KB build/static/css/44.cab4acd4.chunk.css\n", + "[build:js ] 3.59 KB build/static/css/40.c8c8fb7b.chunk.css\n", + "[build:js ] 3.55 KB build/static/css/28.d2badfaa.chunk.css\n", + "[build:js ] 3.45 KB build/static/css/31.f9553609.chunk.css\n", + "[build:js ] 3.42 KB build/static/css/main.1620dd75.chunk.css\n", + "[build:js ] 3.38 KB build/static/css/14.358acc02.chunk.css\n", + "[build:js ] 3.33 KB build/static/css/15.03bb2699.chunk.css\n", + "[build:js ] 3.01 KB build/static/css/33.a3824a05.chunk.css\n", + "[build:js ] 2.93 KB build/static/css/8.cb6978fe.chunk.css\n", + "[build:js ] 2.93 KB build/static/css/37.b28afa48.chunk.css\n", + "[build:js ] 2.68 KB build/static/css/17.e97a51a9.chunk.css\n", + "[build:js ] 2.36 KB build/static/js/runtime-main.93cf2cc2.js\n", + "[build:js ] 2.22 KB build/static/css/46.8802b9ed.chunk.css\n", + "[build:js ] 1.88 KB build/static/css/3.5a177014.chunk.css\n", + "[build:js ] 1.82 KB build/static/css/22.da13c24a.chunk.css\n", + "[build:js ] 1.75 KB build/static/css/25.60fe7761.chunk.css\n", + "[build:js ] 1.65 KB build/static/css/35.4ae74f55.chunk.css\n", + "[build:js ] 1.63 KB build/static/css/4.2767a370.chunk.css\n", + "[build:js ] 1.38 KB build/static/css/26.55146ab5.chunk.css\n", + "[build:js ] 1.38 KB build/static/css/42.1daee3f2.chunk.css\n", + "[build:js ] 1.34 KB build/static/css/21.1292209e.chunk.css\n", + "[build:js ] 1.33 KB build/static/css/12.c4f3ec61.chunk.css\n", + "[build:js ] 1.17 KB build/static/css/29.731ed37a.chunk.css\n", + "[build:js ] 1.17 KB build/static/css/43.591843cd.chunk.css\n", + "[build:js ] 1.16 KB build/static/css/39.7136c113.chunk.css\n", + "[build:js ] 1.15 KB build/static/css/13.b92f339a.chunk.css\n", + "[build:js ] 892 B build/static/css/10.fbe53728.chunk.css\n", + "[build:js ] 855 B build/static/css/16.4d8b4e59.chunk.css\n", + "[build:js ] 843 B build/static/css/32.ec811526.chunk.css\n", + "[build:js ] 842 B build/static/css/49.aed328b4.chunk.css\n", + "[build:js ] 781 B build/static/css/19.ebd9fac7.chunk.css\n", + "[build:js ] 649 B build/static/css/11.00d836be.chunk.css\n", + "[build:js ] 612 B build/static/css/41.02132579.chunk.css\n", + "[build:js ] 599 B build/static/css/20.43bc7b14.chunk.css\n", + "[build:js ] 587 B build/static/css/27.dd2ca198.chunk.css\n", + "[build:js ] 558 B build/static/css/45.016a44b7.chunk.css\n", + "[build:js ] 553 B build/static/css/5.16b79253.chunk.css\n", + "[build:js ] 530 B build/static/css/38.14902daf.chunk.css\n", + "[build:js ] 529 B build/static/css/9.18a35fb2.chunk.css\n", + "[build:js ] 436 B build/static/css/7.a6816828.chunk.css\n", + "[build:js ] 412 B build/static/css/30.e818b263.chunk.css\n", + "[build:js ] 412 B build/static/css/48.72ebc63a.chunk.css\n", + "[build:js ] 395 B build/static/css/23.42d35cc6.chunk.css\n", + "[build:js ] 377 B build/static/css/36.6dfe5c09.chunk.css\n", + "[build:js ] 244 B build/static/css/6.5bfb48a1.chunk.css\n", + "[build:js ] 173 B build/static/css/34.80de7923.chunk.css\n", + "[build:js ] 146 B build/static/js/10.f411f275.chunk.js\n", + "[build:js ] 146 B build/static/js/11.4e6c8854.chunk.js\n", + "[build:js ] 146 B build/static/js/12.f9870f5f.chunk.js\n", + "[build:js ] 146 B build/static/js/13.d3b36598.chunk.js\n", + "[build:js ] 146 B build/static/js/14.f3e5f0c0.chunk.js\n", + "[build:js ] 146 B build/static/js/16.69728091.chunk.js\n", + "[build:js ] 146 B build/static/js/17.d442b349.chunk.js\n", + "[build:js ] 146 B build/static/js/20.3d36a25d.chunk.js\n", + "[build:js ] 146 B build/static/js/21.c8f370b9.chunk.js\n", + "[build:js ] 146 B build/static/js/22.65d6fb2c.chunk.js\n", + "[build:js ] 146 B build/static/js/23.1a97b3f3.chunk.js\n", + "[build:js ] 146 B build/static/js/24.88387069.chunk.js\n", + "[build:js ] 146 B build/static/js/25.80a2df61.chunk.js\n", + "[build:js ] 146 B build/static/js/26.74ef91bb.chunk.js\n", + "[build:js ] 146 B build/static/js/27.3cefad52.chunk.js\n", + "[build:js ] 146 B build/static/js/28.48479a5a.chunk.js\n", + "[build:js ] 146 B build/static/js/29.d6259be0.chunk.js\n", + "[build:js ] 146 B build/static/js/30.fd56c76e.chunk.js\n", + "[build:js ] 146 B build/static/js/31.617c9e21.chunk.js\n", + "[build:js ] 146 B build/static/js/32.0d796257.chunk.js\n", + "[build:js ] 146 B build/static/js/33.3b6b24db.chunk.js\n", + "[build:js ] 146 B build/static/js/34.28fd73e6.chunk.js\n", + "[build:js ] 146 B build/static/js/35.755f6531.chunk.js\n", + "[build:js ] 146 B build/static/js/36.dd8b3ab7.chunk.js\n", + "[build:js ] 146 B build/static/js/37.c5358f46.chunk.js\n", + "[build:js ] 146 B build/static/js/38.1fcd9548.chunk.js\n", + "[build:js ] 146 B build/static/js/39.eb709435.chunk.js\n", + "[build:js ] 146 B build/static/js/40.e293316a.chunk.js\n", + "[build:js ] 146 B build/static/js/41.53f5da7f.chunk.js\n", + "[build:js ] 146 B build/static/js/42.81e76e31.chunk.js\n", + "[build:js ] 146 B build/static/js/43.402680a9.chunk.js\n", + "[build:js ] 146 B build/static/js/44.cb25fdce.chunk.js\n", + "[build:js ] 146 B build/static/js/45.0f3213c3.chunk.js\n", + "[build:js ] 146 B build/static/js/47.d9202e8c.chunk.js\n", + "[build:js ] 146 B build/static/js/48.60461c62.chunk.js\n", + "[build:js ] 146 B build/static/js/49.8a0f6e42.chunk.js\n", + "[build:js ] 145 B build/static/js/15.e7857ae6.chunk.js\n", + "[build:js ] 145 B build/static/js/18.b890f99c.chunk.js\n", + "[build:js ] 145 B build/static/js/19.f8fe388f.chunk.js\n", + "[build:js ] 145 B build/static/js/46.c9c397f7.chunk.js\n", + "[build:js ] 144 B build/static/js/3.bfc919cf.chunk.js\n", + "[build:js ] 144 B build/static/js/4.e7dcf275.chunk.js\n", + "[build:js ] 144 B build/static/js/5.c0031344.chunk.js\n", + "[build:js ] 144 B build/static/js/6.c72bac37.chunk.js\n", + "[build:js ] 144 B build/static/js/7.080b9b2a.chunk.js\n", + "[build:js ] 144 B build/static/js/8.12719b3e.chunk.js\n", + "[build:js ] 144 B build/static/js/9.857290a7.chunk.js\n", + "[build:js ] \n", + "[build:js ] The project was built assuming it is hosted at /.\n", + "[build:js ] You can control this with the homepage field in your package.json.\n", + "[build:js ] \n", + "[build:js ] The build folder is ready to be deployed.\n", + "[build:js ] You may serve it with a static server:\n", + "[build:js ] \n", + "[build:js ] yarn global add serve\n", + "[build:js ] serve -s build\n", + "[build:js ] \n", + "[build:js ] Find out more about deployment here:\n", + "[build:js ] \n", + "[build:js ] https://cra.link/deployment\n", + "[build:js ] \n", + "[build:post ] $ bash ./scripts/post.sh; bash ./scripts/clean.sh\n", + "[build:post ] Compiling distribution resources...Completed\n", + "[build:post ] Updating graphics... UI_BRAND_LABEL=-brand...Completed\n", + "[build:post ] Updating templates display name... UI_NAME=product discovery...Completed\n", + "[build:post ] Cleaning locale resources...Completed\n", + "[build:post ] Cleaning document resources...Completed\n", + "[test:integration ] $ jest --roots=./tests\n", + "[test:integration ] PASS tests/templates.test.js\n", + "[test:integration ] PASS tests/code.test.js\n", + "[test:integration ] PASS tests/version.test.js\n", + "[test:integration ] PASS tests/brand.test.js\n", + "[test:integration ] PASS tests/dist.test.js\n", + "[test:integration ] \n", + "[test:integration ] Test Suites: 5 passed, 5 total\n", + "[test:integration ] Tests: 8 passed, 8 total\n", + "[test:integration ] Snapshots: 10 passed, 10 total\n", + "[test:integration ] Time: 3.568 s\n", + "[test:integration ] Ran all test suites.\n", + "Done in 170.73s.\n", + "COMMIT quipucords-ui\n", + "--> d9a93449ea77\n", + "Successfully tagged localhost/quipucords-ui:latest\n", + "d9a93449ea77e85090322137076ed24809265b0c404771cdd5e98cdeead90bc8\n" + ] + } + ], + "source": [ + "!podman build --tag quipucords-ui -f Containerfile.quipucords-ui ." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build the application image" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting Containerfile\n" + ] + } + ], + "source": [ + "%%writefile Containerfile\n", + "\n", + "# FROM quipucords-ui:latest as yarn_builder\n", + "\n", + "FROM quipucords-base-image:latest\n", + "\n", + "# setup python virtualenv\n", + "RUN python3 -m venv /opt/venv\n", + "ENV PATH=\"/opt/venv/bin:${PATH}\"\n", + "\n", + "WORKDIR /app\n", + "# copy cargo config (this should become part of cargo inject IF crates are available \n", + "# from local files - only problem is this file needs to be at an specific location)\n", + "# NOTICE the config is placed on root directory - this was required to successfully\n", + "# build indirect rust dependencies (cryptography and bcrypt). Looks like pip is running\n", + "# not running the build under /app\n", + "COPY cargo_config.toml /.cargo/config.toml\n", + "COPY quipucords/requirements.txt .\n", + "\n", + "\n", + "RUN source /tmp/cachi2.env && \\\n", + " pip install -U pip 'setuptools<67' wheel &&\\\n", + " # build/install kombu first, as it requires an older setuptools and dont follow PEP-517\n", + " pip install kombu &&\\\n", + " pip install -U setuptools &&\\\n", + " pip install -r requirements.txt\n", + "\n", + "# copy quipucords source\n", + "COPY quipucords /app\n", + "# copy UI code\n", + "COPY --from=quipucords-ui:latest /app/dist/client quipucords/client\n", + "COPY --from=quipucords-ui:latest /app/dist/templates quipucords/quipucords/templates\n", + "\n", + "ENV DJANGO_DEBUG=False\n", + "ENV LANG=C\n", + "ENV LC_ALL=C\n", + "ENV PRODUCTION=True\n", + "ENV PYTHONPATH=/app/quipucords\n", + "\n", + "RUN make server-static\n", + "\n", + "EXPOSE 443\n", + "COPY quipucords/deploy /deploy\n", + "COPY quipucords/deploy/ssl/ /etc/ssl/qpc/\n", + "\n", + "CMD [\"/bin/bash\", \"/deploy/docker_run.sh\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "STEP 1/20: FROM quipucords-base-image:latest\n", + "STEP 2/20: RUN python3 -m venv /opt/venv\n", + "--> Using cache d9185e6f5c2fdfd47fe6c943907b170ce6b3b03ace40d93e43a64b1e3b67e728\n", + "--> d9185e6f5c2f\n", + "STEP 3/20: ENV PATH=\"/opt/venv/bin:${PATH}\"\n", + "--> Using cache d67fe7085a7c7ece58f8601fe1eed6107fdc2d5b0cc6c1399aaf88696b4dc267\n", + "--> d67fe7085a7c\n", + "STEP 4/20: WORKDIR /app\n", + "--> Using cache 021917a443648249d499c6fac3f0fd3d3829a519026694e921dc1c12f8ce0289\n", + "--> 021917a44364\n", + "STEP 5/20: COPY cargo_config.toml /.cargo/config.toml\n", + "--> Using cache 00d1a1cd976da0dfecdbe8202ed4fe6f3ebd5ec259cc048701b41f95db2ab56d\n", + "--> 00d1a1cd976d\n", + "STEP 6/20: COPY quipucords/requirements.txt .\n", + "--> Using cache 08e1ba082e883e1f3599048312811dcba882c35b8dc52e30259ec4497a274363\n", + "--> 08e1ba082e88\n", + "STEP 7/20: RUN source /tmp/cachi2.env && pip install -U pip 'setuptools<67' wheel && pip install kombu && pip install -U setuptools && pip install -r requirements.txt\n", + "--> Using cache ffcac5df9f0544f7a22db8b6608358aba746c42df6c43840fc1ad6936f5ca961\n", + "--> ffcac5df9f05\n", + "STEP 8/20: COPY quipucords /app\n", + "--> 705b3a54c775\n", + "STEP 9/20: COPY --from=quipucords-ui:latest /app/dist/client quipucords/client\n", + "--> cabc944bdc64\n", + "STEP 10/20: COPY --from=quipucords-ui:latest /app/dist/templates quipucords/quipucords/templates\n", + "--> b11b8312f07b\n", + "STEP 11/20: ENV DJANGO_DEBUG=False\n", + "--> 1e28770741b9\n", + "STEP 12/20: ENV LANG=C\n", + "--> 14407a35ec5f\n", + "STEP 13/20: ENV LC_ALL=C\n", + "--> 4c43ffafe40f\n", + "STEP 14/20: ENV PRODUCTION=True\n", + "--> 9b74746bd100\n", + "STEP 15/20: ENV PYTHONPATH=/app/quipucords\n", + "--> be0290ff0cc4\n", + "STEP 16/20: RUN make server-static\n", + "/opt/venv/bin/python quipucords/manage.py collectstatic --settings quipucords.settings --no-input\n", + "\n", + "1054 static files copied to '/app/quipucords/staticfiles', 2742 post-processed.\n", + "--> 3aee033bcb0e\n", + "STEP 17/20: EXPOSE 443\n", + "--> c2538a10644d\n", + "STEP 18/20: COPY quipucords/deploy /deploy\n", + "--> c79136653ce3\n", + "STEP 19/20: COPY quipucords/deploy/ssl/ /etc/ssl/qpc/\n", + "--> 42b3fd01d57a\n", + "STEP 20/20: CMD [\"/bin/bash\", \"/deploy/docker_run.sh\"]\n", + "COMMIT quipucords-no-network\n", + "--> c4dd60b563b8\n", + "Successfully tagged localhost/quipucords-no-network:latest\n", + "c4dd60b563b8d962aeea571c06c441153b40d82de51ed77ac71e224c378728dd\n" + ] + } + ], + "source": [ + "!podman build . \\\n", + " --volume \"$(realpath ./cachi2-output)\":/tmp/cachi2-output:Z \\\n", + " --volume \"$(realpath ./cachi2.env)\":/tmp/cachi2.env:Z \\\n", + " --network none \\\n", + " --tag quipucords-no-network" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "f7f73f2a4ba5b45eaa4349971c646b7363bbca677601a55a3a10c56650fa511f" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}