{"id":15686501,"url":"https://github.com/thenets/package-constructor","last_synced_at":"2025-11-08T17:30:37.665Z","repository":{"id":184897264,"uuid":"653404111","full_name":"thenets/package-constructor","owner":"thenets","description":"All you need to build packages and applications in an air-gapped environment.","archived":false,"fork":false,"pushed_at":"2023-12-01T20:37:31.000Z","size":90,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-14T21:46:56.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thenets.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-14T01:55:32.000Z","updated_at":"2023-11-07T01:25:19.000Z","dependencies_parsed_at":"2023-11-07T04:49:09.220Z","dependency_job_id":"dd4375bc-b05e-49ba-97af-a78be4eaf8dc","html_url":"https://github.com/thenets/package-constructor","commit_stats":null,"previous_names":["thenets/cachito-cli"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenets%2Fpackage-constructor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenets%2Fpackage-constructor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenets%2Fpackage-constructor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenets%2Fpackage-constructor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thenets","download_url":"https://codeload.github.com/thenets/package-constructor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239558934,"owners_count":19658934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T17:40:27.703Z","updated_at":"2025-11-08T17:30:37.632Z","avatar_url":"https://github.com/thenets.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Package Constructor\n\nAll you need to build packages and applications in an air-gapped environment. The power of `cachito` and `podman` combined.\n\n## Why was this project created?\n\n- My pain: it takes too long to iterate in an air-gapped Jenkins or any other pipeline. The flow of committing to a git repo and triggering a job in a CI tool it's not a productive solution.\n\n- My problem: I need a faster way to iterate and build a container, a portion with internet access and a portion without internet access. I also need to extract all Python dependencies downloaded, including the hidden ones, like `build`, `hatch`, `hacther`, etc.\n\n- The goal of this project: build a container image with a section with internet and another without internet + using Cachito proxies. It also extracts all Python dependencies that passed\nthrough the Cachito proxy (Nexus pip proxy repo).\n\n- Result: this way, I can iterate fast and retrieve dependencies that `pip freeze` don't return.\n\n## Features\n\nMain features:\n- Build system configurable via a single YAML file\n\nModules:\n- Server: Install the Cachito server with all the components\n- Builder: Build packages and applications in an air-gapped environment\n- Nexus: Check repositories and packages\n\nAdditional features:\n- Python: Extract the `requirements.txt` from the Containerfile build using a proxy repository\n\nPending features/tasks:\n- [ ] Automatically extract Python depenedencies based on the configuration file\n- [ ] Create new proxy pip repos per build instead of restart cachito and cleanup the cache\n- [ ] Each `Dockerfile` should be built with their own context. So, for all files from it's location must be copied to the workdir\n\n\n## How to use\n\nAdd the `./bin/` to your `$PATH` var:\n\n```bash\nexport $PATH=$(pwd)/bin/:${PATH}\n```\n\nStart all Cachito servers:\n\n```bash\nconstructor\n```\n\nCreate the `./Containerfile`. In order to use the internal Cachito servers you must load `constructor/proxy/\u003cimageName\u003e/proxy.sh` to your context:\n\n```dockerfile\n# ./Containerfile\nFROM my.local/base-image\n\nADD constructor /constructor\n\nENV PIP_NO_BINARY=:all:\n\nRUN set -x \\\n    \u0026\u0026 source constructor/proxy/main/proxy.sh \\\n    \u0026\u0026 python3 -m venv /venv \\\n    \u0026\u0026 /venv/bin/pip3 install -r /constructor/packagemanager/python/requirements-freeze.txt\n\nRUN pip list -l \u003e /hello.txt\n\nCMD [\"cat\", \"/hello.txt\"]\n```\n\nCreate the main configuration file:\n\n```yaml\n# Simplest scenario for the Package Constructor build system\n# - Container build\n\n---\n\n# Defines the container build\nkind: container\n\n# Defines the working directory where the constructor will be executed\n# and will store all the generated files\nworkdir:\n  # Path to the working directory relative to the configuration file\n  path: ./cache/\n\n# Each source will be cloned into a volume\n# and then added to the container build\nsources:\n  - kind: git\n    url: https://github.com/pyca/cryptography.git\n    ref: \"41.0.5\"\n    path: cryptography\n\n# Each package manager will have a respective proxy service available\n# for the container build\npackageManagers:\n  # Ansible roles and collections\n  # creates the files:\n  #   $WORKDIR/constructor/packagemanager/ansible/requirements.yml\n  #   $WORKDIR/constructor/packagemanager/ansible/requirements-freeze.txt\n  ansible:\n    # Collections. Must include the package name and version\n    collections:\n      - community-general==6.2.0\n    # Roles. Must include the package name and version\n    roles:\n      - cloudalchemy.node_exporter==2.0.0\n\n  # Python package manager\n  # creates the file $WORKDIR/constructor/packagemanager/python/requirements-freeze.txt\n  python:\n    pythonVersion: \"^3.9\"\n    # If true, it will search for all the dependencies to build the package\n    includeDependencies: true\n    # Dependencies. Must include the package name and version\n    dependencies:\n      - cryptography==41.0.5\n\n# Assuming \"kind: containers\", the container key is required\n# Each container will be built sequentially. You can chain them.\ncontainers:\n  # Base image\n  # ===================\n  - name: \"base\"\n    imageName: \"my.local/base-image\"\n    containerfileContent: |\n      FROM docker.io/redhat/ubi9:latest\n      RUN set x \\\n          \u0026\u0026 dnf install -y \\\n              # utils\n              tar vim bash findutils dnf \\\n              # rust\n              cargo \\\n              # gcc\n              gcc gcc-c++ cmake cmake-data \\\n              # cryptography\n              libffi-devel openssl-devel redhat-rpm-config pkg-config \\\n              # python\n              python3-devel \\\n              python3-pip-wheel \\\n              python3-setuptools \\\n              python3-setuptools-wheel \\\n              python3-wheel-wheel \\\n              python3-six\n    restrictions:\n      disableDnsResolution: false\n    proxies:\n      python: false\n      golang: false\n    sources_subpath: sources\n    podmanCacheEnabled: true\n\n\n  # Main image\n  # ===================\n  - # Build name (required, must be unique, [a-z, 0-9, -])\n    name: \"main\"\n\n    # Podman image name (required)\n    imageName: \"package-constructor-scenario-simple\"\n\n    # Main Containerfile (required)\n    # This is where the main logic of the container build is defined\n    containerfilePath: ./scenario-simple.containerfile\n\n    # All restrictions applied during the build time\n    # if a build can be performed in a container with these restrictions\n    # it probably means that all the dependencies can be compiled in an\n    # air-gapped environment.\n    restrictions:\n      disableDnsResolution: true\n\n    # All proxies applied during the build time\n    # in order to enable them, you must source the proxy file\n    # example:\n    #   COPY constructor/proxy.sh /tmp/proxy.sh\n    #   RUN source /tmp/proxy.sh \u0026\u0026 pip install requests\n    proxies:\n      python: true\n      golang: true\n\n    # Sources subpath (default: sources)\n    # Available in the container build context\n    # Example: COPY sources /tmp/sources\n    sources_subpath: sources\n\n    # Cache enabled (default: true)\n    podmanCacheEnabled: false\n```\n\n## FAQ\n\n- Is this solution too focused on Python packaging?\n  Yes. There are probably design issues in how I architected the `cli_builder.py` module.\n\n- How do you deal with third-party bindings like `C`, `C++` or `Rust`?\n  I don't. All binding dependencies must come from the distro's package manager. For `Rust` specifically, none is supported since `cachito` don't yet support it, so you must vendor their lib, read more here at [cargo-vendor](https://doc.rust-lang.org/cargo/commands/cargo-vendor.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenets%2Fpackage-constructor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthenets%2Fpackage-constructor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenets%2Fpackage-constructor/lists"}