diff --git a/.github/actions/run-packaging-tests/action.yml b/.github/actions/run-packaging-tests/action.yml deleted file mode 100644 index 81711582..00000000 --- a/.github/actions/run-packaging-tests/action.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: 'Run Packaging Tests' -description: 'Runs the packaging tests' - -inputs: - distro: - description: 'Distribution to test (bookworm, jammy, noble)' - required: true - language: - description: 'Language to test' - required: true - run_piuparts: - description: 'Whether to run piuparts' - required: false - default: 'false' - run_autopkgtest: - description: 'Whether to run autopkgtest' - required: false - default: 'false' - -runs: - using: "composite" - steps: - - name: Package - shell: bash - run: | - cd examples/${{ inputs.distro }}/${{ inputs.language }}/hello-world - pkg-builder package --run-piuparts ${{ inputs.run_piuparts }} --run-autopkgtest ${{ inputs.run_autopkgtest }} - - - name: piuparts - if: ${{ inputs.run_piuparts == 'true' }} - shell: bash - run: | - # installing debian-archive-keyring fails on ubuntu LTS, not sure why, but it says it is already installed - # sudo apt-get install -y debian-archive-keyring - cd examples/${{ inputs.distro }}/${{ inputs.language }}/hello-world - ${HOME}/.local/bin/pkg-builder piuparts - - # TODO version parsing fails, as it doesn't use semver - - name: autopkgtest - if: ${{ inputs.run_autopkgtest == 'true' }} - shell: bash - run: | - sudo cp -R ${HOME}/.pkg-builder /root - apt list --installed autopkgtest - cd examples/${{ inputs.distro }}/${{ inputs.language }}/hello-world - sudo ${HOME}/.local/bin/pkg-builder autopkgtest - - - name: Verify - shell: bash - run: | - cd examples/${{ inputs.distro }}/${{ inputs.language }}/hello-world - ${HOME}/.local/bin/pkg-builder verify --no-package true \ No newline at end of file diff --git a/.github/actions/setup-packaging-env/action.yml b/.github/actions/setup-packaging-env/action.yml deleted file mode 100644 index 46abbae4..00000000 --- a/.github/actions/setup-packaging-env/action.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: 'Setup Packaging Environment' -description: 'Sets up environment for packaging tests' - -inputs: - include_genisoimage: - description: 'Whether to include genisoimage' - required: false - default: 'false' - -runs: - using: "composite" - steps: - - name: Setup sbuild - uses: ./.github/actions/setup-sbuild - - - name: Additional dependencies - shell: bash - run: | - sudo apt install -y autopkgtest vmdb2 qemu-system-x86 - if [ "${{ inputs.include_genisoimage }}" = "true" ]; then - sudo apt-get install -y genisoimage - fi - - - name: Build pkg-builder - shell: bash - run: | - cargo build --verbose - cargo build --release - - - name: Install pkg-builder - shell: bash - run: | - mkdir -p ${HOME}/.local/bin - mv target/release/pkg-builder ${HOME}/.local/bin - # add to path the prebuilt debcrafter binaries as well - cp workspace/pkg_builder/bin_dependencies/debcrafter_* ${HOME}/.local/bin - chmod +x ${HOME}/.local/bin/debcrafter_* - chmod +x ${HOME}/.local/bin/pkg-builder - echo "${HOME}/.local/bin" >> $GITHUB_PATH \ No newline at end of file diff --git a/.github/actions/setup-sbuild/action.yml b/.github/actions/setup-sbuild/action.yml index 95167cb0..fa39c736 100644 --- a/.github/actions/setup-sbuild/action.yml +++ b/.github/actions/setup-sbuild/action.yml @@ -1,18 +1,17 @@ name: 'Setup sbuild' -description: 'Sets up sbuild environment' +description: 'Installs sbuild and its dependencies' runs: using: "composite" steps: - - name: Sbuild setup + - name: Install sbuild and dependencies shell: bash run: | sudo apt-get update - # Note this is an older version of sbuild, no need to patch it, yet - sudo apt install -y debhelper schroot ubuntu-dev-tools - sudo apt-get -y install pkg-config libssl-dev uidmap - sudo apt-get install -y libfilesys-df-perl libmime-lite-perl - wget https://github.com/eth-pkg/sbuild-ubuntu/releases/download/0.85-6-1/sbuild_0.85.6_all.deb - wget https://github.com/eth-pkg/sbuild-ubuntu/releases/download/0.85-6-1/libsbuild-perl_0.85.6_all.deb + sudo apt-get install -y debhelper schroot ubuntu-dev-tools \ + pkg-config libssl-dev uidmap \ + libfilesys-df-perl libmime-lite-perl + wget -q https://github.com/eth-pkg/sbuild-ubuntu/releases/download/0.85-6-1/sbuild_0.85.6_all.deb + wget -q https://github.com/eth-pkg/sbuild-ubuntu/releases/download/0.85-6-1/libsbuild-perl_0.85.6_all.deb sudo dpkg -i sbuild_0.85.6_all.deb libsbuild-perl_0.85.6_all.deb || true - sudo sbuild-adduser `whoami` \ No newline at end of file + sudo sbuild-adduser $(whoami) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..e90019ec --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,48 @@ +name: Deploy docs + +on: + push: + branches: + - main + paths: + - "docs/**" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Install mdBook + uses: peaceiris/actions-mdbook@v2 + with: + mdbook-version: "0.4.43" + + - name: Build docs + run: mdbook build docs + + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: docs/book + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml new file mode 100644 index 00000000..a7189691 --- /dev/null +++ b/.github/workflows/release-plz.yml @@ -0,0 +1,61 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - main + +jobs: + release-plz: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Run release-plz + id: release-plz + uses: release-plz/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update example versions on release PR + if: steps.release-plz.outputs.prs_created == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_PLZ_PR: ${{ steps.release-plz.outputs.pr }} + run: | + # Parse the PR branch from the output + PR_JSON="${RELEASE_PLZ_PR}" + PR_BRANCH=$(echo "$PR_JSON" | jq -r '.head_branch') + + if [ -z "$PR_BRANCH" ] || [ "$PR_BRANCH" = "null" ]; then + echo "Could not determine PR branch, skipping example version bump" + exit 0 + fi + + git fetch origin "$PR_BRANCH" + git checkout "$PR_BRANCH" + + # Read the new CLI version from the bumped Cargo.toml + VERSION=$(grep '^version' crates/cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') + echo "Bumping example versions to $VERSION" + + bash scripts/bump-example-versions.sh "$VERSION" + + # Commit and push if there are changes + if ! git diff --quiet examples/; then + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add examples/ + git commit -m "chore: bump pkg_builder version to $VERSION in examples" + git push origin "$PR_BRANCH" + fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1505e059..bf4d054e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: Tests +name: CI on: push: @@ -8,146 +8,96 @@ on: branches: - main schedule: - - cron: '0 0 * * 0' + - cron: '0 0 * * 0' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + env: CARGO_TERM_COLOR: always jobs: - unit_tests: + unit-tests: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup sbuild uses: ./.github/actions/setup-sbuild - name: Build - run: cargo build --verbose - - - name: Run unit tests - run: cargo test --lib --verbose -- --ignored - - bookworm_amd64_packaging: - runs-on: ubuntu-24.04 - strategy: - matrix: - language: - - c - - dotnet - - go - - java - - java-gradle - - javascript - - nim - - rust - - typescript - - virtual - #- python - max-parallel: 3 - fail-fast: false - steps: - - uses: actions/checkout@v4 - - - name: Setup environment - uses: ./.github/actions/setup-packaging-env - - - name: Create chroot env - run: | - cd examples/bookworm/${{matrix.language}}/hello-world - pkg-builder env create - echo "${HOME}/.cache/sbuild/bookworm-amd64.tar.gz" >> $GITHUB_PATH - - - name: Run packaging tests - uses: ./.github/actions/run-packaging-tests - with: - distro: bookworm - language: ${{matrix.language}} - run_piuparts: false - run_autopkgtest: true + run: cargo build --locked - jammy_amd64_packaging: - runs-on: ubuntu-24.04 - strategy: - matrix: - language: - - c - - dotnet - - go - - java - - java-gradle - - javascript - - nim - - rust - - typescript - - virtual - max-parallel: 3 - fail-fast: false - steps: - - uses: actions/checkout@v4 - - - name: Setup environment - uses: ./.github/actions/setup-packaging-env + - name: Run tests + run: cargo test --locked - - name: Create chroot env - run: | - cd examples/jammy/${{matrix.language}}/hello-world - pkg-builder env create - echo "${HOME}/.cache/sbuild/noble-amd64.tar.gz" >> $GITHUB_PATH - - - name: Run packaging tests - uses: ./.github/actions/run-packaging-tests - with: - distro: jammy - language: ${{matrix.language}} - run_piuparts: false - run_autopkgtest: true - - noble_amd64_packaging: + package: runs-on: ubuntu-24.04 + needs: unit-tests strategy: matrix: - language: - - c - - dotnet - - dotnet-9 - - go - - java - - java-gradle - - javascript - - nim - - rust - - typescript - - virtual - #- python - max-parallel: 3 + include: + # Bookworm + - { distro: bookworm, language: c } + - { distro: bookworm, language: go } + - { distro: bookworm, language: java } + - { distro: bookworm, language: java-gradle } + - { distro: bookworm, language: javascript } + - { distro: bookworm, language: nim } + - { distro: bookworm, language: rust } + - { distro: bookworm, language: typescript } + - { distro: bookworm, language: virtual } + # Trixie + - { distro: trixie, language: c } + - { distro: trixie, language: go } + - { distro: trixie, language: java } + - { distro: trixie, language: java-gradle } + - { distro: trixie, language: javascript } + - { distro: trixie, language: nim } + - { distro: trixie, language: rust } + - { distro: trixie, language: typescript } + - { distro: trixie, language: virtual } + # Noble + - { distro: noble, language: c } + - { distro: noble, language: go } + - { distro: noble, language: java } + - { distro: noble, language: java-gradle } + - { distro: noble, language: javascript } + - { distro: noble, language: nim } + - { distro: noble, language: rust } + - { distro: noble, language: typescript } + - { distro: noble, language: virtual } + max-parallel: 6 fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - name: Setup environment - uses: ./.github/actions/setup-packaging-env - with: - include_genisoimage: true + - name: Setup sbuild + uses: ./.github/actions/setup-sbuild - - name: Additional noble setup + - name: Noble-specific setup + if: matrix.distro == 'noble' run: | - sudo sbuild-adduser `whoami` + sudo apt-get install -y genisoimage sudo sysctl -w kernel.unprivileged_userns_clone=1 - #sudo ln -s /usr/share/debootstrap/scripts/gutsy /usr/share/debootstrap/scripts/noble - #sudo cat /etc/subuid - - name: Create chroot env + - name: Build and install pkg-builder run: | - cd examples/noble/${{matrix.language}}/hello-world - pkg-builder env create - echo "${HOME}/.cache/sbuild/noble-amd64.tar.gz" >> $GITHUB_PATH - - - name: Run packaging tests - uses: ./.github/actions/run-packaging-tests - with: - distro: noble - language: ${{matrix.language}} - run_piuparts: false - run_autopkgtest: true + cargo build --release --locked + mkdir -p ${HOME}/.local/bin + cp target/release/pkg-builder ${HOME}/.local/bin/ + echo "${HOME}/.local/bin" >> $GITHUB_PATH + + - name: Create chroot + working-directory: examples/${{ matrix.distro }}/${{ matrix.language }}/hello-world + run: pkg-builder env create + + - name: Build package + working-directory: examples/${{ matrix.distro }}/${{ matrix.language }}/hello-world + run: pkg-builder build + + - name: Verify hashes + working-directory: examples/${{ matrix.distro }}/${{ matrix.language }}/hello-world + run: pkg-builder verify diff --git a/.gitignore b/.gitignore index 8939eec0..0f605052 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ .idea workspace/pkg_builder/bin_dependencies workspace/**/target/** -bin_dependencies/* \ No newline at end of file +bin_dependencies/* +.claude/ +.codex/ +docs/book/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..a216b022 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,134 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.3.1] - 2025-05-09 + +### Added + +- Recipe-based build system replacing the sbuild packager +- Pipeline-based build architecture +- Version check for tool compatibility +- Image download retry logic +- License and documentation updates + +### Changed + +- Simplified CLI parsing and entry point +- Removed sbuild packager in favor of new pipeline +- Moved Debian-specific configs into deb package +- Reorganized crate structure with workspace versioning +- Replaced eyre with thiserror for error handling +- Rewrote debcrafter integration + +### Fixed + +- Submodule checkout for recursive submodules +- Autopkgtest version handling and image creation +- Piuparts and autopkgtest execution +- Java Gradle version resolution +- Normalize versions to always use semver + +## [0.2.11] - 2025-02-17 + +### Fixed + +- Dotnet backup packages no longer require unnecessary dependencies +- Made deps optional for dotnet packages + +## [0.2.10] - 2025-02-17 + +### Fixed + +- Problem with using ubuntu-latest and piuparts missing +- Allow older packages to be installed + +## [0.2.9] - 2025-01-07 + +### Fixed + +- npm update message no longer shows in output +- Autopkgtest reliability improvements +- Failing Java download URL +- Updated backported dotnet packages + +## [0.2.8] - 2024-09-09 + +### Added + +- Multiple debcrafter version support + +### Changed + +- Updated debcrafter to latest version + +## [0.2.7] - 2024-07-22 + +### Added + +- Initial Python runtime support + +## [0.2.6] - 2024-07-09 + +### Fixed + +- Removed curl dependency + +## [0.2.5] - 2024-06-06 + +### Added + +- Autopkgtest support for Ubuntu 24.04 (Noble) + +## [0.2.4] - 2024-05-29 + +### Fixed + +- Dotnet builds and backup hash/URL handling +- Noble dependencies for dotnet packages +- Microsoft dropped Ubuntu 24.04 support, added workaround + +## [0.2.3] - 2024-05-14 + +### Fixed + +- Autopkgtest on Ubuntu +- Updated Noble package example hashes + +## [0.2.2] - 2024-05-10 + +### Added + +- Ubuntu Noble (24.04) support +- Ubuntu Jammy (22.04) support +- Git source package support +- Reproducible build verification +- Lintian, piuparts, and autopkgtest integration +- Test beds for all supported languages +- Dotnet build support under sbuild +- Java Gradle example + +### Changed + +- Improved CLI usage arguments +- Improved error reporting +- Fail build if lintian, piuparts, or autopkgtest fails + +### Fixed + +- Reproducible builds for Go, Nim, Rust, JavaScript, TypeScript, and virtual packages +- Lintian errors across distributions + +## [0.1.0] - 2024-04-16 + +### Added + +- Initial release +- Debian package building with sbuild +- Support for C, Go, Java, JavaScript, Nim, Rust, TypeScript, and virtual packages +- Declarative TOML-based package configuration +- Bookworm (Debian 12) support +- Integration tests and CI pipeline diff --git a/Cargo.lock b/Cargo.lock index cb1cdb27..896ceb1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -26,6 +26,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.18" @@ -76,207 +85,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "assert-json-diff" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 0.38.44", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.4.0", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-object-pool" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333c456b97c3f2d50604e8b2624253b7f787208cb72eb75e64b0ad11b221652c" -dependencies = [ - "async-std", -] - -[[package]] -name = "async-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" -dependencies = [ - "async-channel 2.3.1", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.4.0", - "futures-lite", - "rustix 0.38.44", - "tracing", -] - -[[package]] -name = "async-signal" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.44", - "signal-hook-registry", - "slab", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-std" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" -dependencies = [ - "async-attributes", - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -285,15 +93,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -301,40 +109,14 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "basic-cookies" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bd8fd42c16bdb08688243dc5f0cc117a3ca9efeeaba3a345a18a6159ad96f7" -dependencies = [ - "lalrpop", - "lalrpop-util", - "regex", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -344,76 +126,54 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "block-buffer" -version = "0.11.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "blocking" -version = "1.6.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite", - "piper", + "generic-array", ] [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] -name = "camino" -version = "1.1.9" +name = "cc" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ - "serde", + "find-msvc-tools", + "shlex", ] [[package]] -name = "cargo-platform" -version = "0.1.9" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cargo_metadata" -version = "0.18.1" +name = "chrono" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", ] -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "clap" version = "4.5.32" @@ -445,7 +205,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -455,20 +215,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] -name = "cli" -version = "0.3.1" +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ - "cargo_metadata", - "clap", - "env_logger", - "log", - "packager_deb", - "regex", - "serde", - "tempfile", - "thiserror", - "toml", - "types", + "termcolor", + "unicode-width 0.1.14", ] [[package]] @@ -478,71 +231,90 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "console" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ - "crossbeam-utils", + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.59.0", ] [[package]] -name = "const-oid" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cb3c4a0d3776f7535c32793be81d6d5fec0d48ac70955d9834e643aa249a52f" - -[[package]] -name = "cpufeatures" -version = "0.2.17" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ + "core-foundation-sys", "libc", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "crunchy" -version = "0.2.3" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] [[package]] name = "crypto-common" -version = "0.2.0-rc.2" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170d71b5b14dec99db7739f6fc7d6ec2db80b78c3acb77db48392ccc3d8a9ea0" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "hybrid-array", + "generic-array", + "typenum", ] [[package]] -name = "debian" -version = "0.1.0" +name = "debcrafter" +version = "0.2.0" +source = "git+https://github.com/eth-pkg/debcrafter.git?branch=refactor-extract-codegen-modules#401cd79dfae49fc02b210c99ce66ac6c97774e3f" dependencies = [ - "log", + "codespan-reporting", + "either", + "fmt2io", + "indexmap 1.9.3", + "rfc822-like", "serde", - "shellexpand", + "serde_derive", + "thiserror", + "toml 0.5.11", + "void", +] + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", "tempfile", "thiserror", - "toml", - "types", + "zeroize", ] [[package]] name = "digest" -version = "0.11.0-pre.10" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c478574b20020306f98d61c8ca3322d762e1ff08117422ac6106438605ea516" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", ] @@ -555,16 +327,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -577,17 +339,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -596,7 +347,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -606,12 +357,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "ena" -version = "0.14.3" +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "log", + "cfg-if", ] [[package]] @@ -654,61 +411,43 @@ dependencies = [ ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "event-listener" -version = "5.4.0" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] -name = "event-listener-strategy" -version = "0.5.3" +name = "fmt2io" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" -dependencies = [ - "event-listener 5.4.0", - "pin-project-lite", -] +checksum = "6b6129284da9f7e5296cc22183a63f24300e945e297705dcc0672f7df01d62c8" [[package]] -name = "fastrand" -version = "2.3.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "filetime" -version = "0.2.25" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", + "foreign-types-shared", ] [[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" @@ -721,69 +460,63 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] -name = "futures-lite" -version = "2.6.0" +name = "futures-sink" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", - "futures-macro", + "futures-io", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", - "pin-utils", "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -809,22 +542,35 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "gloo-timers" -version = "0.3.0" +name = "h2" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ - "futures-channel", + "atomic-waker", + "bytes", + "fnv", "futures-core", - "js-sys", - "wasm-bindgen", + "futures-sink", + "http", + "indexmap 2.8.0", + "slab", + "tokio", + "tokio-util", + "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.2" @@ -837,31 +583,36 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "http" -version = "0.2.12" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -872,69 +623,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "httpdate" -version = "1.0.3" +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] [[package]] -name = "httpmock" -version = "0.7.0" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ec9586ee0910472dec1a1f0f8acf52f0fdde93aea74d70d4a3107b4be0fd5b" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "assert-json-diff", - "async-object-pool", - "async-std", - "async-trait", - "base64", - "basic-cookies", - "crossbeam-utils", - "form_urlencoded", - "futures-util", + "http", "hyper", - "lazy_static", - "levenshtein", - "log", - "regex", - "serde", - "serde_json", - "serde_regex", - "similar", + "hyper-util", + "rustls", + "rustls-pki-types", "tokio", - "url", + "tokio-rustls", + "tower-service", ] [[package]] -name = "hybrid-array" -version = "0.3.0" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dab50e193aebe510fe0e40230145820e02f48dae0cf339ea4204e6e708ff7bd" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "typenum", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "hyper" -version = "0.14.32" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", - "httparse", - "httpdate", - "itoa", + "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", - "want", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] @@ -1052,7 +840,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1076,6 +864,17 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.8.0" @@ -1083,24 +882,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" +name = "io-uring" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] [[package]] -name = "itertools" -version = "0.11.0" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ - "either", + "memchr", + "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.15" @@ -1128,71 +945,19 @@ checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "levenshtein" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" - [[package]] name = "libc" version = "0.2.171" @@ -1207,15 +972,8 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags", "libc", - "redox_syscall", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.9.2" @@ -1228,24 +986,11 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" -dependencies = [ - "value-bag", -] [[package]] name = "memchr" @@ -1253,140 +998,134 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "native-tls" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ - "memchr", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] -name = "once_cell" -version = "1.21.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] [[package]] -name = "option-ext" -version = "0.2.0" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "packager_deb" -version = "0.1.0" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "cargo_metadata", - "debian", - "dirs", - "env_logger", - "filetime", - "httpmock", - "log", - "rand", - "serde", - "sha1", - "sha2", - "shellexpand", - "tempfile", - "thiserror", - "toml", - "types", + "memchr", ] [[package]] -name = "parking" -version = "2.2.1" +name = "once_cell" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" [[package]] -name = "parking_lot" -version = "0.12.3" +name = "openssl" +version = "0.10.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ - "lock_api", - "parking_lot_core", + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", ] [[package]] -name = "parking_lot_core" -version = "0.9.10" +name = "openssl-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "percent-encoding" -version = "2.3.1" +name = "openssl-probe" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] -name = "petgraph" -version = "0.6.5" +name = "openssl-sys" +version = "0.9.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" dependencies = [ - "fixedbitset", - "indexmap", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] -name = "phf_shared" -version = "0.11.3" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "pico-args" -version = "0.5.0" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -1395,41 +1134,85 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +name = "pkg-builder-cli" +version = "0.4.0-rc.1" dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", + "clap", + "dialoguer", + "env_logger", + "log", + "pkg-builder-config", + "pkg-builder-executor", + "pkg-builder-init", + "pkg-builder-update", ] [[package]] -name = "pkg-builder" -version = "0.3.1" +name = "pkg-builder-config" +version = "0.4.0-rc.1" dependencies = [ - "cli", + "log", + "semver", "serde", + "serde_json", + "sha2", + "shellexpand", + "tempfile", "thiserror", - "toml", + "toml 0.8.20", + "url", ] [[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +name = "pkg-builder-executor" +version = "0.4.0-rc.1" dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 0.38.44", - "tracing", - "windows-sys 0.59.0", + "debcrafter", + "log", + "pkg-builder-config", + "reqwest", + "sha2", + "thiserror", + "toml 0.8.20", +] + +[[package]] +name = "pkg-builder-init" +version = "0.4.0-rc.1" +dependencies = [ + "log", + "reqwest", + "serde", + "serde_json", + "sha2", + "toml 0.8.20", +] + +[[package]] +name = "pkg-builder-update" +version = "0.4.0-rc.1" +dependencies = [ + "chrono", + "dialoguer", + "log", + "pkg-builder-config", + "pkg-builder-init", + "regex", + "reqwest", + "serde_json", + "sha2", + "tempfile", + "thiserror", + "toml 0.8.20", + "toml_edit", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "portable-atomic" version = "1.11.0" @@ -1445,21 +1228,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "proc-macro2" version = "1.0.94" @@ -1478,45 +1246,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" -dependencies = [ - "rand_chacha", - "rand_core", - "zerocopy", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -1557,43 +1286,131 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "rfc822-like" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264615e2eab444f9acd5ee00e4401f0025bdde75ab9c1dab3062a040e07c2ff" +dependencies = [ + "fmt2io", + "serde", + "thiserror", + "unicode-segmentation", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustix" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] [[package]] -name = "rustix" -version = "0.38.44" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "zeroize", ] [[package]] -name = "rustix" -version = "1.0.2" +name = "rustls-webpki" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.9.2", - "windows-sys 0.59.0", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -1602,28 +1419,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] -name = "same-file" -version = "1.0.6" +name = "schannel" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "winapi-util", + "windows-sys 0.61.2", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] [[package]] name = "serde" @@ -1642,7 +1473,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1657,16 +1488,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_regex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" -dependencies = [ - "regex", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.8" @@ -1677,27 +1498,34 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.11.0-pre.5" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f44e40722caefdd99383c25d3ae52a1094a1951215ae76f68837ece4e7f566" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] name = "sha2" -version = "0.11.0-pre.5" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b4241d1a56954dce82cecda5c8e9c794eef6f53abe5e5216bac0a0ea71ffa7" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", "digest", ] +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shellexpand" version = "3.1.0" @@ -1708,34 +1536,16 @@ dependencies = [ ] [[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "similar" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" - -[[package]] -name = "siphasher" -version = "1.0.1" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -1745,9 +1555,9 @@ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1759,18 +1569,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "string_cache" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.11.1" @@ -1778,15 +1576,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "syn" -version = "1.0.109" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1799,6 +1592,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -1807,7 +1609,28 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -1820,19 +1643,17 @@ dependencies = [ "fastrand", "getrandom 0.3.1", "once_cell", - "rustix 1.0.2", + "rustix", "windows-sys 0.59.0", ] [[package]] -name = "term" -version = "0.7.0" +name = "termcolor" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "winapi-util", ] [[package]] @@ -1852,16 +1673,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", + "syn", ] [[package]] @@ -1876,29 +1688,61 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", + "bytes", + "io-uring", "libc", "mio", "pin-project-lite", - "signal-hook-registry", + "slab", "socket2", - "tokio-macros", "windows-sys 0.52.0", ] [[package]] -name = "tokio-macros" -version = "2.5.0" +name = "tokio-native-tls" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", ] [[package]] @@ -1928,13 +1772,52 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap", + "indexmap 2.8.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -1943,9 +1826,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-core", @@ -1953,9 +1836,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1972,19 +1855,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" -[[package]] -name = "types" -version = "0.1.0" -dependencies = [ - "log", - "semver", - "serde", - "tempfile", - "thiserror", - "toml", - "url", -] - [[package]] name = "unicode-ident" version = "1.0.18" @@ -1992,10 +1862,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "unicode-xid" -version = "0.2.6" +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -2006,6 +1894,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2027,20 +1916,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "value-bag" -version = "1.10.0" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "walkdir" -version = "2.5.0" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "want" @@ -2068,37 +1959,25 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -2107,9 +1986,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2117,66 +1996,114 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.100", - "wasm-bindgen-backend", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "winapi" -version = "0.3.9" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-sys 0.48.0", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-core" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] [[package]] -name = "winapi-util" -version = "0.1.9" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ - "windows-sys 0.59.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] name = "windows-sys" @@ -2205,6 +2132,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2376,30 +2312,10 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "zerofrom" version = "0.1.6" @@ -2417,10 +2333,16 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zerovec" version = "0.10.4" @@ -2440,5 +2362,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index fca3066d..4d13044f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [workspace] members = [ - "workspace/packager_deb", - "workspace/cli", - "workspace/types", - "workspace/debian", - "workspace/pkg_builder", + "crates/config", + "crates/cli", + "crates/init", + "crates/executor", + "crates/update", ] resolver = "2" [workspace.package] edition = "2021" - +license = "Apache-2.0" [workspace.dependencies] clap = { version = "4.5.4", features = ["derive"] } @@ -19,26 +19,22 @@ toml = "0.8.12" serde = { version = "1.0", features = ["derive"] } env_logger = "0.11.3" log = "0.4" -cargo_metadata = "0.18" -regex = "1.10.4" thiserror = "1.0" shellexpand = "3.1.0" tempfile = "3.1" -git2 = "0.18.3" -test-case = "3.3.1" -glob = "0.3.1" -dirs = "5.0.1" -rand = "0.9.0-alpha.1" -sha2 = "0.11.0-pre.3" -whoami = "1.5.1" -sha1 = "0.11.0-pre.3" -filetime = "0.2.23" -httpmock = "0.7.0" -semver = "1.0.20" # Replace with the version you need -url = "2.4.1" # Use the latest version +sha2 = "0.10" +semver = "1.0.20" +url = "2.4.1" +dialoguer = "0.11" +reqwest = { version = "0.12", features = ["blocking", "json"] } +serde_json = "1.0" +toml_edit = "0.22" +chrono = "0.4" +regex = "1" +debcrafter = { git = "https://github.com/eth-pkg/debcrafter.git", branch = "refactor-extract-codegen-modules" } # Local crates -cli = {path = "workspace/cli"} -debian = {path = "workspace/debian"} -packager_deb = {path = "workspace/packager_deb"} -types = {path = "workspace/types"} +pkg-builder-config = { path = "crates/config" } +pkg-builder-init = { path = "crates/init" } +pkg-builder-executor = { path = "crates/executor" } +pkg-builder-update = { path = "crates/update" } diff --git a/README.md b/README.md new file mode 100644 index 00000000..da95fbc2 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# pkg-builder + +[![CI](https://github.com/eth-pkg/pkg-builder/actions/workflows/tests.yml/badge.svg)](https://github.com/eth-pkg/pkg-builder/actions/workflows/tests.yml) +[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/eth-pkg/pkg-builder/blob/main/LICENSE) + +A command-line tool for creating reproducible Debian packages from TOML configuration files. It integrates with [debcrafter](https://github.com/Kixunil/debcrafter) to simplify the Debian packaging workflow, handling the entire pipeline from environment setup and source acquisition to package building and verification. + +## Why pkg-builder? + +Debian packaging is powerful but notoriously difficult to get right. pkg-builder solves this by letting you define your entire package in a single `pkg-builder.toml` file. Instead of hand-writing debian control files, you declare what you want — source location, build distribution, runtime toolchain — and pkg-builder handles everything else. It pins snapshot archives, normalizes timestamps, and verifies output hashes so that the same config always produces the same `.deb`. + +It works alongside [debcrafter](https://github.com/Kixunil/debcrafter), which generates the Debian specification files (`.sss` files) that describe package metadata and relationships. Together, they provide a fully declarative packaging pipeline: debcrafter handles *what* the package is, pkg-builder handles *how* it gets built. + +## Quick Start + +**1. Install prerequisites and build:** + +```bash +sudo apt install libssl-dev pkg-config quilt debhelper tar git-lfs uidmap +sudo sbuild-adduser $(whoami) +cargo install --path . +``` + +**2. Create the build environment:** + +```bash +pkg-builder --config pkg-builder.toml env create +``` + +**3. Build the package:** + +```bash +pkg-builder --config pkg-builder.toml build +``` + +That's it — your `.deb` is in the workdir. See the [tutorial](docs/src/getting-started/first-package.md) for a complete walkthrough. + +## Features + +- **TOML-driven configuration** — define your package in a single `pkg-builder.toml` file +- **Reproducible builds** — timestamp normalization, snapshot pinning, and hash verification +- **Multiple source types** — tarballs, git repositories (with submodule pinning), and virtual/meta-packages +- **Multi-language support** — C, Rust, Go, Node.js (JavaScript/TypeScript), Java (with Gradle), .NET, Nim +- **Multi-distribution** — Debian (bookworm, trixie) and Ubuntu (noble) +- **Package verification** — SHA-256 hash checking for built `.dsc` and `.deb` files + +## Documentation + +Full documentation is in the [`docs/`](docs/src/SUMMARY.md) directory, built with [mdBook](https://rust-lang.github.io/mdBook/): + +- **Getting Started** — [Installation](docs/src/getting-started/installation.md) | [Tutorial](docs/src/getting-started/first-package.md) | [Concepts](docs/src/getting-started/concepts.md) +- **Guides** — [Source Types](docs/src/guides/source-types.md) | [Runtime Recipes](docs/src/guides/runtime-recipes.md) | [Snapshot Pinning](docs/src/guides/snapshot-pinning.md) | [Patching](docs/src/guides/patching.md) | [Caching](docs/src/guides/caching.md) | [Verification](docs/src/guides/verification.md) +- **Reference** — [Configuration](docs/src/reference/config.md) | [CLI](docs/src/reference/cli.md) | [Recipes](docs/src/reference/recipes.md) +- [Troubleshooting](docs/src/troubleshooting.md) + +To build and view the docs locally: + +```bash +cargo install mdbook +mdbook serve docs/ +``` + +## Examples + +The `examples/` directory contains working configurations for all supported language and distribution combinations: + +``` +examples/ + bookworm/ — Debian stable (C, git-package) + noble/ — Ubuntu 24.04 (C, .NET, Go, Java, JavaScript, Nim, Rust, TypeScript, virtual, git-package) + trixie/ — Debian testing (C, .NET, Go, Java, JavaScript, Nim, Rust, TypeScript, virtual, git-package) +``` + +Each example includes a `pkg-builder.toml` and any supporting files needed for a complete build. They serve as both documentation and integration tests. + +## Contributing + +```bash +# Clone and build +git clone https://github.com/eth-pkg/pkg-builder.git +cd pkg-builder +cargo build + +# Run tests +cargo test +``` + +Bug reports and pull requests are welcome on [GitHub](https://github.com/eth-pkg/pkg-builder/issues). + +## License + +This project is licensed under the [Apache License 2.0](LICENSE). diff --git a/Readme.md b/Readme.md deleted file mode 100644 index e199b2a2..00000000 --- a/Readme.md +++ /dev/null @@ -1,85 +0,0 @@ -# pkg-builder - -[![Tests](https://github.com/eth-pkg/pkg-builder/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/eth-pkg/pkg-builder/actions/workflows/tests.yml) - -A tool to create reproducible builds for Debian-based systems (Ubuntu Jammy, Noble, and Debian 12) using a TOML configuration file. - -## Overview - -pkg-builder uses debcrafter to generate Debian packages from a TOML config, simplifying reproducible packaging for developers. - -## Key Features - -- TOML-based configuration -- Package types: default (tarballs), Git-based, virtual -- Build support: C/C++, Rust, Go, Python, TypeScript/JavaScript, Java, .NET, Nim -- Testing: piuparts (install/remove), autopkgtest (functionality), lintian (quality) -- Package verification with hashes -- Flexible build environments -- Reproducible builds for Ubuntu Jammy, Noble, and Debian 12 - -## Quick Start - -### Prerequisites (Debian/Ubuntu) - -```bash -sudo apt install libssl-dev pkg-config quilt debhelper tar wget autopkgtest vmdb2 qemu-system-x86 git-lfs uidmap -sudo sbuild-adduser `whoami` -``` - -See [installation docs](docs/install.md) for sbuild setup. - -### Basic Usage - -```bash -# Install pkg-builder -cargo install --path . - -# Create environment and build package -pkg-builder env create path/to/pkg-builder.toml -pkg-builder package path/to/pkg-builder.toml -``` - -If no config file path is provided, `pkg-builder.toml` in the current directory is used. - -## Commands - -```bash -pkg-builder package path/to/pkg-builder.toml # Build package -pkg-builder env create path/to/pkg-builder.toml # Create build environment -pkg-builder env clean path/to/pkg-builder.toml # Clean build environment -pkg-builder piuparts path/to/pkg-builder.toml # Run piuparts tests -pkg-builder autopkgtests path/to/pkg-builder.toml # Run autopkgtests -pkg-builder lintian path/to/pkg-builder.toml # Run lintian checks -pkg-builder verify path/to/pkg-builder.toml # Verify package hashes -pkg-builder version # Show version -``` - -If no config file path is provided, `pkg-builder.toml` in the current directory is used. - -## Testing - -```bash -pkg-builder piuparts path/to/pkg-builder.toml # Run piuparts tests -pkg-builder autopkgtests path/to/pkg-builder.toml # Run autopkgtests -pkg-builder lintian path/to/pkg-builder.toml # Run lintian checks -pkg-builder verify path/to/pkg-builder.toml # Verify package hashes -``` - -If no config file path is provided, `pkg-builder.toml` in the current directory is used. - -## Examples - -See [examples documentation](EXAMPLES.md) for sample configs: -- Virtual packages, Rust, TypeScript/JavaScript, Nim, .NET, Java, Python, Go - -## Documentation - -- [Installation Guide](docs/install.md) -- [Configuration Reference](docs/config.md) -- [Examples](docs/examples.md) -- [Packaging FAQ](docs/packaging.md) - -## License - -Apache License, Version 2.0. See [LICENSE](http://www.apache.org/licenses/LICENSE-2.0). diff --git a/build-all.sh b/build-all.sh new file mode 100755 index 00000000..897e39d5 --- /dev/null +++ b/build-all.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# Skip these package types +SKIP_PACKAGES=("dotnet" "dotnet-9" "git-package") + +# All available distros +ALL_DISTROS=(bookworm noble trixie) + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +usage() { + echo "Usage: $0 [OPTIONS] [DISTRO...]" + echo "" + echo "Build, verify, and update hashes for all example packages." + echo "" + echo "Arguments:" + echo " DISTRO... Distros to build (default: all: ${ALL_DISTROS[*]})" + echo "" + echo "Options:" + echo " --skip PKG Skip a package type (can be repeated, default: ${SKIP_PACKAGES[*]})" + echo " --only PKG Only build this package type (can be repeated)" + echo " --no-clean Skip the clean step before building" + echo " --no-verify Skip verify step" + echo " --replace Update hashes in toml when verify finds mismatches" + echo " --dry-run Show what would be built without building" + echo " -h, --help Show this help" +} + +ONLY_PACKAGES=() +NO_CLEAN=false +NO_VERIFY=false +REPLACE=false +DRY_RUN=false +DISTROS=() + +while [[ $# -gt 0 ]]; do + case $1 in + --skip) + SKIP_PACKAGES+=("$2") + shift 2 + ;; + --only) + ONLY_PACKAGES+=("$2") + shift 2 + ;; + --no-clean) + NO_CLEAN=true + shift + ;; + --no-verify) + NO_VERIFY=true + shift + ;; + --replace) + REPLACE=true + shift + ;; + --dry-run) + DRY_RUN=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + -*) + echo "Unknown option: $1" + usage + exit 1 + ;; + *) + DISTROS+=("$1") + shift + ;; + esac +done + +# Default to all distros if none specified +if [[ ${#DISTROS[@]} -eq 0 ]]; then + DISTROS=("${ALL_DISTROS[@]}") +fi + +should_skip() { + local pkg="$1" + # If --only is set, skip everything not in the list + if [[ ${#ONLY_PACKAGES[@]} -gt 0 ]]; then + for only in "${ONLY_PACKAGES[@]}"; do + if [[ "$pkg" == "$only" ]]; then + return 1 + fi + done + return 0 + fi + # Otherwise check skip list + for skip in "${SKIP_PACKAGES[@]}"; do + if [[ "$pkg" == "$skip" ]]; then + return 0 + fi + done + return 1 +} + +# Collect all toml files to process +TOMLS=() +for distro in "${DISTROS[@]}"; do + if [[ ! -d "examples/$distro" ]]; then + echo -e "${RED}Distro not found: examples/$distro${NC}" + continue + fi + for toml in examples/"$distro"/*/hello-world/pkg-builder.toml examples/"$distro"/*/nimbus/pkg-builder.toml; do + [[ -f "$toml" ]] || continue + # Extract package type: examples/distro/TYPE/... + pkg_type=$(echo "$toml" | cut -d/ -f3) + if should_skip "$pkg_type"; then + echo -e "${YELLOW}Skipping ${pkg_type} (${distro})${NC}" + continue + fi + TOMLS+=("$toml") + done +done + +if [[ ${#TOMLS[@]} -eq 0 ]]; then + echo -e "${RED}No packages found to build.${NC}" + exit 1 +fi + +echo -e "${BLUE}Will process ${#TOMLS[@]} package(s):${NC}" +for toml in "${TOMLS[@]}"; do + echo " $toml" +done +echo "" + +if [[ "$DRY_RUN" == true ]]; then + echo -e "${YELLOW}Dry run, exiting.${NC}" + exit 0 +fi + +FAILED=() +SUCCEEDED=() + +for toml in "${TOMLS[@]}"; do + echo -e "\n${BLUE}========================================${NC}" + echo -e "${BLUE}Processing: ${toml}${NC}" + echo -e "${BLUE}========================================${NC}" + + # Step 1: Clean + if [[ "$NO_CLEAN" != true ]]; then + echo -e "${YELLOW}Cleaning...${NC}" + if ! cargo run --bin pkg-builder -- --config "$toml" clean 2>&1; then + echo -e "${YELLOW}Clean failed (continuing anyway)${NC}" + fi + fi + + # Step 2: Remove sbuild tmp folder contents + echo -e "${YELLOW}Removing sbuild tmp folder contents...${NC}" + sudo rm -rf /tmp/sbuild-createchroot 2>/dev/null || true + + + # Step 3: Build + echo -e "${YELLOW}Building...${NC}" + if ! cargo run --bin pkg-builder -- --config "$toml" build 2>&1; then + echo -e "${RED}BUILD FAILED: ${toml}${NC}" + FAILED+=("$toml") + continue + fi + + # Step 4: Verify (and optionally update hashes with --replace) + if [[ "$NO_VERIFY" != true ]]; then + echo -e "${YELLOW}Verifying...${NC}" + verify_output=$(cargo run --bin pkg-builder -- --config "$toml" verify 2>&1) || true + echo "$verify_output" + + if echo "$verify_output" | grep -q "SHA-256 mismatch"; then + if [[ "$REPLACE" == true ]]; then + echo -e "${YELLOW}Hash mismatch detected, updating hashes in ${toml}...${NC}" + + # Split errors (may be joined by "; " on one line) and process each + while IFS= read -r match; do + file_name=$(echo "$match" | sed 's/SHA-256 mismatch for \(.*\): expected.*/\1/') + new_hash=$(echo "$match" | sed 's/.*, got //') + echo -e " Updating hash for ${file_name} -> ${new_hash}" + # Replace by matching the file name in the toml + sed -i "/${file_name}/s/hash = \"[a-f0-9]*\"/hash = \"${new_hash}\"/" "$toml" + done < <(echo "$verify_output" | grep -o 'SHA-256 mismatch for [^;]*') + + # Re-verify + echo -e "${YELLOW}Re-verifying...${NC}" + if cargo run --bin pkg-builder -- --config "$toml" verify 2>&1; then + echo -e "${GREEN}Verification passed after hash update!${NC}" + else + echo -e "${RED}Verification still failing after hash update!${NC}" + FAILED+=("$toml") + continue + fi + else + echo -e "${RED}Verify failed for ${toml}${NC}" + FAILED+=("$toml") + continue + fi + elif echo "$verify_output" | grep -q "No \[verify\] section"; then + echo -e "${RED}No [verify] section in ${toml}${NC}" + FAILED+=("$toml") + continue + elif echo "$verify_output" | grep -q "Verification successful"; then + echo -e "${GREEN}Verification passed!${NC}" + else + echo -e "${RED}Verify failed for ${toml}${NC}" + FAILED+=("$toml") + continue + fi + fi + + SUCCEEDED+=("$toml") +done + +echo -e "\n${BLUE}========================================${NC}" +echo -e "${BLUE}Summary${NC}" +echo -e "${BLUE}========================================${NC}" +echo -e "${GREEN}Succeeded: ${#SUCCEEDED[@]}${NC}" +for s in "${SUCCEEDED[@]}"; do + echo -e " ${GREEN}✓${NC} $s" +done + +if [[ ${#FAILED[@]} -gt 0 ]]; then + echo -e "${RED}Failed: ${#FAILED[@]}${NC}" + for f in "${FAILED[@]}"; do + echo -e " ${RED}✗${NC} $f" + done + exit 1 +fi diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 00000000..019d9ee3 --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "pkg-builder-cli" +version = "0.4.0-rc.1" +edition = "2021" +license.workspace = true + +[[bin]] +name = "pkg-builder" +path = "src/main.rs" + +[dependencies] +pkg-builder-config = { path = "../config" } +pkg-builder-init = { path = "../init" } +pkg-builder-executor = { path = "../executor" } +pkg-builder-update = { path = "../update" } +clap = { workspace = true } +env_logger = { workspace = true } +log = { workspace = true } +dialoguer = { workspace = true } diff --git a/crates/cli/src/commands.rs b/crates/cli/src/commands.rs new file mode 100644 index 00000000..e20db489 --- /dev/null +++ b/crates/cli/src/commands.rs @@ -0,0 +1,135 @@ +use clap::{Args, Parser, Subcommand}; + +#[derive(Debug, Parser)] +#[clap(author, version, about)] +pub struct PkgBuilderArgs { + /// Path to pkg-builder.toml config (default: current directory) + #[clap(long, global = true)] + pub config: Option, + + /// Resume a previous build (skip steps whose artifacts already exist) + #[clap(long, global = true)] + pub resume: bool, + + #[clap(subcommand)] + pub action: ActionType, +} + +#[derive(Debug, Subcommand)] +pub enum ActionType { + /// Interactive project setup wizard + Init(InitCommand), + /// Update package to a new upstream version + Update(UpdateCommand), + /// Build the package + Build, + /// Manage build environment (sbuild chroot) + Env(EnvCommand), + /// Verify package hashes + Verify, + /// Clean build artifacts + Clean, +} + +#[derive(Debug, Args)] +pub struct InitCommand { + /// Package name + #[clap(long)] + pub name: Option, + /// Package version + #[clap(long)] + pub version: Option, + /// Package revision + #[clap(long)] + pub revision: Option, + /// Homepage URL + #[clap(long)] + pub homepage: Option, + /// Maintainer name + #[clap(long)] + pub maintainer_name: Option, + /// Maintainer email + #[clap(long)] + pub maintainer_email: Option, + /// Debian section (e.g., net, utils, devel, admin, libs, web, etc.) + #[clap(long)] + pub section: Option, + /// Short package description/summary + #[clap(long)] + pub summary: Option, + /// Source type: tarball, git, or virtual + #[clap(long)] + pub source_type: Option, + /// Source URL (tarball URL or git repo URL) + #[clap(long)] + pub url: Option, + /// Git tag (for git source type) + #[clap(long)] + pub tag: Option, + /// Target distribution: bookworm, trixie, or noble + #[clap(long)] + pub distribution: Option, + /// Target architecture + #[clap(long)] + pub arch: Option, + /// Runtime recipe: go, rust, node, java, java-gradle, nim, c, etc. Use "none" for no runtime + #[clap(long)] + pub runtime: Option, + /// Output directory (default: current directory) + #[clap(long)] + pub output: Option, + /// Expected upstream hash for tarball verification + #[clap(long)] + pub upstream_hash: Option, +} + +#[derive(Debug, Args)] +pub struct UpdateCommand { + /// New upstream version (omit to auto-detect from GitHub) + #[clap(long)] + pub version: Option, + /// Package revision (default: "1") + #[clap(long)] + pub revision: Option, + /// Changelog message (default: "New upstream version {version}") + #[clap(long)] + pub changelog_msg: Option, + /// GitHub owner/repo (inferred from source URL if omitted) + #[clap(long)] + pub github_repo: Option, + /// Update files in the package directory pointed to by --config + #[clap(long)] + pub in_place: bool, + /// Write to a new directory (copies all files + applies updates) + #[clap(long)] + pub output: Option, + /// Skip download, use this source hash directly + #[clap(long)] + pub hash: Option, + /// Skip GitHub lookup, use this commit hash + #[clap(long)] + pub git_commit: Option, + /// Don't download source (leave hash empty/unchanged, skip patch test) + #[clap(long)] + pub skip_download: bool, + /// Also update runtime to latest version + #[clap(long)] + pub update_runtime: bool, + /// Skip patch application testing + #[clap(long)] + pub skip_patch_check: bool, +} + +#[derive(Debug, Args)] +pub struct EnvCommand { + #[clap(subcommand)] + pub sub_command: EnvSubCommand, +} + +#[derive(Debug, Subcommand)] +pub enum EnvSubCommand { + /// Create build environment (sbuild chroot) + Create, + /// Remove build environment (chroot tarball) + Clean, +} diff --git a/crates/cli/src/init.rs b/crates/cli/src/init.rs new file mode 100644 index 00000000..9edc1761 --- /dev/null +++ b/crates/cli/src/init.rs @@ -0,0 +1,246 @@ +use crate::commands::InitCommand; +use dialoguer::{Confirm, Input, Select}; +use log::warn; +use pkg_builder_init::{ + self, Distribution, InitConfig, Runtime, RuntimeSetup, SourceType, ALL_DISTRIBUTIONS, + ALL_RUNTIMES, ALL_SOURCE_TYPES, DEBIAN_SECTIONS, +}; +use std::path::Path; + +pub fn run(cmd: &InitCommand) -> Result<(), Box> { + let default_name = std::env::current_dir() + .ok() + .and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string())) + .unwrap_or_else(|| "my-package".to_string()); + + // Top-level fields + let name = text_or_flag(&cmd.name, "Package name", Some(&default_name))?; + let version = text_or_flag(&cmd.version, "Package version", Some("1.0.0"))?; + let revision = text_or_flag(&cmd.revision, "Package revision", Some("1"))?; + let homepage = text_or_flag(&cmd.homepage, "Homepage URL", None)?; + let maintainer_name = text_or_flag(&cmd.maintainer_name, "Maintainer name", None)?; + let maintainer_email = text_or_flag(&cmd.maintainer_email, "Maintainer email", None)?; + let section = select_or_flag(&cmd.section, "Debian section", DEBIAN_SECTIONS, Some("net"))?; + let summary = text_or_flag(&cmd.summary, "Short description/summary", None)?; + + // Source type + source-specific fields + let source_type = enum_or_flag(&cmd.source_type, "Source type", ALL_SOURCE_TYPES)?; + let mut source_vals = std::collections::HashMap::new(); + for field in source_type.required_fields() { + let flag = match field.key { + "url" => &cmd.url, + "tag" => &cmd.tag, + _ => &None, + }; + source_vals.insert(field.key, text_or_flag(flag, field.label, None)?); + } + let output_dir = cmd.output.as_deref().unwrap_or("."); + let source = pkg_builder_init::resolve_source( + source_type, + source_vals.get("url").map(|s| s.as_str()), + source_vals.get("tag").map(|s| s.as_str()), + Path::new(output_dir), + cmd.upstream_hash.as_deref(), + )?; + + // Distribution, arch + let distribution = enum_or_flag(&cmd.distribution, "Target distribution", ALL_DISTRIBUTIONS)?; + let arch = cmd.arch.clone().unwrap_or_else(|| "amd64".to_string()); + + // Runtime + runtime vars + let runtime = enum_or_flag(&cmd.runtime, "Runtime recipe", ALL_RUNTIMES)?; + let runtime_vars = resolve_runtime(runtime)?; + + let config = InitConfig { + name, + version, + revision, + homepage, + maintainer_name, + maintainer_email, + section, + summary, + source, + distribution, + arch, + runtime, + runtime_vars, + }; + + let output_path = Path::new(output_dir); + let files = pkg_builder_init::write_init_files(&config, output_path)?; + + println!("Created:"); + println!(" {}", files.toml_path.display()); + println!(" {}", files.sss_path.display()); + println!(" {}", files.sps_path.display()); + + Ok(()) +} + +// ---- Generic prompt helpers ---- + +/// Use the CLI flag value if present, otherwise prompt for text input. +fn text_or_flag( + flag: &Option, + label: &str, + default: Option<&str>, +) -> Result> { + if let Some(v) = flag { + return Ok(v.clone()); + } + let mut input = Input::::new().with_prompt(label); + if let Some(d) = default { + input = input.default(d.to_string()); + } + Ok(input.interact_text()?) +} + +/// Use the CLI flag value if it matches an option, otherwise show a select prompt. +fn select_or_flag( + flag: &Option, + label: &str, + options: &[&str], + default: Option<&str>, +) -> Result> { + if let Some(v) = flag { + if !options.contains(&v.as_str()) { + return Err(format!( + "Unknown {}: '{}'. Valid options: {}", + label, + v, + options.join(", ") + ) + .into()); + } + return Ok(v.clone()); + } + let default_idx = default + .and_then(|d| options.iter().position(|&o| o == d)) + .unwrap_or(0); + let idx = Select::new() + .with_prompt(label) + .items(options) + .default(default_idx) + .interact()?; + Ok(options[idx].to_string()) +} + +/// Use the CLI flag to parse an enum, otherwise show a select prompt. +fn enum_or_flag( + flag: &Option, + label: &str, + all: &[T], +) -> Result> +where + T: EnumSelect, +{ + if let Some(s) = flag { + return T::parse(s).ok_or_else(|| format!("Unknown {}: {}", label, s).into()); + } + let labels: Vec<&str> = all.iter().map(|v| v.display()).collect(); + let idx = Select::new() + .with_prompt(label) + .items(&labels) + .default(0) + .interact()?; + Ok(all[idx]) +} + +trait EnumSelect { + fn parse(s: &str) -> Option + where + Self: Sized; + fn display(&self) -> &'static str; +} + +impl EnumSelect for SourceType { + fn parse(s: &str) -> Option { + SourceType::from_str(s) + } + fn display(&self) -> &'static str { + self.as_str() + } +} + +impl EnumSelect for Distribution { + fn parse(s: &str) -> Option { + Distribution::from_str(s) + } + fn display(&self) -> &'static str { + self.as_str() + } +} + +impl EnumSelect for Runtime { + fn parse(s: &str) -> Option { + Runtime::from_str(s) + } + fn display(&self) -> &'static str { + self.as_str() + } +} + +/// Prompt for all runtime fields based on the RuntimeSetup returned by the lib. +fn resolve_runtime(runtime: Runtime) -> Result, Box> { + match runtime.setup() { + RuntimeSetup::NoVars => Ok(vec![]), + RuntimeSetup::ManualOnly => { + println!("This runtime has complex configuration. Please fill in runtime variables manually after init."); + Ok(vec![]) + } + RuntimeSetup::NeedsInput { fields } => prompt_fields(fields), + RuntimeSetup::AutoResolved { + latest, + fields, + optional_fields, + } => { + let use_latest = Confirm::new() + .with_prompt(format!("Use {} {} (latest)?", runtime, latest.version)) + .default(true) + .interact()?; + + let mut vars = if use_latest { + latest.vars + } else { + let version: String = Input::new() + .with_prompt(format!("{} version", runtime)) + .interact_text()?; + match runtime.resolve_version(&version) { + Ok(v) => v, + Err(e) => { + warn!( + "Could not auto-resolve {} {}: {}. Please enter values manually.", + runtime, version, e + ); + prompt_fields(fields)? + } + } + }; + + for field in optional_fields { + if Confirm::new() + .with_prompt(format!("Add {}?", field.key)) + .default(false) + .interact()? + { + let value: String = Input::new().with_prompt(field.label).interact_text()?; + vars.push((field.key.to_string(), value)); + } + } + + Ok(vars) + } + } +} + +fn prompt_fields( + fields: &[pkg_builder_init::RuntimeField], +) -> Result, Box> { + let mut vars = Vec::new(); + for field in fields { + let value: String = Input::new().with_prompt(field.label).interact_text()?; + vars.push((field.key.to_string(), value)); + } + Ok(vars) +} diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 00000000..4503edc5 --- /dev/null +++ b/crates/cli/src/main.rs @@ -0,0 +1,59 @@ +mod commands; +mod init; +mod update; + +use commands::{ActionType, EnvSubCommand, PkgBuilderArgs}; + +use clap::Parser; +use env_logger::Env; +use log::{error, info}; +use std::process::ExitCode; + +fn main() -> ExitCode { + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + + match run() { + Ok(()) => ExitCode::SUCCESS, + Err(e) => { + error!("{e:#}"); + ExitCode::FAILURE + } + } +} + +fn run() -> Result<(), Box> { + let args = PkgBuilderArgs::parse(); + + if let ActionType::Init(ref init_cmd) = args.action { + return init::run(init_cmd); + } + + let config_path = args.config.unwrap_or_else(|| ".".to_string()); + + if let ActionType::Update(ref update_cmd) = args.action { + return update::run(update_cmd, &config_path); + } + + let config = config::PkgConfig::load(&config_path)?; + + match args.action { + ActionType::Init(_) => unreachable!(), + ActionType::Update(_) => unreachable!(), + ActionType::Verify => { + config::verify::verify_hashes(&config)?; + info!("Verification successful!"); + } + ActionType::Build => { + executor::build(&config, args.resume)?; + } + ActionType::Env(ref env_cmd) => match env_cmd.sub_command { + EnvSubCommand::Create => executor::create_env(&config)?, + EnvSubCommand::Clean => executor::clean_env(&config)?, + }, + ActionType::Clean => { + executor::clean(&config)?; + } + } + + Ok(()) +} diff --git a/crates/cli/src/update.rs b/crates/cli/src/update.rs new file mode 100644 index 00000000..5d89c1b7 --- /dev/null +++ b/crates/cli/src/update.rs @@ -0,0 +1,60 @@ +use crate::commands::UpdateCommand; +use log::info; +use pkg_builder_update::{run_update, UpdateConfig}; +use std::path::Path; + +pub fn run(cmd: &UpdateCommand, config_path: &str) -> Result<(), Box> { + let config_dir = Path::new(config_path); + let config_dir = if config_dir.is_file() { + config_dir.parent().unwrap_or(Path::new(".")) + } else { + config_dir + }; + + let update_cfg = UpdateConfig { + version: cmd.version.clone(), + revision: cmd.revision.clone().unwrap_or_else(|| "1".to_string()), + changelog_msg: cmd.changelog_msg.clone(), + github_repo: cmd.github_repo.clone(), + in_place: cmd.in_place, + output: cmd.output.clone(), + hash: cmd.hash.clone(), + git_commit: cmd.git_commit.clone(), + skip_download: cmd.skip_download, + update_runtime: cmd.update_runtime, + skip_patch_check: cmd.skip_patch_check, + }; + + let summary = run_update(config_dir, &update_cfg)?; + + println!(); + println!( + "Updated {} -> {} (revision {})", + summary.old_version, summary.new_version, summary.new_revision + ); + + if let Some(ref hash) = summary.source_hash { + println!("Source hash: {}", hash); + } + if let Some(ref commit) = summary.git_commit { + println!("Git commit: {}", commit); + } + if summary.runtime_updated { + println!("Runtime: updated"); + } + + if !summary.files_modified.is_empty() { + println!("Files updated:"); + for f in &summary.files_modified { + println!(" {}", f); + } + } + + if let Some(ref patch_summary) = summary.patch_summary { + println!("Patches: {}", patch_summary); + } + + info!("Output directory: {}", summary.output_dir.display()); + + Ok(()) +} diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml new file mode 100644 index 00000000..ea89bb38 --- /dev/null +++ b/crates/config/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "pkg-builder-config" +version = "0.4.0-rc.1" +edition = "2021" +license.workspace = true + +[lib] +name = "config" +path = "src/lib.rs" + +[dependencies] +serde = { workspace = true } +thiserror = { workspace = true } +log = { workspace = true } +toml = { workspace = true } +semver = { workspace = true } +url = { version = "2.4.1", features = ["serde"] } +shellexpand = { workspace = true } +sha2 = { workspace = true } + +[dev-dependencies] +tempfile = { workspace = true } +serde_json = "1.0" diff --git a/crates/config/src/build_env.rs b/crates/config/src/build_env.rs new file mode 100644 index 00000000..940339d0 --- /dev/null +++ b/crates/config/src/build_env.rs @@ -0,0 +1,454 @@ +use std::fmt; +use std::path::PathBuf; + +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum DistributionError { + #[error("Unsupported distribution codename: {0}")] + UnsupportedCodename(String), +} + +/// Supported Linux distributions. +#[derive(Debug, Clone, PartialEq)] +pub enum Distribution { + Debian(DebianCodename), + Ubuntu(UbuntuCodename), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum DebianCodename { + Bookworm, + Trixie, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum UbuntuCodename { + Noble, +} + +impl DebianCodename { + pub fn as_str(&self) -> &'static str { + match self { + DebianCodename::Bookworm => "bookworm", + DebianCodename::Trixie => "trixie", + } + } +} + +impl UbuntuCodename { + /// The canonical short codename (e.g. "noble"), used for serialization, + /// directory names, and all internal references. + pub fn as_str(&self) -> &'static str { + match self { + UbuntuCodename::Noble => "noble", + } + } + + pub fn as_short(&self) -> &'static str { + self.as_str() + } + + /// The full Ubuntu release name (e.g. "noble numbat"), for display only. + pub fn as_full(&self) -> &'static str { + match self { + UbuntuCodename::Noble => "noble numbat", + } + } +} + +impl fmt::Display for DebianCodename { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl fmt::Display for UbuntuCodename { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl Distribution { + pub fn bookworm() -> Self { + Distribution::Debian(DebianCodename::Bookworm) + } + + pub fn trixie() -> Self { + Distribution::Debian(DebianCodename::Trixie) + } + + pub fn noble() -> Self { + Distribution::Ubuntu(UbuntuCodename::Noble) + } + + pub fn from_codename(codename: &str) -> Result { + match codename { + "bookworm" => Ok(Self::bookworm()), + "trixie" => Ok(Self::trixie()), + "noble" | "noble numbat" => Ok(Self::noble()), + _ => Err(DistributionError::UnsupportedCodename(codename.to_string())), + } + } + + pub fn as_short(&self) -> &str { + match self { + Distribution::Debian(c) => c.as_str(), + Distribution::Ubuntu(c) => c.as_short(), + } + } + + pub fn codename(&self) -> &str { + self.as_short() + } + + pub fn repo_url(&self) -> &str { + match self { + Distribution::Debian(_) => "http://deb.debian.org/debian", + Distribution::Ubuntu(_) => "http://archive.ubuntu.com/ubuntu", + } + } + + pub fn keyring(&self) -> &str { + match self { + Distribution::Debian(_) => "/usr/share/keyrings/debian-archive-keyring.gpg", + Distribution::Ubuntu(_) => "/usr/share/keyrings/ubuntu-archive-keyring.gpg", + } + } + + /// Extra chroot-setup-commands needed for this distribution. + pub fn extra_chroot_commands(&self) -> Vec { + match self { + Distribution::Ubuntu(UbuntuCodename::Noble) => vec![ + "apt install -y software-properties-common".to_string(), + "add-apt-repository universe".to_string(), + "add-apt-repository restricted".to_string(), + "add-apt-repository multiverse".to_string(), + "apt update".to_string(), + ], + _ => vec![], + } + } + + pub fn is_ubuntu(&self) -> bool { + matches!(self, Distribution::Ubuntu(_)) + } + + pub fn is_debian(&self) -> bool { + matches!(self, Distribution::Debian(_)) + } +} + +impl AsRef for Distribution { + fn as_ref(&self) -> &str { + match self { + Distribution::Debian(c) => c.as_str(), + Distribution::Ubuntu(c) => c.as_str(), + } + } +} + +impl fmt::Display for Distribution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Distribution::Debian(c) => c.fmt(f), + Distribution::Ubuntu(c) => c.fmt(f), + } + } +} + +impl Serialize for Distribution { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_ref()) + } +} + +impl<'de> Deserialize<'de> for Distribution { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let codename = String::deserialize(deserializer)?; + Distribution::from_codename(&codename).map_err(|e| de::Error::custom(e.to_string())) + } +} + +/// Target architecture. +#[derive(Debug, Clone, PartialEq)] +pub enum Architecture { + Amd64, +} + +impl fmt::Display for Architecture { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Architecture::Amd64 => write!(f, "amd64"), + } + } +} + +impl<'de> Deserialize<'de> for Architecture { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "amd64" => Ok(Architecture::Amd64), + _ => Err(de::Error::custom(format!( + "Unsupported architecture: {}", + s + ))), + } + } +} + +/// Build environment configuration. +#[derive(Debug, Clone)] +pub struct BuildEnv { + pub distribution: Distribution, + pub arch: Architecture, + pub pkg_builder_version: String, + pub chroot_dir: PathBuf, + pub workdir: PathBuf, + pub tool_versions: ToolVersions, + pub snapshot_date: Option, + pub snapshot_security_date: Option, +} + +impl BuildEnv { + /// Returns the repo URL, using snapshot.debian.org when a snapshot date is set. + pub fn repo_url(&self) -> String { + match &self.snapshot_date { + Some(date) => format!("http://snapshot.debian.org/archive/debian/{}/", date), + None => self.distribution.repo_url().to_string(), + } + } + + /// Returns the security repo URL when a snapshot security date is set. + pub fn security_repo_url(&self) -> Option { + self.snapshot_security_date.as_ref().map(|date| { + format!( + "http://snapshot.debian.org/archive/debian-security/{}/", + date + ) + }) + } + + /// Whether this build env uses snapshot pinning. + pub fn uses_snapshot(&self) -> bool { + self.snapshot_date.is_some() + } +} + +#[derive(Debug, Clone)] +pub struct ToolVersions { + pub debcrafter: String, + pub sbuild: String, +} + +/// Normalize a snapshot date: accept `YYYYMMDD` (append `T000000Z`) or full `YYYYMMDDTHHMMSSZ`. +pub fn normalize_snapshot_date(date: &str) -> Result { + // Full format: YYYYMMDDTHHMMSSZ (16 chars) + if date.len() == 16 && date.chars().nth(8) == Some('T') && date.ends_with('Z') { + let digits_ok = date[..8].chars().all(|c| c.is_ascii_digit()) + && date[9..15].chars().all(|c| c.is_ascii_digit()); + if digits_ok { + return Ok(date.to_string()); + } + } + // Short format: YYYYMMDD (8 chars) + if date.len() == 8 && date.chars().all(|c| c.is_ascii_digit()) { + return Ok(format!("{}T000000Z", date)); + } + Err(format!( + "Invalid snapshot date '{}': expected YYYYMMDD or YYYYMMDDTHHMMSSZ", + date + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_distribution_from_codename() { + assert!(matches!( + Distribution::from_codename("bookworm"), + Ok(Distribution::Debian(DebianCodename::Bookworm)) + )); + assert!(matches!( + Distribution::from_codename("noble"), + Ok(Distribution::Ubuntu(UbuntuCodename::Noble)) + )); + assert!(matches!( + Distribution::from_codename("noble numbat"), + Ok(Distribution::Ubuntu(UbuntuCodename::Noble)) + )); + assert!(matches!( + Distribution::from_codename("trixie"), + Ok(Distribution::Debian(DebianCodename::Trixie)) + )); + assert!(Distribution::from_codename("unknown").is_err()); + } + + #[test] + fn test_distribution_as_short() { + assert_eq!(Distribution::bookworm().as_short(), "bookworm"); + assert_eq!(Distribution::trixie().as_short(), "trixie"); + assert_eq!(Distribution::noble().as_short(), "noble"); + } + + #[test] + fn test_distribution_repo_url() { + assert_eq!( + Distribution::bookworm().repo_url(), + "http://deb.debian.org/debian" + ); + assert_eq!( + Distribution::trixie().repo_url(), + "http://deb.debian.org/debian" + ); + assert_eq!( + Distribution::noble().repo_url(), + "http://archive.ubuntu.com/ubuntu" + ); + } + + #[test] + fn test_distribution_keyring() { + assert!(Distribution::bookworm() + .keyring() + .contains("debian-archive-keyring")); + assert!(Distribution::trixie() + .keyring() + .contains("debian-archive-keyring")); + assert!(Distribution::noble() + .keyring() + .contains("ubuntu-archive-keyring")); + } + + #[test] + fn test_noble_has_extra_chroot_commands() { + let cmds = Distribution::noble().extra_chroot_commands(); + assert!(!cmds.is_empty()); + assert!(cmds + .iter() + .any(|c| c.contains("software-properties-common"))); + assert!(cmds.iter().any(|c| c.contains("universe"))); + assert!(cmds.iter().any(|c| c.contains("multiverse"))); + } + + #[test] + fn test_bookworm_no_extra_chroot_commands() { + assert!(Distribution::bookworm().extra_chroot_commands().is_empty()); + } + + #[test] + fn test_trixie_no_extra_chroot_commands() { + assert!(Distribution::trixie().extra_chroot_commands().is_empty()); + } + + #[test] + fn test_is_ubuntu_debian() { + assert!(Distribution::noble().is_ubuntu()); + assert!(!Distribution::noble().is_debian()); + assert!(Distribution::bookworm().is_debian()); + assert!(!Distribution::bookworm().is_ubuntu()); + assert!(Distribution::trixie().is_debian()); + assert!(!Distribution::trixie().is_ubuntu()); + } + + #[test] + fn test_distribution_serde_roundtrip() { + let json = serde_json::to_string(&Distribution::bookworm()).unwrap(); + assert_eq!(json, "\"bookworm\""); + + // Deserialize via serde_json as a proxy + let dist: Distribution = serde_json::from_str("\"noble\"").unwrap(); + assert!(matches!(dist, Distribution::Ubuntu(UbuntuCodename::Noble))); + } + + #[test] + fn test_architecture_display() { + assert_eq!(Architecture::Amd64.to_string(), "amd64"); + } + + fn test_build_env( + snapshot_date: Option<&str>, + snapshot_security_date: Option<&str>, + ) -> BuildEnv { + BuildEnv { + distribution: Distribution::bookworm(), + arch: Architecture::Amd64, + pkg_builder_version: "0.3.1".to_string(), + chroot_dir: PathBuf::from("/tmp/cache"), + workdir: PathBuf::from("/tmp/work"), + tool_versions: ToolVersions { + debcrafter: "8189263".to_string(), + sbuild: "0.85.6".to_string(), + }, + snapshot_date: snapshot_date.map(String::from), + snapshot_security_date: snapshot_security_date.map(String::from), + } + } + + #[test] + fn test_repo_url_without_snapshot() { + let env = test_build_env(None, None); + assert_eq!(env.repo_url(), "http://deb.debian.org/debian"); + assert!(!env.uses_snapshot()); + } + + #[test] + fn test_repo_url_with_snapshot() { + let env = test_build_env(Some("20250101T000000Z"), None); + assert_eq!( + env.repo_url(), + "http://snapshot.debian.org/archive/debian/20250101T000000Z/" + ); + assert!(env.uses_snapshot()); + } + + #[test] + fn test_security_repo_url_without_snapshot() { + let env = test_build_env(None, None); + assert!(env.security_repo_url().is_none()); + } + + #[test] + fn test_security_repo_url_with_snapshot() { + let env = test_build_env(Some("20250101T000000Z"), Some("20250115T000000Z")); + assert_eq!( + env.security_repo_url().unwrap(), + "http://snapshot.debian.org/archive/debian-security/20250115T000000Z/" + ); + } + + #[test] + fn test_normalize_snapshot_date_full() { + assert_eq!( + normalize_snapshot_date("20250101T120000Z").unwrap(), + "20250101T120000Z" + ); + } + + #[test] + fn test_normalize_snapshot_date_short() { + assert_eq!( + normalize_snapshot_date("20250101").unwrap(), + "20250101T000000Z" + ); + } + + #[test] + fn test_normalize_snapshot_date_invalid() { + assert!(normalize_snapshot_date("2025-01-01").is_err()); + assert!(normalize_snapshot_date("abc").is_err()); + assert!(normalize_snapshot_date("").is_err()); + } +} diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs new file mode 100644 index 00000000..65cb890c --- /dev/null +++ b/crates/config/src/lib.rs @@ -0,0 +1,645 @@ +pub mod build_env; +pub mod package; +pub mod runtime; +pub mod source; +pub mod validation; +pub mod verify; + +use std::path::{Path, PathBuf}; + +use build_env::BuildEnv; +use package::PackageFields; +use runtime::RuntimeConfig; +use source::SourceKind; +use thiserror::Error; +use validation::validate_and_normalize; +use verify::VerifyConfig; + +/// The main configuration struct, parsed from pkg-builder.toml. +/// Parsed once, validated once, immutable after construction. +#[derive(Debug, Clone)] +pub struct PkgConfig { + pub package: PackageFields, + pub source: SourceKind, + pub build_env: BuildEnv, + pub runtime: Option, + pub verify: Option, + /// Root directory of the config file (for resolving relative paths) + pub config_root: PathBuf, +} + +#[derive(Debug, Error)] +pub enum ConfigError { + #[error("Failed to read config at {path}: {source}")] + ReadError { + path: PathBuf, + source: std::io::Error, + }, + #[error("Failed to parse config at {path}: {source}")] + ParseError { + path: PathBuf, + source: toml::de::Error, + }, + #[error("Validation error: {0}")] + Validation(String), +} + +/// Name of the default configuration file +pub const CONFIG_FILE_NAME: &str = "pkg-builder.toml"; +pub const WORKDIR_ROOT: &str = "~/.pkg-builder/packages"; + +impl PkgConfig { + /// Single entry point: load, parse, validate, resolve paths. + pub fn load(path: impl AsRef) -> Result { + let path = path.as_ref(); + let config_path = if path.is_dir() { + path.join(CONFIG_FILE_NAME) + } else { + path.to_path_buf() + }; + + let content = + std::fs::read_to_string(&config_path).map_err(|e| ConfigError::ReadError { + path: config_path.clone(), + source: e, + })?; + + let raw: RawConfig = toml::from_str(&content).map_err(|e| ConfigError::ParseError { + path: config_path.clone(), + source: e, + })?; + + let config_root = config_path.parent().unwrap_or(Path::new(".")).to_path_buf(); + + let mut config = raw.into_pkg_config(config_root)?; + + validate_and_normalize(&mut config)?; + + // Resolve paths after validation + config.resolve_paths(); + + Ok(config) + } + + /// Resolve relative paths to absolute paths using config_root. + fn resolve_paths(&mut self) { + // Resolve workdir + if self.build_env.workdir.as_os_str().is_empty() { + let default = format!( + "{}/{}", + WORKDIR_ROOT, + self.build_env.distribution.as_short() + ); + self.build_env.workdir = PathBuf::from(default); + } + self.build_env.workdir = expand_path(&self.build_env.workdir, None); + + // Resolve spec relative to config root + if self.package.spec.is_relative() { + self.package.spec = self.config_root.join(&self.package.spec); + } + + // Resolve tarball URL if it's a local path + if let SourceKind::Tarball { ref mut url, .. } = self.source { + if !url.starts_with("http") { + let resolved = expand_path(&PathBuf::from(&*url), Some(&self.config_root)); + *url = resolved.display().to_string(); + } + } + + // Resolve chroot_dir + self.build_env.chroot_dir = expand_path(&self.build_env.chroot_dir, None); + } +} + +/// Expand a path: handle ~, relative paths. +pub fn expand_path(path: &Path, relative_to: Option<&Path>) -> PathBuf { + let path_str = path.to_string_lossy(); + if path_str.starts_with('~') { + let expanded = shellexpand::tilde(&path_str).to_string(); + PathBuf::from(expanded) + } else if path.is_relative() { + if let Some(base) = relative_to { + base.join(path) + } else { + path.to_path_buf() + } + } else { + path.to_path_buf() + } +} + +// ---- Raw deserialization types (internal) ---- + +/// Raw TOML structure matching the new flat config format. +#[derive(Debug, serde::Deserialize)] +struct RawConfig { + package: PackageFields, + source: RawSource, + build: RawBuild, + #[serde(default)] + runtime: Option, + tools: RawTools, + #[serde(default)] + verify: Option, +} + +#[derive(Debug, serde::Deserialize)] +#[serde(tag = "type", rename_all = "lowercase")] +enum RawSource { + Tarball { + url: String, + #[serde(default)] + hash: Option, + }, + Git { + url: String, + tag: String, + #[serde(default)] + submodules: Vec, + }, + Virtual, +} + +#[derive(Debug, serde::Deserialize)] +struct RawBuild { + distribution: build_env::Distribution, + arch: build_env::Architecture, + #[serde(default)] + workdir: PathBuf, + #[serde(default)] + chroot_dir: Option, + #[serde(default)] + snapshot_date: Option, + #[serde(default)] + snapshot_security_date: Option, +} + +#[derive(Debug, serde::Deserialize)] +struct RawTools { + pkg_builder: String, + debcrafter: String, + sbuild: String, +} + +impl RawConfig { + fn into_pkg_config(self, config_root: PathBuf) -> Result { + let source = match self.source { + RawSource::Tarball { url, hash } => SourceKind::Tarball { url, hash }, + RawSource::Git { + url, + tag, + submodules, + } => SourceKind::Git { + url, + tag, + submodules, + }, + RawSource::Virtual => SourceKind::Virtual, + }; + + let build_env = BuildEnv { + distribution: self.build.distribution, + arch: self.build.arch, + pkg_builder_version: self.tools.pkg_builder, + chroot_dir: self + .build + .chroot_dir + .unwrap_or_else(|| PathBuf::from("~/.cache/sbuild")), + workdir: self.build.workdir, + tool_versions: build_env::ToolVersions { + debcrafter: self.tools.debcrafter, + sbuild: self.tools.sbuild, + }, + snapshot_date: self.build.snapshot_date, + snapshot_security_date: self.build.snapshot_security_date, + }; + + Ok(PkgConfig { + package: self.package, + source, + build_env, + runtime: self.runtime, + verify: self.verify, + config_root, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + fn write_config(dir: &Path, content: &str) { + fs::write(dir.join(CONFIG_FILE_NAME), content).unwrap(); + } + + fn base_default_config() -> &'static str { + r#" +[package] +name = "hello" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "hello.sss" + +[source] +type = "tarball" +url = "https://example.com/hello-1.0.0.tar.gz" +hash = "abc123" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"# + } + + #[test] + fn test_load_default_package() { + let dir = tempdir().unwrap(); + write_config(dir.path(), base_default_config()); + + let config = PkgConfig::load(dir.path()).unwrap(); + assert_eq!(config.package.name, "hello"); + assert!(matches!(config.source, SourceKind::Tarball { .. })); + assert!(matches!( + config.build_env.distribution, + build_env::Distribution::Debian(_) + )); + } + + #[test] + fn test_load_virtual_package() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test-virtual" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "virtual" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + assert!(matches!(config.source, SourceKind::Virtual)); + } + + #[test] + fn test_load_git_package() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test-git" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "git" +url = "https://github.com/example/repo.git" +tag = "v1.0.0" +submodules = [] + +[build] +distribution = "noble" +arch = "amd64" +workdir = "/tmp/test" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "abc123" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + assert!(matches!(config.source, SourceKind::Git { .. })); + assert!(config.runtime.is_some()); + assert_eq!(config.runtime.as_ref().unwrap().profile, "go"); + } + + #[test] + fn test_load_by_file_path() { + let dir = tempdir().unwrap(); + let file_path = dir.path().join("custom-name.toml"); + fs::write(&file_path, base_default_config()).unwrap(); + + let config = PkgConfig::load(&file_path).unwrap(); + assert_eq!(config.package.name, "hello"); + } + + #[test] + fn test_load_nonexistent_file() { + let result = PkgConfig::load("/nonexistent/path/pkg-builder.toml"); + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), ConfigError::ReadError { .. })); + } + + #[test] + fn test_load_invalid_toml() { + let dir = tempdir().unwrap(); + fs::write(dir.path().join(CONFIG_FILE_NAME), "invalid toml {{{").unwrap(); + + let result = PkgConfig::load(dir.path()); + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + ConfigError::ParseError { .. } + )); + } + + #[test] + fn test_cache_dir_defaults_to_sbuild_cache() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "virtual" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + let cache_str = config.build_env.chroot_dir.display().to_string(); + assert!( + cache_str.contains(".cache/sbuild"), + "Expected default cache dir, got: {}", + cache_str + ); + } + + #[test] + fn test_cache_dir_overridden() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "virtual" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" +chroot_dir = "/custom/cache" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + assert_eq!(config.build_env.chroot_dir, PathBuf::from("/custom/cache")); + } + + #[test] + fn test_tarball_url_http_unchanged() { + let dir = tempdir().unwrap(); + write_config(dir.path(), base_default_config()); + + let config = PkgConfig::load(dir.path()).unwrap(); + match &config.source { + SourceKind::Tarball { url, .. } => { + assert_eq!(url, "https://example.com/hello-1.0.0.tar.gz"); + } + _ => panic!("Expected Tarball"), + } + } + + #[test] + fn test_tarball_url_local_resolved() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "tarball" +url = "test.tar.gz" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + match &config.source { + SourceKind::Tarball { url, .. } => { + assert!( + url.ends_with("test.tar.gz"), + "URL should end with filename: {}", + url + ); + assert!( + url.contains(dir.path().to_str().unwrap()), + "URL should contain config root: {}", + url + ); + } + _ => panic!("Expected Tarball"), + } + } + + #[test] + fn test_spec_resolved_relative_to_config_root() { + let dir = tempdir().unwrap(); + write_config(dir.path(), base_default_config()); + + let config = PkgConfig::load(dir.path()).unwrap(); + assert!( + config.package.spec.is_absolute(), + "spec should be absolute: {:?}", + config.package.spec + ); + assert!(config + .package + .spec + .display() + .to_string() + .ends_with("hello.sss")); + } + + #[test] + fn test_expand_path_tilde() { + let result = expand_path(Path::new("~/test"), None); + assert!(!result.to_string_lossy().starts_with('~')); + assert!(result.to_string_lossy().ends_with("test")); + } + + #[test] + fn test_expand_path_absolute() { + let result = expand_path(Path::new("/absolute/path"), None); + assert_eq!(result, PathBuf::from("/absolute/path")); + } + + #[test] + fn test_expand_path_relative_with_base() { + let result = expand_path(Path::new("relative/file.txt"), Some(Path::new("/base/dir"))); + assert_eq!(result, PathBuf::from("/base/dir/relative/file.txt")); + } + + #[test] + fn test_expand_path_relative_without_base() { + let result = expand_path(Path::new("relative/file.txt"), None); + assert_eq!(result, PathBuf::from("relative/file.txt")); + } + + #[test] + fn test_runtime_with_vars() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test-go" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "tarball" +url = "https://example.com/test.tar.gz" +hash = "abc123" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + let rt = config.runtime.as_ref().unwrap(); + assert_eq!(rt.profile, "go"); + assert_eq!( + rt.vars.get("binary_url").and_then(|v| v.as_str()), + Some("https://go.dev/dl/go1.22.2.linux-amd64.tar.gz") + ); + } + + #[test] + fn test_runtime_with_packages_list() { + let dir = tempdir().unwrap(); + write_config( + dir.path(), + r#" +[package] +name = "test-dotnet" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "tarball" +url = "https://example.com/test.tar.gz" +hash = "abc123" + +[build] +distribution = "noble" +arch = "amd64" +workdir = "/tmp/test" + +[runtime] +recipe = "dotnet-backup" +packages = [ + { name = "pkg-a", hash = "aaa", url = "http://a" }, + { name = "pkg-b", hash = "bbb", url = "http://b" }, +] + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ); + + let config = PkgConfig::load(dir.path()).unwrap(); + let rt = config.runtime.as_ref().unwrap(); + assert_eq!(rt.profile, "dotnet-backup"); + let pkgs = rt.vars.get("packages").unwrap().as_array().unwrap(); + assert_eq!(pkgs.len(), 2); + } +} diff --git a/crates/config/src/package.rs b/crates/config/src/package.rs new file mode 100644 index 00000000..f5ef61f9 --- /dev/null +++ b/crates/config/src/package.rs @@ -0,0 +1,13 @@ +use std::path::PathBuf; + +use serde::Deserialize; + +/// Package metadata fields from the [package] section. +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct PackageFields { + pub name: String, + pub version: String, + pub revision: String, + pub homepage: String, + pub spec: PathBuf, +} diff --git a/crates/config/src/runtime.rs b/crates/config/src/runtime.rs new file mode 100644 index 00000000..67705d97 --- /dev/null +++ b/crates/config/src/runtime.rs @@ -0,0 +1,23 @@ +use std::collections::BTreeMap; + +use serde::Deserialize; + +/// Runtime configuration from the [runtime] section. +/// The `profile` field selects the runtime .mk profile. +/// `recipe` is accepted as a deprecated alias for `profile`. +/// All other fields are passed as variables to the runtime Perl template. +#[derive(Debug, Clone, Deserialize)] +pub struct RuntimeConfig { + #[serde(alias = "recipe")] + pub profile: String, + #[serde(flatten)] + pub vars: BTreeMap, +} + +impl RuntimeConfig { + /// Alias for backwards compatibility — code that previously used `.recipe` + /// can use this accessor during the migration period. + pub fn recipe(&self) -> &str { + &self.profile + } +} diff --git a/crates/config/src/source.rs b/crates/config/src/source.rs new file mode 100644 index 00000000..15a59fd4 --- /dev/null +++ b/crates/config/src/source.rs @@ -0,0 +1,22 @@ +use serde::Deserialize; + +/// The kind of source for a package. +#[derive(Debug, Clone)] +pub enum SourceKind { + Tarball { + url: String, + hash: Option, + }, + Git { + url: String, + tag: String, + submodules: Vec, + }, + Virtual, +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct Submodule { + pub commit: String, + pub path: String, +} diff --git a/crates/config/src/validation.rs b/crates/config/src/validation.rs new file mode 100644 index 00000000..0b6a941b --- /dev/null +++ b/crates/config/src/validation.rs @@ -0,0 +1,237 @@ +use crate::build_env::normalize_snapshot_date; +use crate::{ConfigError, PkgConfig}; + +/// Validate the entire configuration. +pub fn validate_and_normalize(config: &mut PkgConfig) -> Result<(), ConfigError> { + if config.package.name.is_empty() { + return Err(ConfigError::Validation( + "package name cannot be empty".into(), + )); + } + + if config.package.version.is_empty() { + return Err(ConfigError::Validation( + "package version cannot be empty".into(), + )); + } + + if config.package.revision.is_empty() { + return Err(ConfigError::Validation( + "package revision cannot be empty".into(), + )); + } + + validate_source_fields(config)?; + validate_snapshot_config(config)?; + + Ok(()) +} + +/// Characters that are unsafe in shell contexts (command injection). +const SHELL_UNSAFE: &[char] = &[ + ';', '&', '|', '$', '`', '(', ')', '{', '}', '<', '>', '!', '#', '\'', '"', '\\', '\n', '\r', + '\0', +]; + +/// Validate that a string contains no shell metacharacters. +fn validate_safe_shell_value(field: &str, value: &str) -> Result<(), ConfigError> { + if let Some(c) = value.chars().find(|c| SHELL_UNSAFE.contains(c)) { + return Err(ConfigError::Validation(format!( + "{} contains unsafe character '{}' — only alphanumeric, dots, hyphens, underscores, slashes, colons, and @ are allowed", + field, c + ))); + } + Ok(()) +} + +/// Validate that a URL contains no shell metacharacters (allows :// and query strings). +fn validate_safe_url(field: &str, value: &str) -> Result<(), ConfigError> { + // URLs may contain ? = & % + but not shell-dangerous chars like ; | ` $ ( ) { } etc. + const URL_UNSAFE: &[char] = &[ + ';', '|', '`', '(', ')', '{', '}', '<', '>', '!', '\'', '"', '\\', '\n', '\r', '\0', + ]; + if let Some(c) = value.chars().find(|c| URL_UNSAFE.contains(c)) { + return Err(ConfigError::Validation(format!( + "{} contains unsafe character '{}' — URLs must not contain shell metacharacters", + field, c + ))); + } + Ok(()) +} + +/// Validate source-related fields that flow into shell commands during the build pipeline. +fn validate_source_fields(config: &PkgConfig) -> Result<(), ConfigError> { + use crate::source::SourceKind; + + // Package fields + validate_safe_shell_value("package.name", &config.package.name)?; + validate_safe_shell_value("package.version", &config.package.version)?; + validate_safe_shell_value("package.revision", &config.package.revision)?; + validate_safe_url("package.homepage", &config.package.homepage)?; + + match &config.source { + SourceKind::Tarball { url, hash } => { + validate_safe_url("source.url", url)?; + if let Some(ref h) = hash { + validate_safe_shell_value("source.hash", h)?; + } + } + SourceKind::Git { + url, + tag, + submodules, + } => { + validate_safe_url("source.url", url)?; + validate_safe_shell_value("source.tag", tag)?; + for (i, sub) in submodules.iter().enumerate() { + validate_safe_shell_value(&format!("source.submodules[{}].path", i), &sub.path)?; + if sub.path.contains("..") { + return Err(ConfigError::Validation(format!( + "source.submodules[{}].path must not contain '..'", + i + ))); + } + validate_safe_shell_value( + &format!("source.submodules[{}].commit", i), + &sub.commit, + )?; + } + } + SourceKind::Virtual => {} + } + + Ok(()) +} + +fn validate_snapshot_config(config: &mut PkgConfig) -> Result<(), ConfigError> { + let has_snapshot = config.build_env.snapshot_date.is_some(); + let has_security = config.build_env.snapshot_security_date.is_some(); + + if !has_snapshot && !has_security { + return Ok(()); + } + + // snapshot_security_date requires snapshot_date + if has_security && !has_snapshot { + return Err(ConfigError::Validation( + "snapshot_security_date requires snapshot_date to be set".into(), + )); + } + + // Snapshots are Debian-only + if config.build_env.distribution.is_ubuntu() { + return Err(ConfigError::Validation( + "snapshot_date is only supported for Debian distributions (Ubuntu has no public snapshot service)".into(), + )); + } + + // Validate and normalize dates + if let Some(ref date) = config.build_env.snapshot_date { + let normalized = normalize_snapshot_date(date).map_err(|e| ConfigError::Validation(e))?; + config.build_env.snapshot_date = Some(normalized); + } + if let Some(ref date) = config.build_env.snapshot_security_date { + let normalized = normalize_snapshot_date(date).map_err(|e| ConfigError::Validation(e))?; + config.build_env.snapshot_security_date = Some(normalized); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::build_env::*; + use crate::package::PackageFields; + use crate::source::SourceKind; + use std::path::PathBuf; + + fn test_config_with_snapshot( + distribution: Distribution, + snapshot_date: Option<&str>, + snapshot_security_date: Option<&str>, + ) -> PkgConfig { + PkgConfig { + package: PackageFields { + spec: "test.sss".into(), + name: "test".to_string(), + version: "1.0.0".to_string(), + revision: "1".to_string(), + homepage: "https://example.com".to_string(), + }, + source: SourceKind::Virtual, + build_env: BuildEnv { + distribution, + arch: Architecture::Amd64, + pkg_builder_version: "0.3.1".to_string(), + chroot_dir: PathBuf::from("/tmp/cache"), + workdir: PathBuf::from("/tmp/work"), + tool_versions: ToolVersions { + debcrafter: "8189263".to_string(), + sbuild: "0.85.6".to_string(), + }, + snapshot_date: snapshot_date.map(String::from), + snapshot_security_date: snapshot_security_date.map(String::from), + }, + runtime: None, + verify: None, + config_root: PathBuf::from("/test"), + } + } + + #[test] + fn test_no_snapshot_passes() { + let mut cfg = test_config_with_snapshot(Distribution::bookworm(), None, None); + assert!(validate_and_normalize(&mut cfg).is_ok()); + } + + #[test] + fn test_debian_snapshot_passes() { + let mut cfg = + test_config_with_snapshot(Distribution::bookworm(), Some("20250101T000000Z"), None); + assert!(validate_and_normalize(&mut cfg).is_ok()); + } + + #[test] + fn test_debian_snapshot_short_date_normalized() { + let mut cfg = test_config_with_snapshot(Distribution::bookworm(), Some("20250101"), None); + assert!(validate_and_normalize(&mut cfg).is_ok()); + assert_eq!( + cfg.build_env.snapshot_date.as_deref(), + Some("20250101T000000Z") + ); + } + + #[test] + fn test_ubuntu_snapshot_rejected() { + let mut cfg = + test_config_with_snapshot(Distribution::noble(), Some("20250101T000000Z"), None); + let err = validate_and_normalize(&mut cfg).unwrap_err(); + assert!(err.to_string().contains("Ubuntu")); + } + + #[test] + fn test_security_without_main_rejected() { + let mut cfg = + test_config_with_snapshot(Distribution::bookworm(), None, Some("20250101T000000Z")); + let err = validate_and_normalize(&mut cfg).unwrap_err(); + assert!(err.to_string().contains("snapshot_security_date requires")); + } + + #[test] + fn test_invalid_date_rejected() { + let mut cfg = test_config_with_snapshot(Distribution::bookworm(), Some("2025-01-01"), None); + let err = validate_and_normalize(&mut cfg).unwrap_err(); + assert!(err.to_string().contains("Invalid snapshot date")); + } + + #[test] + fn test_both_snapshot_dates_pass() { + let mut cfg = test_config_with_snapshot( + Distribution::bookworm(), + Some("20250101T000000Z"), + Some("20250115T000000Z"), + ); + assert!(validate_and_normalize(&mut cfg).is_ok()); + } +} diff --git a/crates/config/src/verify.rs b/crates/config/src/verify.rs new file mode 100644 index 00000000..8378e722 --- /dev/null +++ b/crates/config/src/verify.rs @@ -0,0 +1,90 @@ +use serde::Deserialize; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::{BufReader, Read}; +use std::path::Path; + +use crate::PkgConfig; + +/// Hash entry for a package file. +#[derive(Debug, Clone, Deserialize)] +pub struct PackageHash { + pub name: String, + pub hash: String, +} + +/// Verification configuration, containing expected hashes. +#[derive(Debug, Clone, Deserialize)] +pub struct VerifyConfig { + pub package_hash: Vec, +} + +/// Verify that built package artifacts match the expected SHA-256 hashes. +/// +/// Returns `Ok(())` if all hashes match, or an error listing all mismatches. +pub fn verify_hashes(config: &PkgConfig) -> Result<(), Box> { + let verify_config = config + .verify + .as_ref() + .ok_or("No [verify] section in pkg-builder.toml")?; + + let pkg = &config.package; + let artifacts_dir = config + .build_env + .workdir + .join(format!("{}-{}-{}", pkg.name, pkg.version, pkg.revision)); + + verify_hashes_in_dir(verify_config, &artifacts_dir) +} + +/// Compute SHA-256 hash of a file using streaming reads. +fn sha256_file(path: &Path) -> Result { + let file = File::open(path)?; + let mut reader = BufReader::with_capacity(8192, file); + let mut hasher = Sha256::new(); + let mut buf = [0u8; 8192]; + loop { + let n = reader.read(&mut buf)?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + Ok(hasher + .finalize() + .iter() + .map(|b| format!("{:02x}", b)) + .collect()) +} + +/// Verify package hashes against files in a specific directory. +pub fn verify_hashes_in_dir( + verify_config: &VerifyConfig, + artifacts_dir: &Path, +) -> Result<(), Box> { + let mut errors = Vec::new(); + + for pkg_hash in &verify_config.package_hash { + let file_path = artifacts_dir.join(&pkg_hash.name); + + if !file_path.exists() { + errors.push(format!("Verification file missing: {}", pkg_hash.name)); + continue; + } + + let actual = sha256_file(&file_path)?; + + if actual != pkg_hash.hash { + errors.push(format!( + "SHA-256 mismatch for {}: expected {}, got {}", + pkg_hash.name, pkg_hash.hash, actual + )); + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors.join("; ").into()) + } +} diff --git a/crates/config/tests/parse_examples.rs b/crates/config/tests/parse_examples.rs new file mode 100644 index 00000000..5ce14e40 --- /dev/null +++ b/crates/config/tests/parse_examples.rs @@ -0,0 +1,332 @@ +//! Integration tests that parse every example TOML config file. + +use config::build_env::{Architecture, Distribution}; +use config::source::SourceKind; +use config::PkgConfig; +use std::path::Path; + +fn examples_dir() -> &'static Path { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .parent() + .unwrap() + .join("examples") + .leak() +} + +fn load_example(distro: &str, lang: &str, name: &str) -> PkgConfig { + let path = examples_dir().join(distro).join(lang).join(name); + PkgConfig::load(&path) + .unwrap_or_else(|e| panic!("Failed to load config at {}: {}", path.display(), e)) +} + +// ─── Bookworm examples ─── + +#[test] +fn parse_bookworm_c() { + let cfg = load_example("bookworm", "c", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-c"); + assert_eq!(cfg.package.version, "1.0.0"); + assert_eq!(cfg.package.revision, "1"); + assert!(matches!( + cfg.build_env.distribution, + Distribution::Debian(_) + )); + assert!(matches!(cfg.build_env.arch, Architecture::Amd64)); + match &cfg.source { + SourceKind::Tarball { hash, .. } => { + assert!(hash.is_some()); + } + _ => panic!("Expected Tarball source"), + } + assert!(cfg.runtime.is_none()); // C has no runtime +} + +#[test] +fn parse_bookworm_rust() { + let cfg = load_example("bookworm", "rust", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-rust"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "rust"); + assert!(rt.vars.contains_key("binary_url")); + assert!(rt.vars.contains_key("binary_gpg_asc")); +} + +#[test] +fn parse_bookworm_go() { + let cfg = load_example("bookworm", "go", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-go"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "go"); + let url = rt.vars.get("binary_url").unwrap().as_str().unwrap(); + assert!(url.contains("go.dev")); +} + +#[test] +fn parse_bookworm_java() { + let cfg = load_example("bookworm", "java", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-java"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "java"); + assert!(rt.vars.contains_key("binary_url")); +} + +#[test] +fn parse_bookworm_java_gradle() { + let cfg = load_example("bookworm", "java-gradle", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-java-gradle"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "java-gradle"); + assert!(rt.vars.contains_key("gradle_binary_url")); +} + +#[test] +fn parse_bookworm_javascript() { + let cfg = load_example("bookworm", "javascript", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-javascript"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "node"); + assert!(rt.vars.contains_key("binary_url")); + assert!(rt.vars.contains_key("yarn_version")); +} + +#[test] +fn parse_bookworm_typescript() { + let cfg = load_example("bookworm", "typescript", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-typescript"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "node"); +} + +#[test] +fn parse_bookworm_dotnet() { + let cfg = load_example("bookworm", "dotnet", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-dotnet"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "dotnet-backup"); + let pkgs = rt.vars.get("packages").unwrap().as_array().unwrap(); + assert!(pkgs.len() >= 10); +} + +#[test] +fn parse_bookworm_nim() { + let cfg = load_example("bookworm", "nim", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-nim"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "nim"); + let url = rt.vars.get("binary_url").unwrap().as_str().unwrap(); + assert!(url.contains("nim-lang.org")); +} + +#[test] +fn parse_bookworm_virtual() { + let cfg = load_example("bookworm", "virtual", "hello-world"); + assert_eq!(cfg.package.name, "test-virtual-package"); + assert!(matches!(cfg.source, SourceKind::Virtual)); + assert!(cfg.runtime.is_none()); +} + +#[test] +fn parse_bookworm_git_nimbus() { + let cfg = load_example("bookworm", "git-package", "nimbus"); + assert_eq!(cfg.package.name, "hello-world-git-nim"); + match &cfg.source { + SourceKind::Git { + url, + tag, + submodules, + } => { + assert!(url.contains("nimbus-eth2")); + assert_eq!(tag, "v24.3.0"); + assert!(!submodules.is_empty()); + assert!(submodules.len() > 40); + } + _ => panic!("Expected Git source"), + } + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "nim"); +} + +// ─── Trixie examples ─── + +#[test] +fn parse_trixie_c() { + let cfg = load_example("trixie", "c", "hello-world"); + assert!(matches!( + cfg.build_env.distribution, + Distribution::Debian(_) + )); + assert_eq!(cfg.build_env.distribution.as_short(), "trixie"); + assert!(cfg.runtime.is_none()); +} + +#[test] +fn parse_trixie_rust() { + let cfg = load_example("trixie", "rust", "hello-world"); + assert_eq!(cfg.build_env.distribution.as_short(), "trixie"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "rust"); +} + +#[test] +fn parse_trixie_go() { + let cfg = load_example("trixie", "go", "hello-world"); + assert_eq!(cfg.build_env.distribution.as_short(), "trixie"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "go"); +} + +#[test] +fn parse_trixie_java() { + let cfg = load_example("trixie", "java", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "java"); +} + +#[test] +fn parse_trixie_java_gradle() { + let cfg = load_example("trixie", "java-gradle", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "java-gradle"); +} + +#[test] +fn parse_trixie_javascript() { + let cfg = load_example("trixie", "javascript", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "node"); +} + +#[test] +fn parse_trixie_typescript() { + let cfg = load_example("trixie", "typescript", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "node"); +} + +#[test] +fn parse_trixie_dotnet() { + let cfg = load_example("trixie", "dotnet", "hello-world"); + assert!(cfg.runtime.as_ref().unwrap().profile.starts_with("dotnet")); +} + +#[test] +fn parse_trixie_nim() { + let cfg = load_example("trixie", "nim", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "nim"); +} + +#[test] +fn parse_trixie_virtual() { + let cfg = load_example("trixie", "virtual", "hello-world"); + assert!(matches!(cfg.source, SourceKind::Virtual)); +} + +#[test] +fn parse_trixie_git_nimbus() { + let cfg = load_example("trixie", "git-package", "nimbus"); + assert!(matches!(cfg.source, SourceKind::Git { .. })); +} + +// ─── Noble examples ─── + +#[test] +fn parse_noble_go() { + let cfg = load_example("noble", "go", "hello-world"); + assert!(matches!( + cfg.build_env.distribution, + Distribution::Ubuntu(_) + )); + assert_eq!(cfg.build_env.distribution.as_short(), "noble"); +} + +#[test] +fn parse_noble_rust() { + let cfg = load_example("noble", "rust", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "rust"); +} + +#[test] +fn parse_noble_dotnet9() { + let cfg = load_example("noble", "dotnet-9", "hello-world"); + assert_eq!(cfg.package.name, "hello-world-dotnet"); + let rt = cfg.runtime.as_ref().expect("Expected runtime"); + assert_eq!(rt.profile, "dotnet-backup"); + // Noble dotnet-9 has deps field + assert!(rt.vars.contains_key("deps")); +} + +#[test] +fn parse_noble_virtual() { + let cfg = load_example("noble", "virtual", "hello-world"); + assert!(matches!(cfg.source, SourceKind::Virtual)); +} + +#[test] +fn parse_noble_nim() { + let cfg = load_example("noble", "nim", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "nim"); +} + +#[test] +fn parse_noble_java() { + let cfg = load_example("noble", "java", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "java"); +} + +#[test] +fn parse_noble_javascript() { + let cfg = load_example("noble", "javascript", "hello-world"); + assert_eq!(cfg.runtime.as_ref().unwrap().profile, "node"); +} + +#[test] +fn parse_noble_git_nimbus() { + let cfg = load_example("noble", "git-package", "nimbus"); + assert!(matches!(cfg.source, SourceKind::Git { .. })); +} + +// ─── Parse ALL examples (comprehensive sweep) ─── + +#[test] +fn parse_all_pkg_builder_configs() { + let examples = examples_dir(); + let mut count = 0; + let mut failures = Vec::new(); + + for distro_entry in std::fs::read_dir(examples).unwrap() { + let distro_entry = distro_entry.unwrap(); + if !distro_entry.path().is_dir() { + continue; + } + for lang_entry in std::fs::read_dir(distro_entry.path()).unwrap() { + let lang_entry = lang_entry.unwrap(); + if !lang_entry.path().is_dir() { + continue; + } + for pkg_entry in std::fs::read_dir(lang_entry.path()).unwrap() { + let pkg_entry = pkg_entry.unwrap(); + let pkg_dir = pkg_entry.path(); + if !pkg_dir.is_dir() { + continue; + } + let config_file = pkg_dir.join("pkg-builder.toml"); + if config_file.exists() { + match PkgConfig::load(&pkg_dir) { + Ok(_) => count += 1, + Err(e) => { + failures.push(format!("{}: {}", pkg_dir.display(), e)); + } + } + } + } + } + } + + assert!( + failures.is_empty(), + "Failed to parse {} config(s):\n{}", + failures.len(), + failures.join("\n") + ); + assert!( + count >= 34, + "Expected at least 34 example configs, found {}", + count + ); +} diff --git a/crates/executor/Cargo.toml b/crates/executor/Cargo.toml new file mode 100644 index 00000000..77fc3253 --- /dev/null +++ b/crates/executor/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "pkg-builder-executor" +version = "0.4.0-rc.1" +edition.workspace = true +license.workspace = true + +[lib] +name = "executor" +path = "src/lib.rs" + +[dependencies] +pkg-builder-config = { path = "../config" } +debcrafter = { workspace = true } +reqwest = { workspace = true } +sha2 = { workspace = true } +thiserror.workspace = true +log.workspace = true +toml.workspace = true diff --git a/crates/executor/src/acquire.rs b/crates/executor/src/acquire.rs new file mode 100644 index 00000000..367bf259 --- /dev/null +++ b/crates/executor/src/acquire.rs @@ -0,0 +1,177 @@ +use std::fs; +use std::process::Command; + +use config::PkgConfig; +use log::info; + +use crate::paths::BuildPaths; +use crate::ExecutorError; + +/// Step 1: Acquire the source tarball. +pub fn acquire(config: &PkgConfig, paths: &BuildPaths) -> Result<(), ExecutorError> { + match &config.source { + config::source::SourceKind::Tarball { url, hash } => { + acquire_tarball(url, hash.as_deref(), paths)?; + } + config::source::SourceKind::Git { + url, + tag, + submodules, + } => { + acquire_git(url, tag, submodules, paths)?; + } + config::source::SourceKind::Virtual => { + acquire_virtual(paths)?; + } + } + Ok(()) +} + +fn acquire_tarball( + url: &str, + hash: Option<&str>, + paths: &BuildPaths, +) -> Result<(), ExecutorError> { + if url.starts_with("http://") || url.starts_with("https://") { + info!("Downloading {}", url); + let response = reqwest::blocking::get(url) + .map_err(|e| ExecutorError::Download(url.to_string(), e))?; + if !response.status().is_success() { + return Err(ExecutorError::DownloadStatus( + url.to_string(), + response.status().as_u16(), + )); + } + let bytes = response + .bytes() + .map_err(|e| ExecutorError::Download(url.to_string(), e))?; + fs::write(&paths.src_tarball, &bytes)?; + } else { + // Local file — already resolved to absolute by config loader + let local_path = std::path::PathBuf::from(url); + info!("Copying local tarball from {:?}", local_path); + fs::copy(&local_path, &paths.src_tarball)?; + } + + if let Some(expected) = hash { + verify_hash(&paths.src_tarball, expected)?; + } + + Ok(()) +} + +fn acquire_git( + url: &str, + tag: &str, + submodules: &[config::source::Submodule], + paths: &BuildPaths, +) -> Result<(), ExecutorError> { + info!("Cloning {} (tag: {})", url, tag); + + // Clone + run_cmd( + Command::new("git") + .args(["clone", "--depth=1", "--branch", tag, url]) + .arg(&paths.src_dir), + "git clone", + )?; + + // Init submodules + run_cmd( + Command::new("git") + .args(["submodule", "update", "--init", "--recursive"]) + .current_dir(&paths.src_dir), + "git submodule update", + )?; + + // Checkout specific submodule commits + for sub in submodules { + let sub_dir = paths.src_dir.join(&sub.path); + let commit = sub.commit.trim(); + run_cmd( + Command::new("git") + .args(["fetch", "origin", commit]) + .current_dir(&sub_dir), + &format!("git fetch for submodule {}", sub.path), + )?; + run_cmd( + Command::new("git") + .args(["checkout", commit]) + .current_dir(&sub_dir), + &format!("git checkout for submodule {}", sub.path), + )?; + } + + // Remove .git directories + let _ = fs::remove_dir_all(paths.src_dir.join(".git")); + run_cmd( + Command::new("find") + .arg(&paths.src_dir) + .args(["-name", ".git", "-exec", "rm", "-rf", "{}", "+"]), + "remove .git dirs", + )?; + + // Create reproducible tarball + let src_dir_name = paths + .src_dir + .file_name() + .unwrap() + .to_str() + .unwrap(); + run_cmd( + Command::new("tar") + .args([ + "--sort=name", + "--owner=0", + "--group=0", + "--numeric-owner", + "--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime", + "-czf", + ]) + .arg(&paths.src_tarball) + .args(["-C", paths.out_dir.to_str().unwrap(), src_dir_name]), + "tar create", + )?; + + Ok(()) +} + +fn acquire_virtual(paths: &BuildPaths) -> Result<(), ExecutorError> { + fs::create_dir_all(&paths.src_dir)?; + run_cmd( + Command::new("tar") + .args(["czvf"]) + .arg(&paths.src_tarball) + .args(["--files-from", "/dev/null"]), + "create empty tarball", + )?; + Ok(()) +} + +fn verify_hash(file: &std::path::Path, expected: &str) -> Result<(), ExecutorError> { + use sha2::Digest; + let bytes = fs::read(file)?; + let actual = if expected.len() == 128 { + format!("{:x}", sha2::Sha512::digest(&bytes)) + } else { + format!("{:x}", sha2::Sha256::digest(&bytes)) + }; + if actual != expected { + return Err(ExecutorError::HashMismatch { + expected: expected.to_string(), + actual, + }); + } + Ok(()) +} + +fn run_cmd(cmd: &mut Command, description: &str) -> Result<(), ExecutorError> { + let status = cmd.status()?; + if !status.success() { + return Err(ExecutorError::CommandFailed { + command: description.to_string(), + code: status.code().unwrap_or(1), + }); + } + Ok(()) +} diff --git a/crates/executor/src/chroot_setup.rs b/crates/executor/src/chroot_setup.rs new file mode 100644 index 00000000..20f1a17f --- /dev/null +++ b/crates/executor/src/chroot_setup.rs @@ -0,0 +1,60 @@ +use config::build_env::DebianCodename; +use config::PkgConfig; + +use crate::runtime::{load_runtime_perl, substitute_template}; +use crate::ExecutorError; + +/// Chroot setup commands and runtime Perl code for sbuild.conf. +pub struct ChrootSetup { + pub runtime_perl: Option, + pub pre_runtime_commands: Vec, + pub post_runtime_commands: Vec, +} + +impl ChrootSetup { + pub fn from_config(config: &PkgConfig) -> Result { + let mut pre = Vec::new(); + let mut post = Vec::new(); + + // Snapshot workaround (must come first) + if config.build_env.uses_snapshot() { + pre.push( + r#"echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99snapshot"# + .to_string(), + ); + } + + // Noble/distribution repos (before runtime) + for cmd in config.build_env.distribution.extra_chroot_commands() { + pre.push(cmd); + } + + // Runtime Perl template (substitute {{var}} placeholders) + let runtime_perl = if let Some(ref rt) = config.runtime { + let template = load_runtime_perl(&rt.profile, &config.config_root)?; + Some(substitute_template(&template, config)) + } else { + None + }; + + // Snapshot security (must come after runtime) + if let Some(security_url) = config.build_env.security_repo_url() { + let codename = match &config.build_env.distribution { + config::build_env::Distribution::Debian(DebianCodename::Bookworm) => "bookworm", + config::build_env::Distribution::Debian(DebianCodename::Trixie) => "trixie", + _ => config.build_env.distribution.as_short(), + }; + post.push(format!( + "echo 'deb {} {}-security main' > /etc/apt/sources.list.d/security-snapshot.list", + security_url, codename + )); + post.push("apt-get update".to_string()); + } + + Ok(ChrootSetup { + runtime_perl, + pre_runtime_commands: pre, + post_runtime_commands: post, + }) + } +} diff --git a/crates/executor/src/debian.rs b/crates/executor/src/debian.rs new file mode 100644 index 00000000..dd2fc2f9 --- /dev/null +++ b/crates/executor/src/debian.rs @@ -0,0 +1,79 @@ +use std::fs; +use std::os::unix::fs::PermissionsExt; +use std::path::Path; + +use config::PkgConfig; +use log::info; + +use crate::paths::BuildPaths; +use crate::ExecutorError; + +/// Step 3: Generate Debian packaging via debcrafter library + copy src/ overrides. +pub fn generate_debian(config: &PkgConfig, paths: &BuildPaths) -> Result<(), ExecutorError> { + // Load the .sss spec file + let mut spec: debcrafter::generate::SingleSource = + debcrafter::input::load_toml(&paths.spec_file).map_err(|e| { + ExecutorError::Debcrafter(format!("Failed to load spec {:?}: {}", paths.spec_file, e)) + })?; + + // Resolve maintainer: spec field → DEBEMAIL env var → error + let maintainer = spec + .maintainer + .take() + .or_else(|| std::env::var("DEBEMAIL").ok()) + .ok_or(ExecutorError::MissingMaintainer)?; + + info!("Running debcrafter on {:?}", paths.spec_file); + + let command = debcrafter::generate::Command::Generate { + dest: &paths.out_dir, + maintainer: &maintainer, + homepage: spec.homepage.as_deref(), + standards_version: &spec.standards_version, + }; + + let mut opts = debcrafter::generate::GlobalOptions { record_deps: None }; + + debcrafter::generate::process_source( + paths.spec_file.parent().unwrap_or(Path::new(".")), + &spec.name, + &mut spec.source, + &command, + &mut opts, + ); + + // Copy local src/ overrides if present + let src_overrides = config.config_root.join("src"); + if src_overrides.is_dir() { + info!("Copying src/ overrides from {:?}", src_overrides); + copy_dir_contents(&src_overrides, &paths.src_dir)?; + } + + // Ensure debian/rules is executable (src/ overrides may clobber permissions) + let rules_path = paths.src_dir.join("debian/rules"); + if rules_path.exists() { + fs::set_permissions(&rules_path, fs::Permissions::from_mode(0o755))?; + } + + Ok(()) +} + +/// Recursively copy contents of `src` directory into `dest`. +fn copy_dir_contents(src: &Path, dest: &Path) -> Result<(), ExecutorError> { + for entry in fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dest_path = dest.join(entry.file_name()); + + if src_path.is_dir() { + fs::create_dir_all(&dest_path)?; + copy_dir_contents(&src_path, &dest_path)?; + } else { + if let Some(parent) = dest_path.parent() { + fs::create_dir_all(parent)?; + } + fs::copy(&src_path, &dest_path)?; + } + } + Ok(()) +} diff --git a/crates/executor/src/env.rs b/crates/executor/src/env.rs new file mode 100644 index 00000000..615d1f83 --- /dev/null +++ b/crates/executor/src/env.rs @@ -0,0 +1,49 @@ +use std::fs; +use std::process::Command; + +use config::PkgConfig; +use log::info; + +use crate::paths::BuildPaths; +use crate::ExecutorError; + +/// Create the sbuild chroot environment. +pub fn create_env(config: &PkgConfig, paths: &BuildPaths) -> Result<(), ExecutorError> { + info!("Creating chroot at {:?}", paths.chroot_tarball); + + // Ensure chroot_dir exists + if let Some(parent) = paths.chroot_tarball.parent() { + fs::create_dir_all(parent)?; + } + + let mut cmd = Command::new("sbuild-createchroot"); + cmd.args(["--chroot-mode=unshare", "--make-sbuild-tarball"]) + .arg(&paths.chroot_tarball); + + if config.build_env.uses_snapshot() { + cmd.arg("--debootstrapopts=--no-check-gpg"); + } + + cmd.arg(config.build_env.distribution.as_short()) + .arg("/tmp/sbuild-createchroot") + .arg(config.build_env.repo_url()); + + let status = cmd.status()?; + if !status.success() { + return Err(ExecutorError::CommandFailed { + command: "sbuild-createchroot".to_string(), + code: status.code().unwrap_or(1), + }); + } + + Ok(()) +} + +/// Remove the chroot tarball. +pub fn clean_env(paths: &BuildPaths) -> Result<(), ExecutorError> { + if paths.chroot_tarball.exists() { + info!("Removing chroot tarball {:?}", paths.chroot_tarball); + fs::remove_file(&paths.chroot_tarball)?; + } + Ok(()) +} diff --git a/crates/executor/src/extract.rs b/crates/executor/src/extract.rs new file mode 100644 index 00000000..5a5a5097 --- /dev/null +++ b/crates/executor/src/extract.rs @@ -0,0 +1,23 @@ +use std::fs; +use std::process::Command; + +use crate::paths::BuildPaths; +use crate::ExecutorError; + +/// Step 2: Extract the source tarball into src_dir. +pub fn extract(paths: &BuildPaths) -> Result<(), ExecutorError> { + fs::create_dir_all(&paths.src_dir)?; + let status = Command::new("tar") + .args(["-C"]) + .arg(&paths.src_dir) + .args(["-xf"]) + .arg(&paths.src_tarball) + .status()?; + if !status.success() { + return Err(ExecutorError::CommandFailed { + command: "tar extract".to_string(), + code: status.code().unwrap_or(1), + }); + } + Ok(()) +} diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs new file mode 100644 index 00000000..e3ad6626 --- /dev/null +++ b/crates/executor/src/lib.rs @@ -0,0 +1,115 @@ +mod acquire; +mod chroot_setup; +mod debian; +mod env; +mod extract; +mod paths; +mod preflight; +pub mod runtime; +mod sbuild; +mod sbuild_conf; + +use std::fs; + +use config::PkgConfig; +use log::info; +use thiserror::Error; + +use paths::BuildPaths; + +#[derive(Debug, Error)] +pub enum ExecutorError { + #[error("Runtime profile not found: {0}")] + ProfileNotFound(String), + #[error("Missing required tools: {}", .0.join(", "))] + MissingTools(Vec), + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("Download failed for {0}: {1}")] + Download(String, reqwest::Error), + #[error("Download failed for {0}: HTTP {1}")] + DownloadStatus(String, u16), + #[error("Hash mismatch: expected {expected}, got {actual}")] + HashMismatch { expected: String, actual: String }, + #[error("Command '{command}' failed with exit code {code}")] + CommandFailed { command: String, code: i32 }, + #[error("Debcrafter error: {0}")] + Debcrafter(String), + #[error("Missing maintainer: set 'maintainer' in .sss spec or DEBEMAIL environment variable")] + MissingMaintainer, +} + +/// Run the full build pipeline. +pub fn build(config: &PkgConfig, resume: bool) -> Result<(), ExecutorError> { + let paths = BuildPaths::from_config(config); + preflight::check_required_tools(config)?; + + if !resume { + if paths.out_dir.exists() { + info!("Cleaning previous build artifacts..."); + fs::remove_dir_all(&paths.out_dir)?; + } + } + + fs::create_dir_all(&paths.out_dir)?; + + if !resume || !paths.src_tarball.exists() { + info!("Step 1/4: Acquiring source..."); + acquire::acquire(config, &paths)?; + } else { + info!("Step 1/4: Acquiring source... (skipped, tarball exists)"); + } + + if !resume || !paths.src_dir.exists() { + info!("Step 2/4: Extracting source..."); + extract::extract(&paths)?; + } else { + info!("Step 2/4: Extracting source... (skipped, src_dir exists)"); + } + + if !resume || !paths.src_dir.join("debian/source/format").exists() { + info!("Step 3/4: Generating Debian packaging..."); + debian::generate_debian(config, &paths)?; + } else { + info!("Step 3/4: Generating Debian packaging... (skipped)"); + } + + info!("Step 4/4: Running sbuild..."); + sbuild::run_sbuild(config, &paths)?; + + Ok(()) +} + +/// Create the sbuild chroot environment. +pub fn create_env(config: &PkgConfig) -> Result<(), ExecutorError> { + let paths = BuildPaths::from_config(config); + env::create_env(config, &paths) +} + +/// Remove the chroot tarball. +pub fn clean_env(config: &PkgConfig) -> Result<(), ExecutorError> { + let paths = BuildPaths::from_config(config); + env::clean_env(&paths) +} + +/// Remove build artifacts (out_dir). +pub fn clean(config: &PkgConfig) -> Result<(), ExecutorError> { + let paths = BuildPaths::from_config(config); + if paths.out_dir.exists() { + info!("Removing {:?}", paths.out_dir); + fs::remove_dir_all(&paths.out_dir)?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::runtime::*; + + #[test] + fn test_builtin_runtime_perl_exist() { + assert!(load_runtime_perl("go", std::path::Path::new("/nonexistent")).is_ok()); + assert!(load_runtime_perl("c", std::path::Path::new("/nonexistent")).is_ok()); + assert!(load_runtime_perl("nonexistent", std::path::Path::new("/nonexistent")).is_err()); + } +} diff --git a/crates/executor/src/paths.rs b/crates/executor/src/paths.rs new file mode 100644 index 00000000..c68cd35b --- /dev/null +++ b/crates/executor/src/paths.rs @@ -0,0 +1,127 @@ +use std::path::PathBuf; + +use config::PkgConfig; + +/// Concrete paths computed from config for the build pipeline. +pub struct BuildPaths { + pub config_root: PathBuf, + pub out_dir: PathBuf, + pub src_dir: PathBuf, + pub src_tarball: PathBuf, + pub chroot_tarball: PathBuf, + pub spec_file: PathBuf, +} + +impl BuildPaths { + pub fn from_config(config: &PkgConfig) -> Self { + let pkg = &config.package; + let env = &config.build_env; + + let out_dir = env + .workdir + .join(format!("{}-{}-{}", pkg.name, pkg.version, pkg.revision)); + let src_dir = out_dir.join(format!("{}-{}", pkg.name, pkg.version)); + let src_tarball = out_dir.join(format!("{}_{}.orig.tar.gz", pkg.name, pkg.version)); + + let chroot_tarball = if let Some(ref date) = env.snapshot_date { + env.chroot_dir + .join(format!("{}-{}-{}.tar.gz", env.distribution.as_short(), env.arch, date)) + } else { + env.chroot_dir + .join(format!("{}-{}.tar.gz", env.distribution.as_short(), env.arch)) + }; + + // spec is already resolved by config loader (relative paths joined with config_root) + let spec_file = pkg.spec.clone(); + + BuildPaths { + config_root: config.config_root.clone(), + out_dir, + src_dir, + src_tarball, + chroot_tarball, + spec_file, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use config::build_env::*; + use config::package::PackageFields; + use config::source::SourceKind; + + #[test] + fn test_paths_basic() { + let config = PkgConfig { + package: PackageFields { + name: "hello".into(), + version: "1.0.0".into(), + revision: "1".into(), + homepage: "https://example.com".into(), + spec: PathBuf::from("/home/user/pkg/hello.sss"), + }, + source: SourceKind::Virtual, + build_env: BuildEnv { + distribution: Distribution::bookworm(), + arch: Architecture::Amd64, + pkg_builder_version: "0.3.1".into(), + chroot_dir: PathBuf::from("/var/cache/sbuild"), + workdir: PathBuf::from("/tmp/work"), + tool_versions: ToolVersions { + debcrafter: "abc123".into(), + sbuild: "0.85.6".into(), + }, + snapshot_date: None, + snapshot_security_date: None, + }, + runtime: None, + verify: None, + config_root: PathBuf::from("/home/user/pkg"), + }; + + let paths = BuildPaths::from_config(&config); + assert_eq!(paths.out_dir, PathBuf::from("/tmp/work/hello-1.0.0-1")); + assert_eq!(paths.src_dir, PathBuf::from("/tmp/work/hello-1.0.0-1/hello-1.0.0")); + assert_eq!(paths.src_tarball, PathBuf::from("/tmp/work/hello-1.0.0-1/hello_1.0.0.orig.tar.gz")); + assert_eq!(paths.chroot_tarball, PathBuf::from("/var/cache/sbuild/bookworm-amd64.tar.gz")); + assert_eq!(paths.spec_file, PathBuf::from("/home/user/pkg/hello.sss")); + } + + #[test] + fn test_paths_with_snapshot() { + let config = PkgConfig { + package: PackageFields { + name: "hello".into(), + version: "1.0.0".into(), + revision: "1".into(), + homepage: "https://example.com".into(), + spec: PathBuf::from("/home/user/pkg/hello.sss"), + }, + source: SourceKind::Virtual, + build_env: BuildEnv { + distribution: Distribution::bookworm(), + arch: Architecture::Amd64, + pkg_builder_version: "0.3.1".into(), + chroot_dir: PathBuf::from("/var/cache/sbuild"), + workdir: PathBuf::from("/tmp/work"), + tool_versions: ToolVersions { + debcrafter: "abc123".into(), + sbuild: "0.85.6".into(), + }, + snapshot_date: Some("20240101T000000Z".into()), + snapshot_security_date: None, + }, + runtime: None, + verify: None, + config_root: PathBuf::from("/home/user/pkg"), + }; + + let paths = BuildPaths::from_config(&config); + assert_eq!( + paths.chroot_tarball, + PathBuf::from("/var/cache/sbuild/bookworm-amd64-20240101T000000Z.tar.gz") + ); + } +} diff --git a/crates/executor/src/preflight.rs b/crates/executor/src/preflight.rs new file mode 100644 index 00000000..b0fa58be --- /dev/null +++ b/crates/executor/src/preflight.rs @@ -0,0 +1,46 @@ +use std::process::Command; + +use config::PkgConfig; + +use crate::ExecutorError; + +/// Check that all required external tools are available on PATH. +pub fn check_required_tools(config: &PkgConfig) -> Result<(), ExecutorError> { + let mut tools: Vec<&str> = Vec::new(); + + match &config.source { + config::source::SourceKind::Tarball { .. } => { + tools.push("tar"); + } + config::source::SourceKind::Git { .. } => { + tools.extend(["git", "tar"]); + } + config::source::SourceKind::Virtual => { + tools.push("tar"); + } + } + tools.extend(["dpkg-parsechangelog", "sbuild"]); + + let mut missing = Vec::new(); + for tool in &tools { + if !tool_exists(tool) { + missing.push(tool.to_string()); + } + } + + if !missing.is_empty() { + return Err(ExecutorError::MissingTools(missing)); + } + + Ok(()) +} + +fn tool_exists(name: &str) -> bool { + Command::new("which") + .arg(name) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status() + .map(|s| s.success()) + .unwrap_or(false) +} diff --git a/crates/executor/src/runtime.rs b/crates/executor/src/runtime.rs new file mode 100644 index 00000000..96330ab1 --- /dev/null +++ b/crates/executor/src/runtime.rs @@ -0,0 +1,159 @@ +use std::path::Path; + +use config::PkgConfig; + +use crate::ExecutorError; + +/// Validate that a profile name contains only safe characters. +pub fn validate_profile_name(name: &str) -> Result<(), ExecutorError> { + if name.is_empty() + || !name + .chars() + .all(|c| c.is_alphanumeric() || c == '-' || c == '_') + { + return Err(ExecutorError::ProfileNotFound(format!( + "Invalid profile name: '{}' (must be alphanumeric, hyphens, or underscores)", + name + ))); + } + Ok(()) +} + +/// Load a runtime .perl template. Checks local directory first, then built-in. +pub fn load_runtime_perl(name: &str, config_root: &Path) -> Result { + validate_profile_name(name)?; + + // Check local override first + let local_path = config_root.join("runtimes").join(format!("{}.perl", name)); + if local_path.exists() { + return std::fs::read_to_string(&local_path).map_err(ExecutorError::Io); + } + + match load_builtin_runtime_perl(name) { + Some(content) => Ok(content.to_string()), + None => Err(ExecutorError::ProfileNotFound(format!( + "runtimes/{}.perl", + name + ))), + } +} + +fn load_builtin_runtime_perl(name: &str) -> Option<&'static str> { + match name { + "go" => Some(include_str!("../../../runtimes/go.perl")), + "rust" => Some(include_str!("../../../runtimes/rust.perl")), + "node" => Some(include_str!("../../../runtimes/node.perl")), + "java" => Some(include_str!("../../../runtimes/java.perl")), + "java-gradle" => Some(include_str!("../../../runtimes/java-gradle.perl")), + "nim" => Some(include_str!("../../../runtimes/nim.perl")), + "dotnet-noble" => Some(include_str!("../../../runtimes/dotnet-noble.perl")), + "dotnet-debian" => Some(include_str!("../../../runtimes/dotnet-debian.perl")), + "dotnet-backup" => Some(include_str!("../../../runtimes/dotnet-backup.perl")), + "c" => Some(include_str!("../../../runtimes/c.perl")), + _ => None, + } +} + +/// Substitute `{{var_name}}` placeholders in a runtime .perl template with config values. +pub fn substitute_template(template: &str, config: &PkgConfig) -> String { + let mut result = template.to_string(); + + if let Some(ref runtime) = config.runtime { + // Substitute scalar vars: {{key}} → value + for (key, value) in &runtime.vars { + if let toml::Value::String(s) = value { + let escaped = perl_escape_single_quote(s); + result = result.replace(&format!("{{{{{}}}}}", key), &escaped); + } + } + + // Substitute {{packages_perl}} for dotnet runtimes + if result.contains("{{packages_perl}}") { + let packages_perl = render_packages_perl(runtime, config); + result = result.replace("{{packages_perl}}", &packages_perl); + } + } + + result +} + +/// Escape a value for embedding in a Perl single-quoted string. +fn perl_escape_single_quote(s: &str) -> String { + s.replace('\\', "\\\\").replace('\'', "\\'") +} + +/// Render dotnet packages as Perl hashref entries for the `@packages` array. +fn render_packages_perl( + runtime: &config::runtime::RuntimeConfig, + config: &PkgConfig, +) -> String { + let mut entries = Vec::new(); + + if let Some(toml::Value::Array(pkgs)) = runtime.vars.get("packages") { + for item in pkgs { + if let toml::Value::Table(table) = item { + let name = table + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let url = table + .get("url") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let hash = table + .get("hash") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + let mut entry = format!( + " {{ name => '{}', url => '{}', hash => '{}'", + perl_escape_single_quote(name), + perl_escape_single_quote(url), + perl_escape_single_quote(hash), + ); + + if runtime.profile.starts_with("dotnet") { + let apt_name = transform_dotnet_name(name, &config.build_env.arch); + entry.push_str(&format!( + ", apt_name => '{}'", + perl_escape_single_quote(&apt_name) + )); + } + + entry.push_str(" }"); + entries.push(entry); + } + } + } + + entries.join(",\n") + "," +} + +fn transform_dotnet_name(input: &str, arch: &config::build_env::Architecture) -> String { + let arch_str = format!("_{}", arch); + if let Some(pos) = input.find(&arch_str) { + let trimmed = &input[..pos]; + trimmed.replace('_', "=") + } else { + input.replace('_', "=") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_builtin_runtime_perl_exist() { + assert!(load_builtin_runtime_perl("go").is_some()); + assert!(load_builtin_runtime_perl("c").is_some()); + assert!(load_builtin_runtime_perl("nonexistent").is_none()); + } + + #[test] + fn test_perl_escape_single_quote() { + assert_eq!(perl_escape_single_quote("hello"), "hello"); + assert_eq!(perl_escape_single_quote("it's"), "it\\'s"); + assert_eq!(perl_escape_single_quote("a\\b"), "a\\\\b"); + } +} diff --git a/crates/executor/src/sbuild.rs b/crates/executor/src/sbuild.rs new file mode 100644 index 00000000..d954bfdc --- /dev/null +++ b/crates/executor/src/sbuild.rs @@ -0,0 +1,40 @@ +use std::fs; +use std::process::Command; + +use config::PkgConfig; +use log::info; + +use crate::chroot_setup::ChrootSetup; +use crate::paths::BuildPaths; +use crate::sbuild_conf; +use crate::ExecutorError; + +/// Step 4: Generate sbuild.conf and invoke sbuild. +pub fn run_sbuild(config: &PkgConfig, paths: &BuildPaths) -> Result<(), ExecutorError> { + let chroot_setup = ChrootSetup::from_config(config)?; + let conf_content = sbuild_conf::render_sbuild_conf(config, &chroot_setup); + + let conf_path = paths.config_root.join("sbuild.conf"); + fs::write(&conf_path, &conf_content)?; + info!("Generated sbuild.conf at {:?}", conf_path); + + let status = Command::new("sbuild") + .arg("-c") + .arg(&paths.chroot_tarball) + .arg(&paths.src_dir) + .env("SBUILD_CONFIG", &conf_path) + .status()?; + + if !status.success() { + return Err(ExecutorError::CommandFailed { + command: "sbuild".to_string(), + code: status.code().unwrap_or(1), + }); + } + + // Touch .built marker + let built_marker = paths.out_dir.join(".built"); + fs::write(&built_marker, "")?; + + Ok(()) +} diff --git a/crates/executor/src/sbuild_conf.rs b/crates/executor/src/sbuild_conf.rs new file mode 100644 index 00000000..0b6efe40 --- /dev/null +++ b/crates/executor/src/sbuild_conf.rs @@ -0,0 +1,158 @@ +use config::PkgConfig; + +use crate::chroot_setup::ChrootSetup; + +/// Generate a Perl sbuild.conf file from config + chroot setup. +pub fn render_sbuild_conf(config: &PkgConfig, setup: &ChrootSetup) -> String { + let mut out = String::new(); + + // Header + let runtime_label = config + .runtime + .as_ref() + .map(|rt| rt.profile.as_str()) + .unwrap_or("none"); + out.push_str(&format!( + "# Auto-generated by pkg-builder — do not edit\n\ + # Runtime: {} | Distribution: {}\n\n", + runtime_label, + config.build_env.distribution.as_short() + )); + + // Basic settings + out.push_str(&format!( + "$distribution = '{}';\n", + config.build_env.distribution.as_short() + )); + out.push_str("$build_arch_all = 1;\n"); + out.push_str("$build_source = 1;\n"); + out.push_str("$source_only_changes = 1;\n"); + out.push_str("$chroot_mode = 'unshare';\n"); + out.push_str("$run_piuparts = 0;\n"); + out.push_str("$apt_upgrade = 0;\n"); + out.push_str("$apt_distupgrade = 0;\n"); + out.push_str("$run_autopkgtest = 0;\n"); + out.push_str("$verbose = 1;\n"); + out.push_str("$run_lintian = 0;\n"); + + // Build dir — use $ENV{HOME} so the path isn't tied to a specific user + let build_dir = portabilize_perl_path(&format!( + "{}/{}-{}-{}", + config.build_env.workdir.display(), + config.package.name, + config.package.version, + config.package.revision + )); + out.push_str(&format!("$build_dir = {};\n", build_dir)); + out.push('\n'); + + // Runtime Perl code (variable declarations + @runtime_commands) + if let Some(ref perl_code) = setup.runtime_perl { + out.push_str(perl_code); + if !perl_code.ends_with('\n') { + out.push('\n'); + } + out.push('\n'); + } + + // Assemble $external_commands + let has_pre = !setup.pre_runtime_commands.is_empty(); + let has_runtime = setup.runtime_perl.is_some(); + let has_post = !setup.post_runtime_commands.is_empty(); + + if has_pre || has_runtime || has_post { + out.push_str("$external_commands = {\n"); + out.push_str(" 'chroot-setup-commands' => [\n"); + + for cmd in &setup.pre_runtime_commands { + out.push_str(&format!(" {},\n", perl_quote(cmd))); + } + + if has_runtime { + out.push_str(" @runtime_commands,\n"); + } + + for cmd in &setup.post_runtime_commands { + out.push_str(&format!(" {},\n", perl_quote(cmd))); + } + + out.push_str(" ],\n"); + out.push_str("};\n"); + } + + // Perl config files must return a true value + out.push_str("\n1;\n"); + + out +} + +/// Quote a string for use in a Perl single-quoted context. +fn perl_quote(s: &str) -> String { + if !s.contains('\'') { + format!("'{}'", s) + } else if !s.contains('}') || balanced_braces(s) { + format!("q{{{}}}", s) + } else { + let escaped = s + .replace('\\', "\\\\") + .replace('"', "\\\"") + .replace('$', "\\$") + .replace('@', "\\@"); + format!("\"{}\"", escaped) + } +} + +/// Convert an absolute path to a portable Perl expression. +fn portabilize_perl_path(path: &str) -> String { + if let Ok(home) = std::env::var("HOME") { + if let Some(rest) = path.strip_prefix(&home) { + let rest = rest.strip_prefix('/').unwrap_or(rest); + return format!("\"$ENV{{HOME}}/{}\"", rest); + } + } + format!("'{}'", path) +} + +fn balanced_braces(s: &str) -> bool { + let mut depth = 0i32; + for c in s.chars() { + match c { + '{' => depth += 1, + '}' => { + depth -= 1; + if depth < 0 { + return false; + } + } + _ => {} + } + } + depth == 0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_perl_quote_simple() { + assert_eq!(perl_quote("hello"), "'hello'"); + assert_eq!(perl_quote("apt install -y wget"), "'apt install -y wget'"); + } + + #[test] + fn test_perl_quote_with_single_quotes() { + let cmd = r#"echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99snapshot"#; + let quoted = perl_quote(cmd); + assert!(quoted.starts_with("q{")); + } + + #[test] + fn test_balanced_braces() { + assert!(balanced_braces("hello")); + assert!(balanced_braces("{hello}")); + assert!(balanced_braces("{{}}")); + assert!(!balanced_braces("{")); + assert!(!balanced_braces("}")); + } +} diff --git a/crates/init/Cargo.toml b/crates/init/Cargo.toml new file mode 100644 index 00000000..e99c7df9 --- /dev/null +++ b/crates/init/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "pkg-builder-init" +version = "0.4.0-rc.1" +edition = "2021" +license.workspace = true + +[dependencies] +reqwest = { workspace = true } +sha2 = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +log = { workspace = true } diff --git a/crates/init/src/generate.rs b/crates/init/src/generate.rs new file mode 100644 index 00000000..b932a90e --- /dev/null +++ b/crates/init/src/generate.rs @@ -0,0 +1,282 @@ +use std::collections::BTreeMap; + +use serde::Serialize; + +use crate::{InitConfig, Runtime, SourceConfig}; + +// --- Serializable types matching the pkg-builder.toml schema --- + +#[derive(Serialize)] +struct PkgBuilderToml { + package: Package, + source: Source, + build: Build, + #[serde(skip_serializing_if = "Option::is_none")] + runtime: Option, + tools: Tools, +} + +#[derive(Serialize)] +struct Package { + name: String, + version: String, + revision: String, + homepage: String, + spec: String, +} + +#[derive(Serialize)] +#[serde(tag = "type", rename_all = "lowercase")] +enum Source { + Tarball { + url: String, + #[serde(skip_serializing_if = "Option::is_none")] + hash: Option, + }, + Git { + url: String, + tag: String, + submodules: Vec, + }, + Virtual, +} + +#[derive(Serialize)] +struct Build { + distribution: String, + arch: String, + workdir: String, +} + +#[derive(Serialize)] +struct RuntimeSection { + profile: String, + #[serde(flatten)] + vars: BTreeMap, +} + +#[derive(Serialize)] +struct Tools { + pkg_builder: String, + debcrafter: String, + sbuild: String, +} + +/// Generate the contents of `pkg-builder.toml`. +pub fn generate_toml(config: &InitConfig) -> String { + let source = match &config.source { + SourceConfig::Virtual => Source::Virtual, + SourceConfig::Git { url, tag } => Source::Git { + url: url.clone(), + tag: tag.clone(), + submodules: vec![], + }, + SourceConfig::Tarball { url, hash } => { + let filename = url.rsplit('/').next().unwrap_or(url); + Source::Tarball { + url: filename.to_string(), + hash: hash.clone(), + } + } + }; + + let runtime = if config.runtime != Runtime::None { + let mut vars = BTreeMap::new(); + for (key, value) in &config.runtime_vars { + vars.insert(key.clone(), toml::Value::String(value.clone())); + } + Some(RuntimeSection { + profile: config.runtime.to_string(), + vars, + }) + } else { + None + }; + + let toml_config = PkgBuilderToml { + package: Package { + name: config.name.clone(), + version: config.version.clone(), + revision: config.revision.clone(), + homepage: config.homepage.clone(), + spec: format!("{}.sss", config.name), + }, + source, + build: Build { + distribution: config.distribution.to_string(), + arch: config.arch.clone(), + workdir: format!("~/.pkg-builder/packages/{}", config.distribution), + }, + runtime, + tools: Tools { + pkg_builder: "0.3.1".into(), + debcrafter: "8189263".into(), + sbuild: "0.85.6".into(), + }, + }; + + toml::to_string_pretty(&toml_config).expect("failed to serialize config") +} + +// --- Serializable types for debcrafter specs --- + +#[derive(Serialize)] +struct SourceServiceSpec { + name: String, + maintainer: String, + #[serde(skip_serializing_if = "Option::is_none")] + homepage: Option, + standards_version: String, + section: String, + variants: Vec, + build_depends: Vec, + packages: Vec, + skip_debug_symbols: bool, +} + +#[derive(Serialize)] +struct PackageSpec { + name: String, + architecture: String, + summary: String, + conflicts: Vec, + recommends: Vec, + provides: Vec, + suggests: Vec, + depends: Vec, + add_files: Vec, + add_links: Vec, + add_manpages: Vec, + long_doc: String, +} + +/// Generate the contents of `{name}.sss` (debcrafter source service spec). +pub fn generate_sss(config: &InitConfig) -> String { + let homepage = if config.homepage.is_empty() { + None + } else { + Some(config.homepage.clone()) + }; + let spec = SourceServiceSpec { + name: config.name.clone(), + maintainer: format!("{} <{}>", config.maintainer_name, config.maintainer_email), + homepage, + standards_version: "4.5.1".into(), + section: config.section.clone(), + variants: vec![], + build_depends: vec![], + packages: vec![config.name.clone()], + skip_debug_symbols: true, + }; + toml::to_string_pretty(&spec).expect("failed to serialize sss") +} + +/// Generate the contents of `{name}.sps` (debcrafter package spec). +pub fn generate_sps(config: &InitConfig) -> String { + let summary = if config.summary.is_empty() { + &config.name + } else { + &config.summary + }; + let spec = PackageSpec { + name: config.name.clone(), + architecture: "any".into(), + summary: summary.clone().to_string(), + conflicts: vec![], + recommends: vec![], + provides: vec![], + suggests: vec![], + depends: vec![], + add_files: vec![], + add_links: vec![], + add_manpages: vec![], + long_doc: format!( + "{}\n Long Description:\n TODO: Add a detailed description of the package.", + summary + ), + }; + toml::to_string_pretty(&spec).expect("failed to serialize sps") +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Distribution; + + fn test_config() -> InitConfig { + InitConfig { + name: "hello-world".into(), + version: "1.0.0".into(), + revision: "1".into(), + homepage: "https://example.com".into(), + maintainer_name: "Test".into(), + maintainer_email: "test@example.com".into(), + section: "net".into(), + summary: "A test package".into(), + source: SourceConfig::Tarball { + url: "https://example.com/hello-1.0.0.tar.gz".into(), + hash: Some("abc123".into()), + }, + distribution: Distribution::Bookworm, + arch: "amd64".into(), + runtime: Runtime::None, + runtime_vars: vec![], + } + } + + #[test] + fn test_generate_toml_is_valid() { + let toml_str = generate_toml(&test_config()); + let parsed: toml::Value = toml::from_str(&toml_str).expect("generated TOML should parse"); + assert_eq!(parsed["package"]["name"].as_str(), Some("hello-world")); + assert_eq!(parsed["source"]["type"].as_str(), Some("tarball")); + assert_eq!(parsed["tools"]["sbuild"].as_str(), Some("0.85.6")); + } + + #[test] + fn test_generate_toml_virtual() { + let mut config = test_config(); + config.source = SourceConfig::Virtual; + let toml_str = generate_toml(&config); + let parsed: toml::Value = toml::from_str(&toml_str).unwrap(); + assert_eq!(parsed["source"]["type"].as_str(), Some("virtual")); + } + + #[test] + fn test_generate_toml_git() { + let mut config = test_config(); + config.source = SourceConfig::Git { + url: "https://github.com/example/repo.git".into(), + tag: "v1.0.0".into(), + }; + let toml_str = generate_toml(&config); + let parsed: toml::Value = toml::from_str(&toml_str).unwrap(); + assert_eq!(parsed["source"]["type"].as_str(), Some("git")); + assert_eq!(parsed["source"]["tag"].as_str(), Some("v1.0.0")); + } + + #[test] + fn test_generate_toml_with_runtime() { + let mut config = test_config(); + config.runtime = Runtime::Go; + config.runtime_vars = vec![ + ("binary_url".into(), "https://go.dev/dl/go1.22.tar.gz".into()), + ("binary_checksum".into(), "abc123".into()), + ]; + let toml_str = generate_toml(&config); + let parsed: toml::Value = toml::from_str(&toml_str).unwrap(); + assert_eq!(parsed["runtime"]["profile"].as_str(), Some("go")); + assert_eq!( + parsed["runtime"]["binary_url"].as_str(), + Some("https://go.dev/dl/go1.22.tar.gz") + ); + } + + #[test] + fn test_generate_toml_no_runtime_section_when_none() { + let config = test_config(); + let toml_str = generate_toml(&config); + let parsed: toml::Value = toml::from_str(&toml_str).unwrap(); + assert!(parsed.get("runtime").is_none()); + } +} diff --git a/crates/init/src/lib.rs b/crates/init/src/lib.rs new file mode 100644 index 00000000..d545ae28 --- /dev/null +++ b/crates/init/src/lib.rs @@ -0,0 +1,303 @@ +mod generate; +pub mod runtime; +mod tarball; + +pub use generate::{generate_sps, generate_sss, generate_toml}; +pub use runtime::{LatestVersion, Runtime, RuntimeField, RuntimeSetup, ALL_RUNTIMES}; +pub use tarball::{ + download_and_hash_tarball, sha256_file, try_verify_upstream_hash, TarballResult, +}; + +use log::warn; +use std::fmt; +use std::fs; +use std::path::Path; +use std::time::Duration; + +/// Create an HTTP client with a 30-second timeout. +pub fn http_client() -> reqwest::blocking::Client { + reqwest::blocking::Client::builder() + .timeout(Duration::from_secs(30)) + .build() + .expect("Failed to build HTTP client") +} + +// ---- Source type ---- + +/// Supported source types. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SourceType { + Tarball, + Git, + Virtual, +} + +/// All available source types, in display order. +pub const ALL_SOURCE_TYPES: &[SourceType] = + &[SourceType::Tarball, SourceType::Git, SourceType::Virtual]; + +impl fmt::Display for SourceType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl SourceType { + pub fn as_str(&self) -> &'static str { + match self { + SourceType::Tarball => "tarball", + SourceType::Git => "git", + SourceType::Virtual => "virtual", + } + } + + pub fn from_str(s: &str) -> Option { + ALL_SOURCE_TYPES.iter().find(|t| t.as_str() == s).copied() + } + + /// Fields the consumer needs to provide for this source type. + pub fn required_fields(&self) -> &'static [RuntimeField] { + match self { + SourceType::Virtual => &[], + SourceType::Git => &[ + RuntimeField { + key: "url", + label: "Git repository URL", + }, + RuntimeField { + key: "tag", + label: "Git tag", + }, + ], + SourceType::Tarball => &[RuntimeField { + key: "url", + label: "Tarball URL", + }], + } + } +} + +// ---- Distribution ---- + +/// Supported target distributions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Distribution { + Bookworm, + Trixie, + Noble, +} + +/// All available distributions, in display order. +pub const ALL_DISTRIBUTIONS: &[Distribution] = &[ + Distribution::Bookworm, + Distribution::Trixie, + Distribution::Noble, +]; + +impl fmt::Display for Distribution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl Distribution { + pub fn as_str(&self) -> &'static str { + match self { + Distribution::Bookworm => "bookworm", + Distribution::Trixie => "trixie", + Distribution::Noble => "noble", + } + } + + pub fn from_str(s: &str) -> Option { + ALL_DISTRIBUTIONS.iter().find(|d| d.as_str() == s).copied() + } +} + +// ---- Debian section ---- + +/// All valid Debian sections, for use in selection prompts. +pub const DEBIAN_SECTIONS: &[&str] = &[ + "admin", + "cli-mono", + "comm", + "database", + "debug", + "devel", + "doc", + "editors", + "education", + "electronics", + "embedded", + "fonts", + "games", + "gnome", + "gnu-r", + "gnustep", + "golang", + "graphics", + "hamradio", + "haskell", + "httpd", + "interpreters", + "introspection", + "java", + "javascript", + "kde", + "kernel", + "libdevel", + "libs", + "lisp", + "localization", + "mail", + "math", + "metapackages", + "misc", + "net", + "news", + "ocaml", + "oldlibs", + "otherosfs", + "perl", + "php", + "python", + "ruby", + "rust", + "science", + "shells", + "sound", + "tasks", + "tex", + "text", + "utils", + "vcs", + "video", + "web", + "x11", + "xfce", + "zope", +]; + +// ---- Source config ---- + +/// Resolved source configuration for an init config. +#[derive(Debug, Clone)] +pub enum SourceConfig { + Virtual, + Git { url: String, tag: String }, + Tarball { url: String, hash: Option }, +} + +/// Resolve source details based on source type. +/// +/// For `Tarball`: if `url` is a remote URL, downloads it to `output_dir`, +/// computes sha256 hash, and optionally verifies against `upstream_hash`. +/// For local file URLs, hashes the file in place. +pub fn resolve_source( + source_type: SourceType, + url: Option<&str>, + tag: Option<&str>, + output_dir: &Path, + upstream_hash: Option<&str>, +) -> Result> { + match source_type { + SourceType::Virtual => Ok(SourceConfig::Virtual), + SourceType::Git => { + let url = url.ok_or("Git source type requires a URL")?; + let tag = tag.ok_or("Git source type requires a tag")?; + Ok(SourceConfig::Git { + url: url.to_string(), + tag: tag.to_string(), + }) + } + SourceType::Tarball => { + let url = url.ok_or("Tarball source type requires a URL")?; + + // Local file: hash it directly + if !url.starts_with("http://") && !url.starts_with("https://") { + let hash = if Path::new(url).exists() { + Some(sha256_file(url)?) + } else { + None + }; + return Ok(SourceConfig::Tarball { + url: url.to_string(), + hash, + }); + } + + // Remote URL: download, hash, save + match download_and_hash_tarball(url, output_dir, upstream_hash) { + Ok(result) => Ok(SourceConfig::Tarball { + url: url.to_string(), + hash: Some(result.hash), + }), + Err(e) => { + warn!("Failed to download tarball: {}", e); + Ok(SourceConfig::Tarball { + url: url.to_string(), + hash: None, + }) + } + } + } + } +} + +// ---- Init config ---- + +/// All the data needed to generate init files, fully resolved (no prompts). +pub struct InitConfig { + pub name: String, + pub version: String, + pub revision: String, + pub homepage: String, + pub maintainer_name: String, + pub maintainer_email: String, + pub section: String, + pub summary: String, + pub source: SourceConfig, + pub distribution: Distribution, + pub arch: String, + pub runtime: Runtime, + pub runtime_vars: Vec<(String, String)>, +} + +/// Paths of the generated files. +pub struct GeneratedFiles { + pub toml_path: std::path::PathBuf, + pub sss_path: std::path::PathBuf, + pub sps_path: std::path::PathBuf, +} + +/// Generate and write the three init files to `output_dir`. +/// +/// Returns an error if any of the target files already exist. +pub fn write_init_files( + config: &InitConfig, + output_dir: &Path, +) -> Result> { + if !output_dir.exists() { + fs::create_dir_all(output_dir)?; + } + + let toml_path = output_dir.join("pkg-builder.toml"); + let sss_path = output_dir.join(format!("{}.sss", config.name)); + let sps_path = output_dir.join(format!("{}.sps", config.name)); + + for path in [&toml_path, &sss_path, &sps_path] { + if path.exists() { + return Err(format!("{} already exists", path.display()).into()); + } + } + + fs::write(&toml_path, generate_toml(config))?; + fs::write(&sss_path, generate_sss(config))?; + fs::write(&sps_path, generate_sps(config))?; + + Ok(GeneratedFiles { + toml_path, + sss_path, + sps_path, + }) +} diff --git a/crates/init/src/runtime.rs b/crates/init/src/runtime.rs new file mode 100644 index 00000000..1765742f --- /dev/null +++ b/crates/init/src/runtime.rs @@ -0,0 +1,451 @@ +use sha2::{Digest, Sha256}; +use std::fmt; + +use crate::http_client; + +/// Supported runtime recipes. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Runtime { + None, + Go, + Rust, + Node, + Java, + JavaGradle, + Nim, + C, + DotnetNoble, + DotnetDebian, + DotnetBackup, +} + +/// All available runtime variants, in display order. +pub const ALL_RUNTIMES: &[Runtime] = &[ + Runtime::None, + Runtime::Go, + Runtime::Rust, + Runtime::Node, + Runtime::Java, + Runtime::JavaGradle, + Runtime::Nim, + Runtime::C, + Runtime::DotnetNoble, + Runtime::DotnetDebian, + Runtime::DotnetBackup, +]; + +impl fmt::Display for Runtime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl Runtime { + /// The string used in pkg-builder.toml `profile = "..."`. + pub fn as_str(&self) -> &'static str { + match self { + Runtime::None => "none", + Runtime::Go => "go", + Runtime::Rust => "rust", + Runtime::Node => "node", + Runtime::Java => "java", + Runtime::JavaGradle => "java-gradle", + Runtime::Nim => "nim", + Runtime::C => "c", + Runtime::DotnetNoble => "dotnet-noble", + Runtime::DotnetDebian => "dotnet-debian", + Runtime::DotnetBackup => "dotnet-backup", + } + } + + /// Parse from a string (e.g. CLI flag value). + pub fn from_str(s: &str) -> Option { + ALL_RUNTIMES.iter().find(|r| r.as_str() == s).copied() + } + + /// Descriptors for fields that must be provided for this runtime. + /// Each field has (key, label) — key is the TOML field name, label is a human-readable prompt. + pub fn required_fields(&self) -> &'static [RuntimeField] { + match self { + Runtime::None | Runtime::C => &[], + Runtime::Go => &[ + RuntimeField { + key: "binary_url", + label: "Go binary URL", + }, + RuntimeField { + key: "binary_checksum", + label: "Go binary checksum (sha256)", + }, + ], + Runtime::Rust => &[ + RuntimeField { + key: "binary_url", + label: "Rust binary URL", + }, + RuntimeField { + key: "binary_gpg_asc", + label: "Rust GPG signature (ASCII-armored)", + }, + ], + Runtime::Node => &[ + RuntimeField { + key: "binary_url", + label: "Node.js binary URL", + }, + RuntimeField { + key: "binary_checksum", + label: "Node.js binary checksum (sha256)", + }, + ], + Runtime::Java => &[ + RuntimeField { + key: "binary_url", + label: "JDK download URL", + }, + RuntimeField { + key: "binary_checksum", + label: "JDK checksum (sha256)", + }, + RuntimeField { + key: "jdk_version", + label: "JDK version (e.g. 17.0.10)", + }, + ], + Runtime::JavaGradle => &[ + RuntimeField { + key: "binary_url", + label: "JDK download URL", + }, + RuntimeField { + key: "binary_checksum", + label: "JDK checksum (sha256)", + }, + RuntimeField { + key: "jdk_version", + label: "JDK version (e.g. 17.0.10)", + }, + RuntimeField { + key: "gradle_binary_url", + label: "Gradle download URL", + }, + RuntimeField { + key: "gradle_binary_checksum", + label: "Gradle checksum (sha256)", + }, + RuntimeField { + key: "gradle_version", + label: "Gradle version (e.g. 8.7)", + }, + ], + Runtime::Nim => &[ + RuntimeField { + key: "binary_url", + label: "Nim binary URL", + }, + RuntimeField { + key: "binary_checksum", + label: "Nim binary checksum (sha256sum format: 'hash filename')", + }, + RuntimeField { + key: "nim_version", + label: "Nim version", + }, + ], + Runtime::DotnetNoble | Runtime::DotnetDebian | Runtime::DotnetBackup => &[], + } + } + + /// Determine what setup this runtime needs. + /// + /// This is the single entry point for consumers to find out what to do + /// for a given runtime. It tries auto-resolution where possible. + pub fn setup(&self) -> RuntimeSetup { + match self { + Runtime::None | Runtime::C => RuntimeSetup::NoVars, + Runtime::DotnetNoble | Runtime::DotnetDebian | Runtime::DotnetBackup => { + RuntimeSetup::ManualOnly + } + Runtime::Java | Runtime::JavaGradle => RuntimeSetup::NeedsInput { + fields: self.required_fields(), + }, + _ => { + // Go, Rust, Node, Nim: try auto-resolve + match self.resolve_latest() { + Ok(latest) => RuntimeSetup::AutoResolved { + latest, + fields: self.required_fields(), + optional_fields: self.optional_fields(), + }, + Err(_) => RuntimeSetup::NeedsInput { + fields: self.required_fields(), + }, + } + } + } + } + + /// Given a user-specified version, resolve the runtime vars. + /// + /// For runtimes like Go/Node, this fetches the checksum for the specific version. + /// For Rust, this fetches the GPG signature. + /// For Nim, this downloads and computes the checksum. + fn resolve_latest(&self) -> Result> { + match self { + Runtime::Go => { + let (version, url, checksum) = resolve_go_latest()?; + Ok(LatestVersion { + version, + vars: vec![ + ("binary_url".into(), url), + ("binary_checksum".into(), checksum), + ], + }) + } + Runtime::Node => { + let (version, url, checksum) = resolve_node_latest()?; + Ok(LatestVersion { + version, + vars: vec![ + ("binary_url".into(), url), + ("binary_checksum".into(), checksum), + ], + }) + } + _ => Err("Auto-resolution not supported for this runtime".into()), + } + } + + /// Given a user-specified version, resolve the runtime vars. + /// + /// For runtimes like Go/Node, this fetches the checksum for the specific version. + /// For Rust, this fetches the GPG signature. + /// For Nim, this downloads and computes the checksum. + /// Returns the vars that could be auto-resolved; missing ones need manual input. + pub fn resolve_version( + &self, + version: &str, + ) -> Result, Box> { + match self { + Runtime::Go => { + let url = go_download_url(version); + let checksum = fetch_go_checksum(version)?; + Ok(vec![ + ("binary_url".into(), url), + ("binary_checksum".into(), checksum), + ]) + } + Runtime::Rust => { + let url = rust_download_url(version); + let gpg_asc = fetch_rust_gpg_asc(&url)?; + Ok(vec![ + ("binary_url".into(), url), + ("binary_gpg_asc".into(), gpg_asc), + ]) + } + Runtime::Node => { + let url = node_download_url(version); + let checksum = fetch_node_checksum(version)?; + Ok(vec![ + ("binary_url".into(), url), + ("binary_checksum".into(), checksum), + ]) + } + Runtime::Nim => { + let url = nim_download_url(version); + let checksum = fetch_nim_checksum(version)?; + Ok(vec![ + ("binary_url".into(), url), + ("binary_checksum".into(), checksum), + ("nim_version".into(), version.to_string()), + ]) + } + _ => Err("Version resolution not supported for this runtime".into()), + } + } + + /// Optional extra fields that can be prompted after the main vars + /// (e.g. yarn_version for Node). + pub fn optional_fields(&self) -> &'static [RuntimeField] { + match self { + Runtime::Node => &[RuntimeField { + key: "yarn_version", + label: "Yarn version", + }], + _ => &[], + } + } +} + +/// Descriptor for a configuration field (used for both runtime and source fields). +pub struct RuntimeField { + /// The TOML key (e.g. "binary_url"). + pub key: &'static str, + /// Human-readable label for prompting. + pub label: &'static str, +} + +/// Result of auto-resolving the latest version of a runtime. +pub struct LatestVersion { + /// The resolved version string (e.g. "1.22.2"). + pub version: String, + /// The auto-resolved runtime vars. + pub vars: Vec<(String, String)>, +} + +/// What a consumer needs to do to configure a runtime. +/// +/// Returned by `Runtime::setup()`. The consumer matches on this and +/// acts accordingly (prompt, confirm, skip, etc.). +pub enum RuntimeSetup { + /// No runtime vars needed (none, c). + NoVars, + + /// Latest version auto-resolved. Consumer should confirm or let the user + /// override with a custom version (using `Runtime::resolve_version()`). + /// On override failure, fall back to prompting for `fields`. + AutoResolved { + latest: LatestVersion, + fields: &'static [RuntimeField], + optional_fields: &'static [RuntimeField], + }, + + /// No auto-resolution available. Consumer should prompt for each field. + NeedsInput { fields: &'static [RuntimeField] }, + + /// Runtime is too complex for auto-population. Consumer should inform the + /// user to fill in vars manually after init. + ManualOnly, +} + +// ---- Internal resolution functions ---- + +fn resolve_go_latest() -> Result<(String, String, String), Box> { + let resp = http_client().get("https://go.dev/dl/?mode=json").send()?; + let releases: serde_json::Value = resp.json()?; + let arr = releases.as_array().ok_or("Expected array")?; + let release = arr.first().ok_or("No Go releases found")?; + let version = release["version"] + .as_str() + .ok_or("No version field")? + .strip_prefix("go") + .unwrap_or(release["version"].as_str().unwrap()); + let files = release["files"].as_array().ok_or("No files")?; + let file = files + .iter() + .find(|f| { + f["os"].as_str() == Some("linux") + && f["arch"].as_str() == Some("amd64") + && f["kind"].as_str() == Some("archive") + }) + .ok_or("No linux-amd64 archive found")?; + let checksum = file["sha256"].as_str().ok_or("No sha256")?; + let filename = file["filename"].as_str().ok_or("No filename")?; + let url = format!("https://go.dev/dl/{}", filename); + Ok((version.to_string(), url, checksum.to_string())) +} + +fn fetch_go_checksum(version: &str) -> Result> { + let resp = http_client().get("https://go.dev/dl/?mode=json").send()?; + let releases: serde_json::Value = resp.json()?; + let target = format!("go{}", version); + let arr = releases.as_array().ok_or("Expected array")?; + let release = arr + .iter() + .find(|r| r["version"].as_str() == Some(target.as_str())) + .ok_or("Version not found")?; + let files = release["files"].as_array().ok_or("No files")?; + let file = files + .iter() + .find(|f| { + f["os"].as_str() == Some("linux") + && f["arch"].as_str() == Some("amd64") + && f["kind"].as_str() == Some("archive") + }) + .ok_or("No linux-amd64 archive")?; + Ok(file["sha256"].as_str().ok_or("No sha256")?.to_string()) +} + +pub fn go_download_url(version: &str) -> String { + format!("https://go.dev/dl/go{}.linux-amd64.tar.gz", version) +} + +fn fetch_rust_gpg_asc(url: &str) -> Result> { + let asc_url = format!("{}.asc", url); + let resp = http_client().get(&asc_url).send()?; + if !resp.status().is_success() { + return Err(format!("HTTP {}", resp.status()).into()); + } + Ok(resp.text()?) +} + +pub fn rust_download_url(version: &str) -> String { + format!( + "https://static.rust-lang.org/dist/rust-{}-x86_64-unknown-linux-gnu.tar.xz", + version + ) +} + +fn resolve_node_latest() -> Result<(String, String, String), Box> { + let resp = http_client() + .get("https://nodejs.org/dist/index.json") + .send()?; + let releases: serde_json::Value = resp.json()?; + let arr = releases.as_array().ok_or("Expected array")?; + let release = arr + .iter() + .find(|r| r["lts"].is_string()) + .or_else(|| arr.first()) + .ok_or("No Node.js releases found")?; + let version = release["version"] + .as_str() + .ok_or("No version")? + .strip_prefix('v') + .unwrap_or(release["version"].as_str().unwrap()); + let url = node_download_url(version); + let checksum = fetch_node_checksum(version)?; + Ok((version.to_string(), url, checksum)) +} + +fn fetch_node_checksum(version: &str) -> Result> { + let sums_url = format!( + "https://nodejs.org/download/release/v{}/SHASUMS256.txt", + version + ); + let resp = http_client().get(&sums_url).send()?; + let text = resp.text()?; + let target = format!("node-v{}-linux-x64.tar.gz", version); + for line in text.lines() { + if line.contains(&target) { + return Ok(line.split_whitespace().next().unwrap_or("").to_string()); + } + } + Err("Checksum not found in SHASUMS256.txt".into()) +} + +pub fn node_download_url(version: &str) -> String { + format!( + "https://nodejs.org/download/release/v{}/node-v{}-linux-x64.tar.gz", + version, version + ) +} + +pub fn nim_download_url(version: &str) -> String { + format!( + "https://nim-lang.org/download/nim-{}-linux_x64.tar.xz", + version + ) +} + +fn fetch_nim_checksum(version: &str) -> Result> { + let url = nim_download_url(version); + let resp = http_client().get(&url).send()?; + if !resp.status().is_success() { + return Err(format!("HTTP {}", resp.status()).into()); + } + let bytes = resp.bytes()?; + let mut hasher = Sha256::new(); + hasher.update(&bytes); + let hash = format!("{:x}", hasher.finalize()); + Ok(format!("{} nim-{}-linux_x64.tar.xz", hash, version)) +} diff --git a/crates/init/src/tarball.rs b/crates/init/src/tarball.rs new file mode 100644 index 00000000..5b59944b --- /dev/null +++ b/crates/init/src/tarball.rs @@ -0,0 +1,133 @@ +use log::warn; +use sha2::{Digest, Sha256}; +use std::fs; +use std::io::Read; +use std::path::Path; + +use crate::http_client; + +/// Result of downloading and hashing a tarball. +pub struct TarballResult { + /// The computed sha256 hash. + pub hash: String, + /// The local path where the tarball was saved (if downloaded from a URL). + pub local_path: Option, +} + +/// Download a tarball from `url`, save it to `output_dir`, and compute its sha256 hash. +/// +/// If `url` is a local file path, hashes it in place without downloading. +/// If `upstream_hash` is provided, verifies the computed hash matches. +pub fn download_and_hash_tarball( + url: &str, + output_dir: &Path, + upstream_hash: Option<&str>, +) -> Result> { + // Local file: hash it directly + if !url.starts_with("http://") && !url.starts_with("https://") { + if Path::new(url).exists() { + let hash = sha256_file(url)?; + return Ok(TarballResult { + hash, + local_path: None, + }); + } + return Err(format!("Local file not found: {}", url).into()); + } + + let response = http_client().get(url).send()?; + if !response.status().is_success() { + return Err(format!("Failed to download tarball (HTTP {})", response.status()).into()); + } + let bytes = response.bytes()?; + + let mut hasher = Sha256::new(); + hasher.update(&bytes); + let hash = format!("{:x}", hasher.finalize()); + + // Verify against upstream hash if provided + if let Some(upstream) = upstream_hash { + if hash != upstream { + return Err( + format!("Hash mismatch! Computed: {}, Expected: {}", hash, upstream).into(), + ); + } + } else { + try_verify_upstream_hash(url, &hash); + } + + // Save tarball locally + let filename = url.rsplit('/').next().unwrap_or("source.tar.gz"); + let local_path = output_dir.join(filename); + fs::write(&local_path, &bytes)?; + + Ok(TarballResult { + hash, + local_path: Some(local_path), + }) +} + +/// Compute the sha256 hash of a local file. +pub fn sha256_file(path: &str) -> Result> { + let mut file = fs::File::open(path)?; + let mut hasher = Sha256::new(); + let mut buf = [0u8; 8192]; + loop { + let n = file.read(&mut buf)?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + Ok(format!("{:x}", hasher.finalize())) +} + +/// Try to verify the computed hash against upstream checksums. +/// +/// Attempts `{url}.sha256`, `{url}.sha256sum`, and `SHA256SUMS` in the same directory. +/// Logs warnings on mismatch, but does not return an error. +pub fn try_verify_upstream_hash(url: &str, computed_hash: &str) { + for suffix in &[".sha256", ".sha256sum"] { + let hash_url = format!("{}{}", url, suffix); + if let Ok(resp) = http_client().get(&hash_url).send() { + if resp.status().is_success() { + if let Ok(text) = resp.text() { + let upstream = text.trim().split_whitespace().next().unwrap_or(""); + if upstream == computed_hash { + log::info!("Upstream hash verified via {}", hash_url); + } else if !upstream.is_empty() { + warn!( + "Upstream hash mismatch from {}: expected {}, got {}", + hash_url, upstream, computed_hash + ); + } + return; + } + } + } + } + + if let Some(dir_url) = url + .rsplit_once('/') + .map(|(base, _)| format!("{}/SHA256SUMS", base)) + { + if let Ok(resp) = http_client().get(&dir_url).send() { + if resp.status().is_success() { + if let Ok(text) = resp.text() { + let filename = url.rsplit('/').next().unwrap_or(""); + for line in text.lines() { + if line.contains(filename) { + let hash = line.split_whitespace().next().unwrap_or(""); + if hash == computed_hash { + log::info!("Upstream hash verified via SHA256SUMS"); + } else { + warn!("Upstream hash mismatch from SHA256SUMS"); + } + return; + } + } + } + } + } + } +} diff --git a/crates/update/Cargo.toml b/crates/update/Cargo.toml new file mode 100644 index 00000000..3eb072df --- /dev/null +++ b/crates/update/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "pkg-builder-update" +version = "0.4.0-rc.1" +edition = "2021" +license.workspace = true + +[dependencies] +pkg-builder-config = { path = "../config" } +pkg-builder-init = { path = "../init" } +reqwest = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +log = { workspace = true } +toml = { workspace = true } +toml_edit = { workspace = true } +chrono = { workspace = true } +regex = { workspace = true } +tempfile = { workspace = true } +thiserror = { workspace = true } +dialoguer = { workspace = true } diff --git a/crates/update/src/changelog.rs b/crates/update/src/changelog.rs new file mode 100644 index 00000000..6bfaee00 --- /dev/null +++ b/crates/update/src/changelog.rs @@ -0,0 +1,164 @@ +use chrono::Utc; +use std::path::Path; + +/// Generate a new Debian changelog entry. +/// +/// Returns the formatted entry as a string, ready to be prepended to an existing changelog. +pub fn new_changelog_entry( + package_name: &str, + version: &str, + revision: &str, + distribution: &str, + maintainer: &str, + message: &str, +) -> String { + let date = Utc::now().format("%a, %d %b %Y %H:%M:%S %z").to_string(); + format!( + "{} ({}-{}) {}; urgency=medium\n\n * {}\n\n -- {} {}\n", + package_name, version, revision, distribution, message, maintainer, date + ) +} + +/// Prepend a new changelog entry to an existing debian/changelog file. +/// +/// If the file doesn't exist, creates it with just the new entry. +pub fn prepend_changelog_entry( + changelog_path: &Path, + entry: &str, +) -> Result<(), Box> { + let existing = if changelog_path.exists() { + std::fs::read_to_string(changelog_path)? + } else { + String::new() + }; + + let new_content = if existing.is_empty() { + entry.to_string() + } else { + format!("{}\n{}", entry, existing) + }; + + if let Some(parent) = changelog_path.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write(changelog_path, new_content)?; + Ok(()) +} + +/// Try to extract the maintainer string from a .sss file. +/// +/// Looks for a line like `maintainer: "Name "` or `maintainer = "Name "`. +pub fn extract_maintainer_from_sss(sss_path: &Path) -> Option { + let content = std::fs::read_to_string(sss_path).ok()?; + for line in content.lines() { + let trimmed = line.trim(); + if let Some(rest) = trimmed.strip_prefix("maintainer") { + let rest = rest.trim(); + let rest = rest.strip_prefix(':').or_else(|| rest.strip_prefix('='))?; + let rest = rest.trim(); + let value = rest.trim_matches('"').trim_matches('\''); + if !value.is_empty() { + return Some(value.to_string()); + } + } + } + None +} + +/// Try to find a .sss file in the package directory and extract the maintainer. +pub fn find_maintainer(config_root: &Path) -> Option { + if let Ok(entries) = std::fs::read_dir(config_root) { + for entry in entries.flatten() { + let path = entry.path(); + if path.extension().and_then(|e| e.to_str()) == Some("sss") { + if let Some(m) = extract_maintainer_from_sss(&path) { + return Some(m); + } + } + } + } + None +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + #[test] + fn test_new_changelog_entry_format() { + let entry = new_changelog_entry( + "geth", + "1.15.0", + "1", + "bookworm", + "Test User ", + "New upstream version 1.15.0", + ); + + assert!(entry.starts_with("geth (1.15.0-1) bookworm; urgency=medium")); + assert!(entry.contains("* New upstream version 1.15.0")); + assert!(entry.contains("-- Test User ")); + } + + #[test] + fn test_prepend_to_existing_changelog() { + let dir = tempdir().unwrap(); + let changelog_path = dir.path().join("debian").join("changelog"); + fs::create_dir_all(changelog_path.parent().unwrap()).unwrap(); + fs::write( + &changelog_path, + "old-pkg (1.0.0-1) bookworm; urgency=medium\n\n * Old entry\n\n -- Old Mon, 01 Jan 2024 00:00:00 +0000\n", + ) + .unwrap(); + + let entry = new_changelog_entry( + "old-pkg", + "2.0.0", + "1", + "bookworm", + "New ", + "New upstream version 2.0.0", + ); + prepend_changelog_entry(&changelog_path, &entry).unwrap(); + + let content = fs::read_to_string(&changelog_path).unwrap(); + assert!(content.starts_with("old-pkg (2.0.0-1)")); + assert!(content.contains("Old entry")); + } + + #[test] + fn test_extract_maintainer_from_sss() { + let dir = tempdir().unwrap(); + let sss_path = dir.path().join("test.sss"); + fs::write( + &sss_path, + "name: test\nmaintainer: \"Test User \"\n", + ) + .unwrap(); + + let m = extract_maintainer_from_sss(&sss_path); + assert_eq!(m, Some("Test User ".to_string())); + } + + #[test] + fn test_prepend_creates_file_if_missing() { + let dir = tempdir().unwrap(); + let changelog_path = dir.path().join("src").join("debian").join("changelog"); + + let entry = new_changelog_entry( + "test", + "1.0.0", + "1", + "bookworm", + "Test ", + "Initial release", + ); + prepend_changelog_entry(&changelog_path, &entry).unwrap(); + + assert!(changelog_path.exists()); + let content = fs::read_to_string(&changelog_path).unwrap(); + assert!(content.contains("Initial release")); + } +} diff --git a/crates/update/src/files.rs b/crates/update/src/files.rs new file mode 100644 index 00000000..cdd9254b --- /dev/null +++ b/crates/update/src/files.rs @@ -0,0 +1,228 @@ +use log::{debug, info}; +use regex::Regex; +use std::fs; +use std::path::Path; + +/// Substitutions to apply across all files in the package directory. +pub struct FileSubstitutions { + pub old_version: String, + pub new_version: String, + pub old_hash: Option, + pub new_hash: Option, + pub old_tag: Option, + pub new_tag: Option, + pub old_commit: Option, + pub new_commit: Option, +} + +/// Files to skip during substitution (already handled or should not be modified). +const SKIP_FILES: &[&str] = &["pkg-builder.toml", "pkg-builder-verify.toml"]; + +/// Walk the package directory and apply version/hash substitutions to all text files. +/// +/// Returns the list of files that were modified. +pub fn apply_substitutions( + dir: &Path, + subs: &FileSubstitutions, +) -> Result, Box> { + let mut modified = Vec::new(); + walk_and_substitute(dir, dir, subs, &mut modified)?; + Ok(modified) +} + +fn walk_and_substitute( + root: &Path, + dir: &Path, + subs: &FileSubstitutions, + modified: &mut Vec, +) -> Result<(), Box> { + let entries = fs::read_dir(dir)?; + for entry in entries { + let entry = entry?; + let path = entry.path(); + + if path.is_dir() { + // Skip hidden directories + if path + .file_name() + .and_then(|n| n.to_str()) + .is_some_and(|n| n.starts_with('.')) + { + continue; + } + walk_and_substitute(root, &path, subs, modified)?; + continue; + } + + let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + + if SKIP_FILES.contains(&file_name) { + debug!("Skipping {}", path.display()); + continue; + } + + if is_binary(&path)? { + debug!("Skipping binary file {}", path.display()); + continue; + } + + let content = fs::read_to_string(&path)?; + let new_content = substitute_content(&content, subs); + + if new_content != content { + let rel = path.strip_prefix(root).unwrap_or(&path); + info!("Updated: {}", rel.display()); + fs::write(&path, &new_content)?; + modified.push(rel.display().to_string()); + } + } + Ok(()) +} + +/// Apply all substitutions to a string, using word-boundary-aware replacement. +fn substitute_content(content: &str, subs: &FileSubstitutions) -> String { + let mut result = content.to_string(); + + // Replace version with word boundaries to avoid partial matches + result = replace_with_boundaries(&result, &subs.old_version, &subs.new_version); + + if let (Some(ref old_hash), Some(ref new_hash)) = (&subs.old_hash, &subs.new_hash) { + if old_hash != new_hash { + result = result.replace(old_hash, new_hash); + } + } + + if let (Some(ref old_tag), Some(ref new_tag)) = (&subs.old_tag, &subs.new_tag) { + if old_tag != new_tag { + result = replace_with_boundaries(&result, old_tag, new_tag); + } + } + + if let (Some(ref old_commit), Some(ref new_commit)) = (&subs.old_commit, &subs.new_commit) { + if old_commit != new_commit { + result = result.replace(old_commit, new_commit); + } + } + + result +} + +/// Replace a string only at word boundaries (to avoid "1.0.0" matching inside "1.0.0-beta1"). +fn replace_with_boundaries(content: &str, old: &str, new: &str) -> String { + if old == new || old.is_empty() { + return content.to_string(); + } + let pattern = format!(r"(? re.replace_all(content, new).to_string(), + Err(_) => content.replace(old, new), + } +} + +/// Check if a file is binary by looking for null bytes in the first 512 bytes. +fn is_binary(path: &Path) -> Result { + let content = fs::read(path)?; + let check_len = content.len().min(512); + Ok(content[..check_len].contains(&0)) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + #[test] + fn test_version_substitution() { + let subs = FileSubstitutions { + old_version: "1.14.0".to_string(), + new_version: "1.15.0".to_string(), + old_hash: None, + new_hash: None, + old_tag: None, + new_tag: None, + old_commit: None, + new_commit: None, + }; + + let input = "version = 1.14.0\nurl = https://example.com/pkg-1.14.0.tar.gz\n"; + let result = substitute_content(input, &subs); + assert!(result.contains("1.15.0")); + assert!(!result.contains("1.14.0")); + } + + #[test] + fn test_hash_substitution() { + let subs = FileSubstitutions { + old_version: "1.0.0".to_string(), + new_version: "2.0.0".to_string(), + old_hash: Some("abc123".to_string()), + new_hash: Some("def456".to_string()), + old_tag: None, + new_tag: None, + old_commit: None, + new_commit: None, + }; + + let input = "hash = abc123\n"; + let result = substitute_content(input, &subs); + assert!(result.contains("def456")); + assert!(!result.contains("abc123")); + } + + #[test] + fn test_skips_pkg_builder_toml() { + let dir = tempdir().unwrap(); + fs::write(dir.path().join("pkg-builder.toml"), "version = \"1.0.0\"\n").unwrap(); + fs::write(dir.path().join("other.txt"), "version = 1.0.0\n").unwrap(); + + let subs = FileSubstitutions { + old_version: "1.0.0".to_string(), + new_version: "2.0.0".to_string(), + old_hash: None, + new_hash: None, + old_tag: None, + new_tag: None, + old_commit: None, + new_commit: None, + }; + + let modified = apply_substitutions(dir.path(), &subs).unwrap(); + assert_eq!(modified.len(), 1); + assert!(modified[0].contains("other.txt")); + + // pkg-builder.toml should be untouched + let toml_content = fs::read_to_string(dir.path().join("pkg-builder.toml")).unwrap(); + assert!(toml_content.contains("1.0.0")); + } + + #[test] + fn test_skips_binary_files() { + let dir = tempdir().unwrap(); + let mut binary_content = vec![0u8; 100]; + binary_content[50] = 0; // null byte + fs::write(dir.path().join("binary.dat"), &binary_content).unwrap(); + + let subs = FileSubstitutions { + old_version: "1.0.0".to_string(), + new_version: "2.0.0".to_string(), + old_hash: None, + new_hash: None, + old_tag: None, + new_tag: None, + old_commit: None, + new_commit: None, + }; + + let modified = apply_substitutions(dir.path(), &subs).unwrap(); + assert!(modified.is_empty()); + } + + #[test] + fn test_word_boundary_replacement() { + let result = replace_with_boundaries("v1.0.0 and 1.0.0-beta1", "1.0.0", "2.0.0"); + // Should replace the standalone 1.0.0 (after v) but the word boundary logic + // should handle the -beta1 case + assert!(result.contains("2.0.0")); + } +} diff --git a/crates/update/src/github.rs b/crates/update/src/github.rs new file mode 100644 index 00000000..6a8b1d3a --- /dev/null +++ b/crates/update/src/github.rs @@ -0,0 +1,161 @@ +use log::info; +use pkg_builder_init::http_client; + +/// Parse a GitHub "owner/repo" from a source URL. +/// +/// Handles URLs like: +/// - `https://github.com/owner/repo/archive/refs/tags/v1.0.0.tar.gz` +/// - `https://github.com/owner/repo.git` +/// - `https://github.com/owner/repo/releases/download/v1.0.0/file.tar.gz` +pub fn parse_github_repo(url: &str) -> Option { + let url = url + .strip_prefix("https://github.com/") + .or_else(|| url.strip_prefix("http://github.com/"))?; + + let parts: Vec<&str> = url.splitn(4, '/').collect(); + if parts.len() < 2 { + return None; + } + let owner = parts[0]; + let repo = parts[1].strip_suffix(".git").unwrap_or(parts[1]); + Some(format!("{}/{}", owner, repo)) +} + +/// Fetch the latest release tag from a GitHub repository. +/// +/// Returns the tag name (e.g., "v1.15.0") and the version with "v" prefix stripped. +pub fn fetch_latest_release( + owner_repo: &str, +) -> Result<(String, String), Box> { + let url = format!( + "https://api.github.com/repos/{}/releases/latest", + owner_repo + ); + let client = http_client(); + + let mut request = client + .get(&url) + .header("Accept", "application/vnd.github+json"); + + if let Ok(token) = std::env::var("GITHUB_TOKEN") { + request = request.header("Authorization", format!("Bearer {}", token)); + } + + let resp = request.send()?; + if !resp.status().is_success() { + return Err(format!( + "GitHub API error (HTTP {}): {}", + resp.status(), + resp.text().unwrap_or_default() + ) + .into()); + } + + let json: serde_json::Value = resp.json()?; + let tag_name = json["tag_name"] + .as_str() + .ok_or("No tag_name in release response")?; + + let version = tag_name.strip_prefix('v').unwrap_or(tag_name); + info!( + "Latest release for {}: {} (version {})", + owner_repo, tag_name, version + ); + + Ok((tag_name.to_string(), version.to_string())) +} + +/// Fetch the commit SHA for a given tag. +pub fn fetch_tag_commit(owner_repo: &str, tag: &str) -> Result> { + let url = format!( + "https://api.github.com/repos/{}/git/ref/tags/{}", + owner_repo, tag + ); + let client = http_client(); + + let mut request = client + .get(&url) + .header("Accept", "application/vnd.github+json"); + if let Ok(token) = std::env::var("GITHUB_TOKEN") { + request = request.header("Authorization", format!("Bearer {}", token)); + } + + let resp = request.send()?; + if !resp.status().is_success() { + return Err(format!( + "GitHub API error fetching tag {}: HTTP {}", + tag, + resp.status() + ) + .into()); + } + + let json: serde_json::Value = resp.json()?; + let obj_type = json["object"]["type"].as_str().unwrap_or(""); + let sha = json["object"]["sha"] + .as_str() + .ok_or("No sha in tag ref response")?; + + // If it's an annotated tag, we need to dereference to get the commit + if obj_type == "tag" { + let tag_url = format!( + "https://api.github.com/repos/{}/git/tags/{}", + owner_repo, sha + ); + let mut request = client + .get(&tag_url) + .header("Accept", "application/vnd.github+json"); + if let Ok(token) = std::env::var("GITHUB_TOKEN") { + request = request.header("Authorization", format!("Bearer {}", token)); + } + let resp = request.send()?; + let json: serde_json::Value = resp.json()?; + let commit_sha = json["object"]["sha"] + .as_str() + .ok_or("No sha in annotated tag response")?; + Ok(commit_sha.to_string()) + } else { + Ok(sha.to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_github_repo_archive_url() { + let url = "https://github.com/ethereum/go-ethereum/archive/refs/tags/v1.14.0.tar.gz"; + assert_eq!( + parse_github_repo(url), + Some("ethereum/go-ethereum".to_string()) + ); + } + + #[test] + fn test_parse_github_repo_release_url() { + let url = "https://github.com/sigp/lighthouse/releases/download/v5.0.0/lighthouse-v5.0.0-x86_64-unknown-linux-gnu.tar.gz"; + assert_eq!(parse_github_repo(url), Some("sigp/lighthouse".to_string())); + } + + #[test] + fn test_parse_github_repo_git_url() { + let url = "https://github.com/prysmaticlabs/prysm.git"; + assert_eq!( + parse_github_repo(url), + Some("prysmaticlabs/prysm".to_string()) + ); + } + + #[test] + fn test_parse_github_repo_non_github() { + let url = "https://example.com/foo/bar.tar.gz"; + assert_eq!(parse_github_repo(url), None); + } + + #[test] + fn test_parse_github_repo_short() { + let url = "https://github.com/owner/repo"; + assert_eq!(parse_github_repo(url), Some("owner/repo".to_string())); + } +} diff --git a/crates/update/src/lib.rs b/crates/update/src/lib.rs new file mode 100644 index 00000000..e552158a --- /dev/null +++ b/crates/update/src/lib.rs @@ -0,0 +1,587 @@ +pub mod changelog; +pub mod files; +pub mod github; +pub mod patches; +pub mod toml_rewrite; + +use changelog::{find_maintainer, new_changelog_entry, prepend_changelog_entry}; +use config::PkgConfig; +use files::{apply_substitutions, FileSubstitutions}; +use github::{fetch_latest_release, fetch_tag_commit, parse_github_repo}; +use log::{info, warn}; +use patches::test_patches; +use std::path::{Path, PathBuf}; +use thiserror::Error; +use toml_rewrite::{rewrite_toml, TomlUpdates}; + +#[derive(Debug, Error)] +pub enum UpdateError { + #[error("Config error: {0}")] + Config(#[from] config::ConfigError), + #[error("{0}")] + Other(String), + #[error(transparent)] + Io(#[from] std::io::Error), +} + +impl From> for UpdateError { + fn from(e: Box) -> Self { + UpdateError::Other(e.to_string()) + } +} + +/// Configuration for the update command. +pub struct UpdateConfig { + pub version: Option, + pub revision: String, + pub changelog_msg: Option, + pub github_repo: Option, + pub in_place: bool, + pub output: Option, + pub hash: Option, + pub git_commit: Option, + pub skip_download: bool, + pub update_runtime: bool, + pub skip_patch_check: bool, +} + +/// Summary of what was updated. +pub struct UpdateSummary { + pub old_version: String, + pub new_version: String, + pub new_revision: String, + pub source_hash: Option, + pub git_commit: Option, + pub runtime_updated: bool, + pub files_modified: Vec, + pub patch_summary: Option, + pub output_dir: PathBuf, +} + +/// Run the update process. +pub fn run_update( + config_path: &Path, + update_cfg: &UpdateConfig, +) -> Result { + // Stage 1: Load current state + info!("Loading current config..."); + let config = PkgConfig::load(config_path)?; + let config_root = config.config_root.clone(); + let old_version = config.package.version.clone(); + + let (old_source_url, old_hash, old_tag) = match &config.source { + config::source::SourceKind::Tarball { url, hash } => { + (Some(url.clone()), hash.clone(), None) + } + config::source::SourceKind::Git { url, tag, .. } => { + (Some(url.clone()), None, Some(tag.clone())) + } + config::source::SourceKind::Virtual => (None, None, None), + }; + + // Stage 2: Determine new version + let (new_version, new_tag_name) = resolve_new_version( + &update_cfg.version, + &update_cfg.github_repo, + old_source_url.as_deref(), + )?; + info!("Updating {} -> {}", old_version, new_version); + + // Stage 3: Resolve new source + let (new_source_url, new_hash, new_commit, _temp_dir) = resolve_new_source( + &config, + &old_version, + &new_version, + &new_tag_name, + old_source_url.as_deref(), + update_cfg, + )?; + + // Resolve runtime updates + let runtime_vars = if update_cfg.update_runtime { + resolve_runtime_update(&config)? + } else { + None + }; + + // Determine output directory + let output_dir = determine_output_dir(&config_root, update_cfg)?; + + // If --output, copy the entire package directory first + if update_cfg.output.is_some() && output_dir != config_root { + info!("Copying package directory to {}...", output_dir.display()); + copy_dir_recursive(&config_root, &output_dir)?; + } + + // Stage 4: Rewrite pkg-builder.toml + info!("Updating pkg-builder.toml..."); + let toml_path = output_dir.join("pkg-builder.toml"); + let updates = TomlUpdates { + version: Some(new_version.clone()), + revision: Some(update_cfg.revision.clone()), + source_url: new_source_url.clone(), + source_hash: new_hash.clone(), + source_tag: new_tag_name.clone(), + runtime_vars, + }; + let new_toml = rewrite_toml(&toml_path, &updates)?; + std::fs::write(&toml_path, &new_toml)?; + + // Stage 5: Update changelog + info!("Updating changelog..."); + let changelog_path = output_dir.join("src").join("debian").join("changelog"); + let distribution = config.build_env.distribution.as_short(); + let maintainer = + find_maintainer(&output_dir).unwrap_or_else(|| "Unknown ".to_string()); + let default_msg = format!("New upstream version {}", new_version); + let changelog_msg = update_cfg.changelog_msg.as_deref().unwrap_or(&default_msg); + let entry = new_changelog_entry( + &config.package.name, + &new_version, + &update_cfg.revision, + distribution, + &maintainer, + changelog_msg, + ); + prepend_changelog_entry(&changelog_path, &entry)?; + + // Stage 6: Test patches + let patch_summary = + if !update_cfg.skip_patch_check && !update_cfg.skip_download && update_cfg.hash.is_none() { + let patches_dir = output_dir.join("src").join("debian").join("patches"); + if patches_dir.exists() { + // We need the extracted source for patch testing + // For now, if we have a temp dir with source, use it + // Otherwise skip + if let Some(ref _temp) = _temp_dir { + let interactive = atty_is_interactive(); + match test_patches(_temp.path(), &patches_dir, &output_dir, interactive) { + Ok(result) => { + let summary = result.summary(); + info!("Patch test: {}", summary); + Some(summary) + } + Err(e) => { + warn!("Patch testing failed: {}", e); + Some(format!("error: {}", e)) + } + } + } else { + info!("No extracted source available for patch testing"); + None + } + } else { + None + } + } else { + None + }; + + // Stage 7: Update other files + info!("Updating version strings in package files..."); + let subs = FileSubstitutions { + old_version: old_version.clone(), + new_version: new_version.clone(), + old_hash: old_hash.clone(), + new_hash: new_hash.clone(), + old_tag: old_tag.clone(), + new_tag: new_tag_name.clone(), + old_commit: None, + new_commit: new_commit.clone(), + }; + let files_modified = apply_substitutions(&output_dir, &subs)?; + + Ok(UpdateSummary { + old_version, + new_version: new_version.clone(), + new_revision: update_cfg.revision.clone(), + source_hash: new_hash, + git_commit: new_commit, + runtime_updated: update_cfg.update_runtime, + files_modified, + patch_summary, + output_dir, + }) +} + +/// Stage 2: Resolve the new version, either from CLI flag or GitHub API. +fn resolve_new_version( + version_flag: &Option, + github_repo_flag: &Option, + source_url: Option<&str>, +) -> Result<(String, Option), UpdateError> { + if let Some(version) = version_flag { + // If explicit version given, try to construct a tag name + let tag = if version.starts_with('v') { + Some(version.clone()) + } else { + Some(format!("v{}", version)) + }; + let clean_version = version.strip_prefix('v').unwrap_or(version).to_string(); + return Ok((clean_version, tag)); + } + + // Auto-detect from GitHub + let repo = github_repo_flag + .clone() + .or_else(|| source_url.and_then(parse_github_repo)) + .ok_or_else(|| { + UpdateError::Other( + "Cannot determine GitHub repo. Use --version or --github-repo.".to_string(), + ) + })?; + + let (tag_name, version) = fetch_latest_release(&repo)?; + Ok((version, Some(tag_name))) +} + +type SourceResolution = ( + Option, + Option, + Option, + Option, +); + +/// Stage 3: Resolve new source URL, hash, and commit. +fn resolve_new_source( + config: &PkgConfig, + old_version: &str, + new_version: &str, + new_tag: &Option, + old_source_url: Option<&str>, + update_cfg: &UpdateConfig, +) -> Result { + // If hash was provided directly, skip download + if let Some(ref hash) = update_cfg.hash { + let new_url = old_source_url.map(|url| url.replace(old_version, new_version)); + return Ok(( + new_url, + Some(hash.clone()), + update_cfg.git_commit.clone(), + None, + )); + } + + // If git commit was provided directly + if let Some(ref commit) = update_cfg.git_commit { + return Ok((None, None, Some(commit.clone()), None)); + } + + match &config.source { + config::source::SourceKind::Tarball { url, .. } => { + let new_url = url.replace(old_version, new_version); + + if update_cfg.skip_download { + return Ok((Some(new_url), None, None, None)); + } + + // Download and hash + let temp_dir = tempfile::tempdir()?; + match pkg_builder_init::download_and_hash_tarball(&new_url, temp_dir.path(), None) { + Ok(result) => { + info!("Downloaded and hashed: {}", result.hash); + // Extract for patch testing + let extract_dir = tempfile::tempdir()?; + if let Some(ref local_path) = result.local_path { + extract_tarball(local_path, extract_dir.path())?; + } + Ok((Some(new_url), Some(result.hash), None, Some(extract_dir))) + } + Err(e) => { + warn!("Failed to download {}: {}", new_url, e); + Ok((Some(new_url), None, None, None)) + } + } + } + config::source::SourceKind::Git { url, .. } => { + let default_tag = format!("v{}", new_version); + let new_tag_str = new_tag.as_deref().unwrap_or(&default_tag); + + // Try to get commit SHA from GitHub + let commit = if !update_cfg.skip_download { + if let Some(repo) = update_cfg + .github_repo + .clone() + .or_else(|| parse_github_repo(url)) + { + match fetch_tag_commit(&repo, new_tag_str) { + Ok(sha) => { + info!("Commit for tag {}: {}", new_tag_str, sha); + Some(sha) + } + Err(e) => { + warn!("Could not fetch commit for tag {}: {}", new_tag_str, e); + None + } + } + } else { + None + } + } else { + None + }; + + Ok((None, None, commit, None)) + } + config::source::SourceKind::Virtual => Ok((None, None, None, None)), + } +} + +/// Resolve runtime update by fetching latest versions. +fn resolve_runtime_update( + config: &PkgConfig, +) -> Result>, UpdateError> { + if let Some(ref rt) = config.runtime { + if let Some(runtime) = pkg_builder_init::Runtime::from_str(&rt.profile) { + match runtime.resolve_version( + // Try to extract current version from runtime vars + &extract_runtime_version(&rt.vars).unwrap_or_default(), + ) { + Ok(vars) => { + info!("Runtime updated"); + return Ok(Some(vars)); + } + Err(e) => { + warn!("Could not auto-update runtime: {}", e); + } + } + } + } + Ok(None) +} + +/// Try to extract a version from runtime variables (e.g., from binary_url). +fn extract_runtime_version( + vars: &std::collections::BTreeMap, +) -> Option { + // Try to find a version in the binary_url + if let Some(url) = vars.get("binary_url").and_then(|v| v.as_str()) { + // Look for version-like patterns in the URL + let re = regex::Regex::new(r"(\d+\.\d+\.\d+)").ok()?; + if let Some(cap) = re.captures(url) { + return Some(cap[1].to_string()); + } + } + None +} + +fn determine_output_dir( + config_root: &Path, + update_cfg: &UpdateConfig, +) -> Result { + if let Some(ref output) = update_cfg.output { + Ok(PathBuf::from(output)) + } else if update_cfg.in_place { + Ok(config_root.to_path_buf()) + } else { + // Default: in-place (non-interactive mode) or prompt + if atty_is_interactive() { + let choices = &["Update in-place", "Write to new directory"]; + let selection = dialoguer::Select::new() + .with_prompt("How should the update be written?") + .items(choices) + .default(0) + .interact() + .map_err(|e| UpdateError::Other(e.to_string()))?; + + match selection { + 0 => Ok(config_root.to_path_buf()), + 1 => { + let dir: String = dialoguer::Input::new() + .with_prompt("Output directory") + .interact_text() + .map_err(|e| UpdateError::Other(e.to_string()))?; + Ok(PathBuf::from(dir)) + } + _ => unreachable!(), + } + } else { + // Non-interactive: default to in-place + Ok(config_root.to_path_buf()) + } + } +} + +/// Check if stdin is a TTY (interactive mode). +fn atty_is_interactive() -> bool { + use std::io::IsTerminal; + std::io::stdin().is_terminal() +} + +/// Extract a tarball to a destination directory. +fn extract_tarball(tarball: &Path, dest: &Path) -> Result<(), Box> { + let status = std::process::Command::new("tar") + .args([ + "xf", + &tarball.display().to_string(), + "--strip-components=1", + "-C", + &dest.display().to_string(), + ]) + .status()?; + if !status.success() { + return Err(format!("tar extraction failed for {}", tarball.display()).into()); + } + Ok(()) +} + +/// Recursively copy a directory. +fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), UpdateError> { + std::fs::create_dir_all(dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dst_path = dst.join(entry.file_name()); + + if src_path.is_dir() { + copy_dir_recursive(&src_path, &dst_path)?; + } else { + std::fs::copy(&src_path, &dst_path)?; + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + fn write_test_config(dir: &Path) { + fs::write( + dir.join("pkg-builder.toml"), + r#"[package] +name = "test-pkg" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test-pkg.sss" + +[source] +type = "tarball" +url = "https://github.com/example/test-pkg/archive/refs/tags/v1.0.0.tar.gz" +hash = "abc123def456" + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "/tmp/test" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +"#, + ) + .unwrap(); + + fs::write( + dir.join("test-pkg.sss"), + "name: test-pkg\nmaintainer: \"Test User \"\n", + ) + .unwrap(); + + // Create a file with version strings + fs::create_dir_all(dir.join("src").join("debian")).unwrap(); + fs::write( + dir.join("src").join("debian").join("rules"), + "#!/usr/bin/make -f\nVERSION=1.0.0\nHASH=abc123def456\n", + ) + .unwrap(); + } + + #[test] + fn test_update_in_place_with_skip_download() { + let dir = tempdir().unwrap(); + write_test_config(dir.path()); + + let update_cfg = UpdateConfig { + version: Some("2.0.0".to_string()), + revision: "1".to_string(), + changelog_msg: Some("Test update".to_string()), + github_repo: None, + in_place: true, + output: None, + hash: Some("newsha256hash".to_string()), + git_commit: None, + skip_download: false, + update_runtime: false, + skip_patch_check: true, + }; + + let summary = run_update(dir.path(), &update_cfg).unwrap(); + assert_eq!(summary.old_version, "1.0.0"); + assert_eq!(summary.new_version, "2.0.0"); + + // Check TOML was updated + let toml_content = fs::read_to_string(dir.path().join("pkg-builder.toml")).unwrap(); + assert!(toml_content.contains("version = \"2.0.0\"")); + assert!(toml_content.contains("hash = \"newsha256hash\"")); + assert!(toml_content.contains("v2.0.0.tar.gz")); + + // Check other files were updated + let rules = fs::read_to_string(dir.path().join("src/debian/rules")).unwrap(); + assert!(rules.contains("VERSION=2.0.0")); + assert!(rules.contains("HASH=newsha256hash")); + + // Check changelog was created + let changelog = fs::read_to_string(dir.path().join("src/debian/changelog")).unwrap(); + assert!(changelog.contains("test-pkg (2.0.0-1)")); + assert!(changelog.contains("Test update")); + } + + #[test] + fn test_update_to_output_dir() { + let dir = tempdir().unwrap(); + write_test_config(dir.path()); + + let output_dir = tempdir().unwrap(); + + let update_cfg = UpdateConfig { + version: Some("3.0.0".to_string()), + revision: "1".to_string(), + changelog_msg: None, + github_repo: None, + in_place: false, + output: Some(output_dir.path().display().to_string()), + hash: Some("outputhash".to_string()), + git_commit: None, + skip_download: false, + update_runtime: false, + skip_patch_check: true, + }; + + let summary = run_update(dir.path(), &update_cfg).unwrap(); + assert_eq!(summary.new_version, "3.0.0"); + + // Original should be unchanged + let original_toml = fs::read_to_string(dir.path().join("pkg-builder.toml")).unwrap(); + assert!(original_toml.contains("version = \"1.0.0\"")); + + // Output should have updates + let output_toml = fs::read_to_string(output_dir.path().join("pkg-builder.toml")).unwrap(); + assert!(output_toml.contains("version = \"3.0.0\"")); + } + + #[test] + fn test_resolve_new_version_explicit() { + let (version, tag) = resolve_new_version(&Some("1.15.0".to_string()), &None, None).unwrap(); + assert_eq!(version, "1.15.0"); + assert_eq!(tag, Some("v1.15.0".to_string())); + } + + #[test] + fn test_resolve_new_version_with_v_prefix() { + let (version, tag) = + resolve_new_version(&Some("v1.15.0".to_string()), &None, None).unwrap(); + assert_eq!(version, "1.15.0"); + assert_eq!(tag, Some("v1.15.0".to_string())); + } + + #[test] + fn test_resolve_new_version_no_source() { + let result = resolve_new_version(&None, &None, None); + assert!(result.is_err()); + } +} diff --git a/crates/update/src/patches.rs b/crates/update/src/patches.rs new file mode 100644 index 00000000..6f6d7225 --- /dev/null +++ b/crates/update/src/patches.rs @@ -0,0 +1,334 @@ +use dialoguer::Select; +use log::{info, warn}; +use std::path::Path; +use std::process::Command; + +/// Result of testing patches against a new source. +pub struct PatchTestResult { + pub applied_cleanly: usize, + pub fixed_interactively: usize, + pub skipped: usize, + pub aborted: bool, +} + +impl PatchTestResult { + pub fn summary(&self) -> String { + let mut parts = Vec::new(); + if self.applied_cleanly > 0 { + parts.push(format!("{} applied cleanly", self.applied_cleanly)); + } + if self.fixed_interactively > 0 { + parts.push(format!("{} fixed interactively", self.fixed_interactively)); + } + if self.skipped > 0 { + parts.push(format!("{} skipped", self.skipped)); + } + if self.aborted { + parts.push("aborted".to_string()); + } + if parts.is_empty() { + "no patches to test".to_string() + } else { + parts.join(", ") + } + } +} + +/// Test patches against extracted source in a temp directory. +/// +/// - `source_dir`: extracted upstream source (temp dir) +/// - `patches_dir`: package's `src/debian/patches/` directory +/// - `interactive`: whether to prompt on failure (false = just report) +/// +/// Returns the patch test result and optionally updates patches in-place if fixed. +pub fn test_patches( + source_dir: &Path, + patches_dir: &Path, + package_dir: &Path, + interactive: bool, +) -> Result> { + let series_path = patches_dir.join("series"); + if !series_path.exists() { + info!("No patches/series file found, skipping patch test"); + return Ok(PatchTestResult { + applied_cleanly: 0, + fixed_interactively: 0, + skipped: 0, + aborted: false, + }); + } + + let series_content = std::fs::read_to_string(&series_path)?; + let patches: Vec<&str> = series_content + .lines() + .map(|l| l.trim()) + .filter(|l| !l.is_empty() && !l.starts_with('#')) + .collect(); + + if patches.is_empty() { + info!("No patches in series file"); + return Ok(PatchTestResult { + applied_cleanly: 0, + fixed_interactively: 0, + skipped: 0, + aborted: false, + }); + } + + info!("Testing {} patches against new source...", patches.len()); + + // Copy patches into the source dir for quilt + let dest_patches = source_dir.join("debian").join("patches"); + copy_dir_recursive(patches_dir, &dest_patches)?; + + // Also copy .pc directory if it exists + let pc_src = package_dir.join("src").join(".pc"); + if pc_src.exists() { + let pc_dest = source_dir.join(".pc"); + copy_dir_recursive(&pc_src, &pc_dest)?; + } + + let mut result = PatchTestResult { + applied_cleanly: 0, + fixed_interactively: 0, + skipped: 0, + aborted: false, + }; + + let quilt_patches = dest_patches.display().to_string(); + + for patch_name in &patches { + info!("Applying patch: {}", patch_name); + + let output = Command::new("quilt") + .arg("push") + .env("QUILT_PATCHES", &quilt_patches) + .current_dir(source_dir) + .output()?; + + if output.status.success() { + result.applied_cleanly += 1; + info!(" OK: {}", patch_name); + continue; + } + + let stderr = String::from_utf8_lossy(&output.stderr); + let stdout = String::from_utf8_lossy(&output.stdout); + warn!( + "Patch {} failed to apply:\n{}\n{}", + patch_name, stdout, stderr + ); + + if !interactive { + warn!("Non-interactive mode: skipping failed patch {}", patch_name); + result.skipped += 1; + continue; + } + + let choices = &[ + "Drop to shell (fix manually, then exit)", + "Force apply + drop to shell (resolve .rej files)", + "Skip this patch (remove from series)", + "Abort patch testing", + ]; + + let selection = Select::new() + .with_prompt(format!( + "Patch '{}' failed. What would you like to do?", + patch_name + )) + .items(choices) + .default(0) + .interact()?; + + match selection { + 0 => { + // Drop to shell + if drop_to_shell(source_dir, &quilt_patches)? { + copy_refreshed_patches(&dest_patches, patches_dir)?; + result.fixed_interactively += 1; + } else { + result.skipped += 1; + } + } + 1 => { + // Force apply + drop to shell + let _ = Command::new("quilt") + .args(["push", "-f"]) + .env("QUILT_PATCHES", &quilt_patches) + .current_dir(source_dir) + .status(); + + if drop_to_shell(source_dir, &quilt_patches)? { + copy_refreshed_patches(&dest_patches, patches_dir)?; + result.fixed_interactively += 1; + } else { + result.skipped += 1; + } + } + 2 => { + // Skip patch + info!("Skipping patch: {}", patch_name); + remove_from_series(&dest_patches.join("series"), patch_name)?; + // Also update the original series file + remove_from_series(&patches_dir.join("series"), patch_name)?; + result.skipped += 1; + } + 3 => { + // Abort + warn!("Aborting patch testing"); + result.aborted = true; + break; + } + _ => unreachable!(), + } + } + + if !result.aborted { + // Copy any updated patches back + copy_refreshed_patches(&dest_patches, patches_dir)?; + } + + Ok(result) +} + +/// Spawn a shell in the source directory with QUILT_PATCHES set. +/// Returns true if the user exited successfully (exit 0). +fn drop_to_shell( + source_dir: &Path, + quilt_patches: &str, +) -> Result> { + let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()); + info!( + "Dropping to shell in {}. Run 'quilt refresh' after fixing, then 'exit 0' to continue.", + source_dir.display() + ); + + let status = Command::new(&shell) + .env("QUILT_PATCHES", quilt_patches) + .current_dir(source_dir) + .status()?; + + Ok(status.success()) +} + +/// Remove a patch name from a series file. +fn remove_from_series( + series_path: &Path, + patch_name: &str, +) -> Result<(), Box> { + let content = std::fs::read_to_string(series_path)?; + let new_content: String = content + .lines() + .filter(|line| line.trim() != patch_name) + .collect::>() + .join("\n"); + std::fs::write(series_path, format!("{}\n", new_content))?; + Ok(()) +} + +/// Copy refreshed patches from the source's patch dir back to the package's patch dir. +fn copy_refreshed_patches( + source_patches: &Path, + dest_patches: &Path, +) -> Result<(), Box> { + if !source_patches.exists() { + return Ok(()); + } + + for entry in std::fs::read_dir(source_patches)? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + let dest = dest_patches.join(entry.file_name()); + std::fs::copy(&path, &dest)?; + } + } + Ok(()) +} + +/// Recursively copy a directory. +fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), Box> { + std::fs::create_dir_all(dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dst_path = dst.join(entry.file_name()); + + if src_path.is_dir() { + copy_dir_recursive(&src_path, &dst_path)?; + } else { + std::fs::copy(&src_path, &dst_path)?; + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + #[test] + fn test_no_patches_dir() { + let source = tempdir().unwrap(); + let patches = tempdir().unwrap(); + let pkg = tempdir().unwrap(); + + let result = test_patches( + source.path(), + &patches.path().join("nonexistent"), + pkg.path(), + false, + ) + .unwrap(); + assert_eq!(result.applied_cleanly, 0); + assert_eq!(result.skipped, 0); + } + + #[test] + fn test_empty_series() { + let source = tempdir().unwrap(); + let patches = tempdir().unwrap(); + let pkg = tempdir().unwrap(); + + fs::write(patches.path().join("series"), "# empty\n").unwrap(); + + let result = test_patches(source.path(), patches.path(), pkg.path(), false).unwrap(); + assert_eq!(result.applied_cleanly, 0); + } + + #[test] + fn test_remove_from_series() { + let dir = tempdir().unwrap(); + let series = dir.path().join("series"); + fs::write(&series, "patch1.diff\npatch2.diff\npatch3.diff\n").unwrap(); + + remove_from_series(&series, "patch2.diff").unwrap(); + + let content = fs::read_to_string(&series).unwrap(); + assert!(!content.contains("patch2.diff")); + assert!(content.contains("patch1.diff")); + assert!(content.contains("patch3.diff")); + } + + #[test] + fn test_patch_result_summary() { + let result = PatchTestResult { + applied_cleanly: 3, + fixed_interactively: 1, + skipped: 0, + aborted: false, + }; + assert_eq!(result.summary(), "3 applied cleanly, 1 fixed interactively"); + + let empty = PatchTestResult { + applied_cleanly: 0, + fixed_interactively: 0, + skipped: 0, + aborted: false, + }; + assert_eq!(empty.summary(), "no patches to test"); + } +} diff --git a/crates/update/src/toml_rewrite.rs b/crates/update/src/toml_rewrite.rs new file mode 100644 index 00000000..10f8b4ea --- /dev/null +++ b/crates/update/src/toml_rewrite.rs @@ -0,0 +1,180 @@ +use std::path::Path; +use toml_edit::DocumentMut; + +/// Fields that can be updated in the TOML document. +pub struct TomlUpdates { + pub version: Option, + pub revision: Option, + pub source_url: Option, + pub source_hash: Option, + pub source_tag: Option, + pub runtime_vars: Option>, +} + +/// Rewrite specific fields in a pkg-builder.toml file, preserving formatting and comments. +/// +/// Returns the modified TOML content as a string. +pub fn rewrite_toml( + toml_path: &Path, + updates: &TomlUpdates, +) -> Result> { + let content = std::fs::read_to_string(toml_path)?; + let mut doc: DocumentMut = content.parse()?; + + if let Some(ref version) = updates.version { + doc["package"]["version"] = toml_edit::value(version.as_str()); + } + if let Some(ref revision) = updates.revision { + doc["package"]["revision"] = toml_edit::value(revision.as_str()); + } + if let Some(ref url) = updates.source_url { + doc["source"]["url"] = toml_edit::value(url.as_str()); + } + if let Some(ref hash) = updates.source_hash { + doc["source"]["hash"] = toml_edit::value(hash.as_str()); + } + if let Some(ref tag) = updates.source_tag { + doc["source"]["tag"] = toml_edit::value(tag.as_str()); + } + if let Some(ref vars) = updates.runtime_vars { + if let Some(runtime) = doc.get_mut("runtime") { + for (key, value) in vars { + runtime[key.as_str()] = toml_edit::value(value.as_str()); + } + } + } + + Ok(doc.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use tempfile::tempdir; + + #[test] + fn test_rewrite_version_and_hash() { + let dir = tempdir().unwrap(); + let toml_path = dir.path().join("pkg-builder.toml"); + fs::write( + &toml_path, + r#"# Package config +[package] +name = "geth" +version = "1.14.0" +revision = "1" +homepage = "https://geth.ethereum.org" +spec = "geth.sss" + +[source] +type = "tarball" +url = "https://github.com/ethereum/go-ethereum/archive/refs/tags/v1.14.0.tar.gz" +hash = "oldsha256" + +[build] +distribution = "bookworm" +arch = "amd64" +"#, + ) + .unwrap(); + + let updates = TomlUpdates { + version: Some("1.15.0".to_string()), + revision: Some("1".to_string()), + source_url: Some( + "https://github.com/ethereum/go-ethereum/archive/refs/tags/v1.15.0.tar.gz" + .to_string(), + ), + source_hash: Some("newsha256".to_string()), + source_tag: None, + runtime_vars: None, + }; + + let result = rewrite_toml(&toml_path, &updates).unwrap(); + + assert!(result.contains("# Package config"), "comments preserved"); + assert!(result.contains("version = \"1.15.0\"")); + assert!(result.contains("hash = \"newsha256\"")); + assert!(result.contains("v1.15.0.tar.gz")); + } + + #[test] + fn test_rewrite_git_tag() { + let dir = tempdir().unwrap(); + let toml_path = dir.path().join("pkg-builder.toml"); + fs::write( + &toml_path, + r#"[package] +name = "prysm" +version = "5.0.0" +revision = "1" +homepage = "https://example.com" +spec = "prysm.sss" + +[source] +type = "git" +url = "https://github.com/prysmaticlabs/prysm.git" +tag = "v5.0.0" +"#, + ) + .unwrap(); + + let updates = TomlUpdates { + version: Some("5.1.0".to_string()), + revision: Some("1".to_string()), + source_url: None, + source_hash: None, + source_tag: Some("v5.1.0".to_string()), + runtime_vars: None, + }; + + let result = rewrite_toml(&toml_path, &updates).unwrap(); + assert!(result.contains("version = \"5.1.0\"")); + assert!(result.contains("tag = \"v5.1.0\"")); + } + + #[test] + fn test_rewrite_runtime_vars() { + let dir = tempdir().unwrap(); + let toml_path = dir.path().join("pkg-builder.toml"); + fs::write( + &toml_path, + r#"[package] +name = "test" +version = "1.0.0" +revision = "1" +homepage = "https://example.com" +spec = "test.sss" + +[source] +type = "virtual" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "oldchecksum" +"#, + ) + .unwrap(); + + let updates = TomlUpdates { + version: None, + revision: None, + source_url: None, + source_hash: None, + source_tag: None, + runtime_vars: Some(vec![ + ( + "binary_url".to_string(), + "https://go.dev/dl/go1.23.0.linux-amd64.tar.gz".to_string(), + ), + ("binary_checksum".to_string(), "newchecksum".to_string()), + ]), + }; + + let result = rewrite_toml(&toml_path, &updates).unwrap(); + assert!(result.contains("go1.23.0")); + assert!(result.contains("newchecksum")); + } +} diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..c2e515e3 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,12 @@ +[book] +title = "pkg-builder" +authors = ["eth-pkg"] +language = "en" +src = "src" + +[build] +build-dir = "book" + +[output.html] +git-repository-url = "https://github.com/eth-pkg/pkg-builder" +edit-url-template = "https://github.com/eth-pkg/pkg-builder/edit/main/docs/src/{path}" diff --git a/docs/config.md b/docs/config.md deleted file mode 100644 index 4e88b23c..00000000 --- a/docs/config.md +++ /dev/null @@ -1,182 +0,0 @@ -# Configuration Reference - -pkg-builder uses TOML configuration files to define package metadata, build environments, and dependencies. - -## Basic Structure - -```toml -[package_fields] -spec_file = "path/to/spec.sss" -package_name = "package-name" -version_number = "1.0.0" -revision_number = "1" -homepage = "https://example.com" - -[package_type] -package_type = "default|git|virtual" -# Fields vary based on package_type - -[build_env] -codename = "bookworm" -arch = "amd64" -pkg_builder_version = "0.3.1" -debcrafter_version = "8189263" -# Additional build environment options -``` - -## Package Fields - -```toml -[package_fields] -spec_file = "hello-world.sss" # Path to spec file -package_name = "hello-world" # Package name -version_number = "1.0.0" # Version -revision_number = "1" # Revision number -homepage = "https://github.com/..." # Project homepage -``` - -## Package Types - -### Virtual Package - -```toml -[package_type] -package_type = "virtual" -``` - -### Default Package Type - -```toml -[package_type] -package_type = "default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "c93bdd829eca65af1e303d..." # Optional checksum - -[package_type.language_env] -language_env = "c|rust|go|javascript|typescript|java|dotnet|nim|python" -# Additional fields based on language_env -``` - -### Git Package Type - -```toml -[package_type] -package_type = "git" -git_tag = "v1.0.0" -git_url = "https://github.com/user/repo.git" - -[[package_type.submodules]] -commit = "abcdef123456" -path = "path/to/submodule" - -[package_type.language_env] -language_env = "c|rust|go|javascript|typescript|java|dotnet|nim|python" -# Additional fields based on language_env -``` - -## Language Environments - -### C (Default) - -```toml -[package_type.language_env] -language_env = "c" -``` - -### Python - -```toml -[package_type.language_env] -language_env = "python" -``` - -### Rust - -```toml -[package_type.language_env] -language_env = "rust" -rust_version = "1.67.0" -rust_binary_url = "https://static.rust-lang.org/..." -rust_binary_gpg_asc = "..." -``` - -### Go - -```toml -[package_type.language_env] -language_env = "go" -go_version = "1.19.0" -go_binary_url = "https://go.dev/dl/..." -go_binary_checksum = "..." -``` - -### JavaScript/TypeScript - -```toml -[package_type.language_env] -language_env = "javascript" # or "typescript" -node_version = "18.12.0" -node_binary_url = "https://nodejs.org/dist/..." -node_binary_checksum = "..." -yarn_version = "1.22.19" # Optional -``` - -### Java - -```toml -[package_type.language_env] -language_env = "java" -is_oracle = false -jdk_version = "17.0.5" -jdk_binary_url = "https://..." -jdk_binary_checksum = "..." - -# Optional Gradle configuration -[package_type.language_env.gradle] -gradle_version = "7.6" -gradle_binary_url = "https://..." -gradle_binary_checksum = "..." -``` - -### .NET - -```toml -[package_type.language_env] -language_env = "dotnet" -use_backup_version = false -deps = ["dependency1", "dependency2"] # Optional - -[[package_type.language_env.dotnet_packages]] -name = "package-name" -hash = "checksum" -url = "https://..." -``` - -### Nim - -```toml -[package_type.language_env] -language_env = "nim" -nim_version = "1.6.8" -nim_binary_url = "https://nim-lang.org/..." -nim_version_checksum = "..." -``` - -## Build Environment - -```toml -[build_env] -codename = "bookworm" # Target distribution -arch = "amd64" # Target architecture -pkg_builder_version = "0.3.1" # Tool version -debcrafter_version = "8189263" # Debcrafter version -sbuild_cache_dir = "/path/to/cache" # Optional cache directory, defaults to ~/.cache/sbuild -run_lintian = true # Enable lintian checks -run_piuparts = true # Enable piuparts tests -run_autopkgtest = true # Enable autopkgtest -lintian_version = "2.116.3" # Lintian version -piuparts_version = "1.1.7" # Piuparts version -autopkgtest_version = "5.28" # Autopkgtest version -sbuild_version = "0.85.6" # Sbuild version -workdir = "~/.pkg-builder/..." # Working directory -``` \ No newline at end of file diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index 49ad6801..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,72 +0,0 @@ -# Examples - -This document contains example usage for different package types. All examples assume you have already built and installed pkg-builder: - -```bash -cargo build && cargo install --path . -``` - -## Virtual Package - -```bash -pkg-builder env create examples/bookworm/virtual-package/pkg-builder.toml -pkg-builder package examples/bookworm/virtual-package/pkg-builder.toml -``` - -## Rust Package - -```bash -pkg-builder env create examples/bookworm/rust/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/rust/hello-world/pkg-builder.toml -``` - -## TypeScript Package - -```bash -pkg-builder env create examples/bookworm/typescript/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/typescript/hello-world/pkg-builder.toml -``` - -## JavaScript Package - -```bash -pkg-builder env create examples/bookworm/javascript/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/javascript/hello-world/pkg-builder.toml -``` - -## Nim Package - -```bash -pkg-builder env create examples/bookworm/nim/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/nim/hello-world/pkg-builder.toml -``` - -## .NET Package - -```bash -pkg-builder env create examples/bookworm/dotnet/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/dotnet/hello-world/pkg-builder.toml -``` - -## Java Package - -```bash -pkg-builder env create examples/bookworm/java/hello-world/pkg-builder.toml -pkg-builder package examples/bookworm/java/hello-world/pkg-builder.toml -``` - -## Testing Examples - -After building a package, you can run specific tests: - -### Piuparts Only - -```bash -pkg-builder piuparts examples/bookworm/virtual-package/pkg-builder.toml -``` - -### Autopkgtest Only - -```bash -pkg-builder autopkgtests examples/bookworm/virtual-package/pkg-builder.toml -``` \ No newline at end of file diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index 5032d24f..00000000 --- a/docs/install.md +++ /dev/null @@ -1,42 +0,0 @@ -# Installation Guide - -## Debian Prerequisites - -```bash -sudo apt install libssl-dev pkg-config quilt debhelper tar wget autopkgtest vmdb2 qemu-system-x86 git-lfs uidmap -sudo sbuild-adduser `whoami` -``` - -## Installing sbuild - -```bash -# Clone repository -git clone https://github.com/eth-pkg/sbuild.git -cd sbuild - -# Install dependencies -sudo apt-get install -y dh-python dh-sequence-python3 libyaml-tiny-perl python3-all genisoimage - -# Build the package -dpkg-buildpackage -us -uc - -# Install the newly built package -cd .. && sudo dpkg -i sbuild_0.85.6_all.deb libsbuild-perl_0.85.6_all.deb -``` - -## Setting up chroot - -```bash -# Create chroot directory if it doesn't exist -sudo mkdir /srv/chroot -sudo chown :sbuild /srv/chroot - -# For noble builds -sudo ln -s /usr/share/debootstrap/scripts/gutsy /usr/share/debootstrap/scripts/noble -``` - -## Ubuntu-specific Setup - -If building for Ubuntu on Bookworm, manually download the ubuntu-archive-keyring: -1. Get the keyring from [ubuntu-archive-keyring](https://salsa.debian.org/debian/ubuntu-keyring/-/raw/master/keyrings/ubuntu-archive-keyring.gpg?ref_type=heads) -2. Copy it into `/usr/share/keyrings` \ No newline at end of file diff --git a/docs/packaging.md b/docs/packaging.md deleted file mode 100644 index 2ef65aab..00000000 --- a/docs/packaging.md +++ /dev/null @@ -1,79 +0,0 @@ -# FAQ - -## Patch source - -Install quilt if not installed. - -Checkout source that you need to modify, you specify version number if needed - ```bash - # Assuming that your downloaded source already setup with in - pkg-builder package /pkg-builder.toml - cd .pkg-builder/packages//- - quilt push -a # apply existing patches - - quilt new your_patch_name.patch - quilt add - ... do your changes - ... vim - ... - - quilt refresh # this will save the modified patches under /debian/patches - ``` - -Copy the patched source to the folder, so you can build package from it. - ```bash - rm .pc/.quilt_patches - rm .pc/.quilt_series - rm .pc/.version - rm .pc/applied-patches - cp -R .pc //src - cp -R patches //src/debian - - ``` - -## Lintian errors - -### generating copyright files -Generally recommended to check the package for copyright and include that as such - -```text -Files: * -Copyright: 2022 ORIGINAL PACKAGE AUTHORS -License: GPL-3+ - -Files: debian/* -Copyright: 2022 MAINTAINER_NAME -License: GPL-3+ - -# Provide the short license for each referenced license -License: GPL-3+ - The full text of the GPL version 3 is distributed in - /usr/share/common-licenses/GPL-3 on Debian systems. -``` - -But in some cases some file could be in another license, which lintian going to fail (license included in file header), -so for this purposes it is good to checkout the source code or navigate to the pkg-builder dir -and run `debmake -c > debian/copyright` and check for such files by comparing the two files. - -### build essential warning - -In case encountaring the following error message, remove build-essential from your dependencies. -`build-essential` packages are already present in the minimal chroot environment provided by `sbuild`. - - -```text -E: source: build-depends-on-build-essential Build-Depends -N: -N: You depend on the build-essential package, which is only a metapackage -N: depending on build tools that have to be installed in all build -N: environments. -N: -N: Please refer to Relationships between source and binary packages - -N: Build-Depends, Build-Depends-Indep, Build-Depends-Arch, Build-Conflicts, -N: Build-Conflicts-Indep, Build-Conflicts-Arch (Section 7.7) in the Debian -N: Policy Manual for details. -N: -N: Visibility: error -N: Show-Always: no -N: Check: fields/package-relations -``` \ No newline at end of file diff --git a/docs/src/README.md b/docs/src/README.md new file mode 100644 index 00000000..f2490e01 --- /dev/null +++ b/docs/src/README.md @@ -0,0 +1,55 @@ +# Introduction + +pkg-builder is a command-line tool for creating reproducible Debian packages from TOML configuration files. It integrates with [debcrafter](https://github.com/Kixunil/debcrafter) to simplify the Debian packaging workflow, handling the entire pipeline from environment setup and source acquisition to package building and verification. + +## Why pkg-builder? + +Debian packaging is powerful but notoriously difficult to get right. A typical packaging workflow involves writing and maintaining `debian/rules`, `debian/control`, `debian/changelog`, source format files, and more — each with its own syntax and subtle interactions. Reproducibility is hard: builds depend on the exact state of upstream archives, toolchain versions, and build environments. + +pkg-builder solves this by letting you define your entire package in a single `pkg-builder.toml` file. Instead of hand-writing debian control files, you declare what you want — source location, build distribution, runtime toolchain — and pkg-builder handles everything else. It pins snapshot archives, normalizes timestamps, and verifies output hashes so that the same config always produces the same `.deb`. + +## Features + +- **TOML-driven configuration** — define your package in a single `pkg-builder.toml` file +- **Reproducible builds** — timestamp normalization, snapshot pinning, and hash verification +- **Multiple source types** — tarballs, git repositories (with submodule pinning), and virtual/meta-packages +- **Multi-language support** — C, Rust, Go, Node.js (JavaScript/TypeScript), Java (with Gradle), .NET, Nim +- **Multi-distribution** — Debian (bookworm, trixie) and Ubuntu (noble) +- **Package verification** — SHA-256 hash checking for built `.dsc` and `.deb` files +- **Interactive init wizard** — scaffold new packages with auto-detection of runtime toolchains + +## Quick start + +```bash +# Install prerequisites and build pkg-builder +sudo apt install libssl-dev pkg-config quilt debhelper tar git-lfs uidmap +cargo install --path crates/cli + +# Create the build environment +pkg-builder --config pkg-builder.toml env create + +# Build the package +pkg-builder --config pkg-builder.toml build +``` + +Or scaffold a new package interactively: + +```bash +pkg-builder init --output ./my-package +``` + +See [Installation](getting-started/installation.md) for full setup instructions and [Your First Package](getting-started/first-package.md) for a step-by-step tutorial. + +## Architecture + +pkg-builder is a Rust workspace with five crates: + +| Crate | Purpose | +|-------|---------| +| `crates/cli` | Command-line interface and argument parsing | +| `crates/config` | TOML parsing, validation, and configuration types | +| `crates/init` | Interactive project initialization wizard | +| `crates/executor` | Build pipeline executor (acquire, extract, debcrafter, sbuild) | +| `crates/update` | Package version update tool | + +The build pipeline directly executes four steps: acquire source, extract tarball, generate debian packaging via debcrafter, and invoke sbuild. diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 00000000..cfb39dd7 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,29 @@ +# Summary + +[Introduction](README.md) + +# Getting Started + +- [Installation](getting-started/installation.md) +- [Your First Package](getting-started/first-package.md) +- [Concepts](getting-started/concepts.md) + +# Guides + +- [Project Initialization](guides/init.md) +- [Source Types](guides/source-types.md) +- [Runtime Recipes](guides/runtime-recipes.md) +- [Snapshot Pinning](guides/snapshot-pinning.md) +- [Patching](guides/patching.md) +- [Caching](guides/caching.md) +- [Verification](guides/verification.md) + +# Reference + +- [Configuration](reference/config.md) +- [CLI](reference/cli.md) +- [Recipes](reference/recipes.md) + +--- + +- [Troubleshooting](troubleshooting.md) diff --git a/docs/src/getting-started/concepts.md b/docs/src/getting-started/concepts.md new file mode 100644 index 00000000..fbe24716 --- /dev/null +++ b/docs/src/getting-started/concepts.md @@ -0,0 +1,77 @@ +# Concepts + +This page explains the key components of the pkg-builder ecosystem and how they fit together. + +## The packaging pipeline + +Building a Debian package with pkg-builder involves three main tools: + +``` +pkg-builder.toml + │ + â–¼ + pkg-builder (executor) + │ + ├── Step 1: Acquire source (download/clone/copy) + ├── Step 2: Extract source tarball + ├── Step 3: debcrafter ──► debian/ files (control, rules, changelog, ...) + └── Step 4: sbuild ──────► .deb + .dsc (built inside a chroot) +``` + +### pkg-builder + +The orchestrator. It reads your `pkg-builder.toml` configuration and directly executes a 4-step build pipeline: + +1. **Acquires the source** (downloads tarballs via HTTP, clones git repos, or creates virtual packages) +2. **Extracts the source** tarball into the working directory +3. **Invokes debcrafter** (as a library) to generate `debian/` packaging files from `.sss` spec files +4. **Runs sbuild** to build the package inside an isolated chroot environment + +### debcrafter + +A separate tool ([debcrafter](https://github.com/Kixunil/debcrafter)) that generates Debian packaging files from `.sss` (source spec) and `.sps` (package spec) files. These spec files are a higher-level, more concise way to describe Debian package metadata and relationships than hand-writing `debian/control`, `debian/rules`, etc. + +Key files: +- **`.sss` (source service spec)** — describes the source package: build dependencies, binary packages it produces, and their relationships +- **`.sps` (package spec)** — describes individual binary packages and their contents +- **`.changelog`** — standard Debian changelog, used by debcrafter during generation + +### sbuild + +A Debian tool that builds packages inside an isolated chroot environment. This ensures builds are clean and reproducible — only explicitly declared dependencies are available. pkg-builder uses a [patched fork](https://github.com/eth-pkg/sbuild) of sbuild. + +The chroot is created once per distribution with `pkg-builder env create` (or `pkg-builder --config env create`) and reused for all subsequent builds. + +## Runtime recipes + +Not all languages can build with just the packages available in the Debian archive. Rust, Go, Node.js, Java, Nim, and .NET all need external toolchains installed into the chroot before the build runs. + +pkg-builder handles this through **runtime recipes** — template files in `runtimes/` that describe how to download and install a specific toolchain. Each recipe uses template variables (like `{{binary_url}}`) that get filled in from the `[runtime]` section of your `pkg-builder.toml`. + +For example, a Go package needs: + +```toml +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" +``` + +C packages don't need a `[runtime]` section — the C toolchain is already in the base chroot. + +See [Runtime Recipes](../guides/runtime-recipes.md) for the full list of recipes and their required fields. + +## Reproducibility + +pkg-builder achieves reproducible builds through several mechanisms: + +- **Snapshot pinning** — locks Debian/Ubuntu package archives to a specific date so dependency resolution is deterministic +- **Tool version pinning** — the `[tools]` section records exact versions of pkg-builder, debcrafter, sbuild, and test tools +- **Source hashing** — the `[source].hash` field ensures the source code hasn't changed +- **Output verification** — the `[verify]` section stores expected SHA-1 hashes of built `.dsc` and `.deb` files + +Together, these mean that given the same `pkg-builder.toml`, you should always get the same output. + +## Working directory + +Each build uses a working directory (`[build].workdir`) where pkg-builder stages the source tree, runs the build, and places output files. By default this is `~/.pkg-builder/packages//`. The `pkg-builder clean` command removes build artifacts from this directory. diff --git a/docs/src/getting-started/first-package.md b/docs/src/getting-started/first-package.md new file mode 100644 index 00000000..19b74402 --- /dev/null +++ b/docs/src/getting-started/first-package.md @@ -0,0 +1,125 @@ +# Your First Package + +This tutorial walks through building a simple C hello-world package for Debian bookworm using pkg-builder. By the end, you'll have a working `.deb` file. + +## Prerequisites + +Make sure you've completed the [Installation](installation.md) steps. You should have `pkg-builder` on your PATH and sbuild set up. + +## Option A: Use `pkg-builder init` + +The fastest way to create a new package is with the interactive wizard: + +```bash +pkg-builder init --output ./my-package +``` + +This prompts for package name, version, source type, distribution, runtime, and more. It generates three files: + +- `pkg-builder.toml` — package configuration +- `.sss` — debcrafter source spec +- `.sps` — debcrafter package spec + +For tarball sources, `init` can automatically download the tarball and compute its SHA-256 hash. For Go, Node.js, Rust, and Nim runtimes, it can auto-resolve the latest toolchain version and fetch checksums. + +You can also run it fully non-interactively by passing all values as flags — see the [CLI Reference](../reference/cli.md#pkg-builder-init) for details. + +Once the files are generated, skip ahead to [Step 1: Create the build environment](#step-1-create-the-build-environment). + +## Option B: Use an existing example + +## The example project + +The repository includes a complete C example at `examples/bookworm/c/hello-world/`. Let's look at what's inside: + +``` +examples/bookworm/c/hello-world/ + pkg-builder.toml # Package configuration + hello-world-c.sss # debcrafter spec file + hello-world-c.sps # debcrafter source spec + hello-world-c.changelog # Debian changelog + hello-world-1.0.0.tar.gz # Source tarball + src/debian/ # Debian packaging files (rules, copyright, tests) +``` + +## The configuration file + +Here's the `pkg-builder.toml` that defines the package: + +```toml +[package] +name = "hello-world-c" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-c.sss" + +[source] +type = "tarball" +url = "hello-world-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e..." + +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "0843091f9e3cff991450c9687935e67644f6b032" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "acd656c4554f41eb2a0ad570ef99ff19db51273d" }, +] +``` + +Let's break this down: + +- **`[package]`** — Package metadata: name, version, revision, and the debcrafter `.sss` spec file. +- **`[source]`** — Where to get the source code. This example uses a local tarball, but it could be a URL or a git repository. +- **`[build]`** — Target distribution, architecture, and working directory for build artifacts. +- **`[tools]`** — Pinned versions of all external tools for reproducibility. +- **`[verify]`** — Expected SHA-1 hashes of the output `.dsc` and `.deb` files. + +## Step 1: Create the build environment + +The build environment is an sbuild chroot — an isolated Debian installation where the package gets built: + +```bash +pkg-builder --config examples/bookworm/c/hello-world/pkg-builder.toml env create +``` + +This creates a bookworm amd64 chroot under `/srv/chroot/`. You only need to do this once per distribution. + +## Step 2: Build the package + +```bash +pkg-builder --config examples/bookworm/c/hello-world/pkg-builder.toml build +``` + +pkg-builder will: + +1. Acquire the source tarball and copy it to the working directory +2. Extract the source tarball +3. Run debcrafter to generate Debian packaging files from the `.sss` spec +4. Invoke sbuild to build the package inside the chroot + +The output `.deb` and `.dsc` files are placed in the workdir (`~/.pkg-builder/packages/bookworm/`). + +## Step 3: Verify the build + +```bash +pkg-builder --config examples/bookworm/c/hello-world/pkg-builder.toml verify +``` + +This compares the SHA-1 hashes of the built files against the expected values in `[verify].package_hash`. If they match, the build is reproducible. + +## Next steps + +- Read [Concepts](concepts.md) to understand how pkg-builder, debcrafter, and sbuild fit together +- See [Source Types](../guides/source-types.md) to learn about git and virtual package sources +- See [Runtime Recipes](../guides/runtime-recipes.md) to build packages for other languages +- Browse `examples/` for working configurations across all supported languages and distributions diff --git a/docs/src/getting-started/installation.md b/docs/src/getting-started/installation.md new file mode 100644 index 00000000..eba7ddfa --- /dev/null +++ b/docs/src/getting-started/installation.md @@ -0,0 +1,62 @@ +# Installation + +## Prerequisites + +Install the required Debian packages: + +```bash +sudo apt install libssl-dev pkg-config quilt debhelper tar git-lfs uidmap +``` + +Add your user to the sbuild group: + +```bash +sudo sbuild-adduser $(whoami) +``` + +## Installing sbuild + +pkg-builder requires a patched version of sbuild from the eth-pkg fork: + +```bash +# Clone the fork +git clone https://github.com/eth-pkg/sbuild.git +cd sbuild + +# Install build dependencies +sudo apt-get install -y dh-python dh-sequence-python3 libyaml-tiny-perl python3-all genisoimage + +# Build and install +dpkg-buildpackage -us -uc +cd .. && sudo dpkg -i sbuild_0.85.6_all.deb libsbuild-perl_0.85.6_all.deb +``` + +## Setting up chroot + +Create the chroot directory used by sbuild: + +```bash +sudo mkdir -p /srv/chroot +sudo chown :sbuild /srv/chroot +``` + +For Ubuntu noble builds, add the debootstrap symlink: + +```bash +sudo ln -s /usr/share/debootstrap/scripts/gutsy /usr/share/debootstrap/scripts/noble +``` + +## Building pkg-builder + +```bash +git clone https://github.com/eth-pkg/pkg-builder.git +cd pkg-builder +cargo install --path crates/cli +``` + +## Ubuntu-specific setup + +If building for Ubuntu on a Debian host, manually install the Ubuntu archive keyring: + +1. Download [ubuntu-archive-keyring.gpg](https://salsa.debian.org/debian/ubuntu-keyring/-/raw/master/keyrings/ubuntu-archive-keyring.gpg?ref_type=heads) +2. Copy it to `/usr/share/keyrings/` diff --git a/docs/src/guides/caching.md b/docs/src/guides/caching.md new file mode 100644 index 00000000..8200f8a1 --- /dev/null +++ b/docs/src/guides/caching.md @@ -0,0 +1,71 @@ +# Caching packages for faster builds + +When building or rebuilding many packages, each sbuild invocation fetches build dependencies from Debian/Ubuntu mirrors. A local caching proxy avoids redundant downloads and significantly speeds up batch builds. + +## Setting up apt-cacher-ng + +```bash +sudo apt install apt-cacher-ng +sudo systemctl enable --now apt-cacher-ng +``` + +This starts a caching proxy on port 3142. The admin UI is available at `http://localhost:3142/acng-report.html`. + +## Transparent proxy (recommended) + +To cache packages without modifying any build configs or sbuild chroots, redirect HTTP traffic at the kernel level: + +```bash +sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner apt-cacher-ng -j REDIRECT --to-port 3142 +``` + +This keeps builds fully reproducible — sbuild still fetches from the same mirrors with the same pinned snapshots, the cache just serves already-downloaded packages locally. + +To persist the rule across reboots: + +```bash +sudo apt install iptables-persistent +sudo netfilter-persistent save +``` + +## Verifying the cache is working + +```bash +# Check service status +sudo systemctl status apt-cacher-ng + +# Watch requests during a build +tail -f /var/log/apt-cacher-ng/apt-cacher.log + +# Inspect cached files +ls /var/cache/apt-cacher-ng/ +``` + +The web UI at `http://localhost:3142/acng-report.html` shows hit/miss ratios and transfer statistics. + +### Reading the log — cache hits vs misses + +Log format: `timestamp|direction|size|client_ip|path` + +- **`I`** = delivered to client (inbound to requester) +- **`O`** = fetched from upstream mirror (outbound to internet) + +**Cache miss** — both `I` and `O` lines appear for the same file (fetched from mirror, then forwarded): + +``` +1773338962|I|15002|192.168.1.102|uburep/pool/main/b/blinker/python3-blinker_1.7.0-1_all.deb +1773338962|O|14606|192.168.1.102|uburep/pool/main/b/blinker/python3-blinker_1.7.0-1_all.deb +``` + +**Cache hit** — only an `I` line, no matching `O` (served directly from local cache). + +On the first build everything will be misses. Subsequent builds of the same or similar packages should show only `I` lines. + +## Tracking exact package versions + +sbuild generates `.buildinfo` files that list every build dependency with its exact version. These files are in the build output directory alongside the `.deb` and `.changes` files. Combined with the pinned snapshot archives in `pkg-builder.toml`, this provides a complete record of what went into each build. + +## Limitations + +- Only caches HTTP, not HTTPS. Mirrors in sbuild chroots should use `http://` URLs (e.g. `http://deb.debian.org`, `http://archive.ubuntu.com`). The default snapshot URLs used by pkg-builder already use HTTP. +- Index files (`Release`, `Packages.gz`) are re-validated on each request to stay current, so metadata is always fresh while `.deb` files are served from cache. diff --git a/docs/src/guides/init.md b/docs/src/guides/init.md new file mode 100644 index 00000000..af729eb3 --- /dev/null +++ b/docs/src/guides/init.md @@ -0,0 +1,101 @@ +# Project Initialization + +The `pkg-builder init` command scaffolds a new package project by generating a `pkg-builder.toml` configuration file and the debcrafter spec files (`.sss` and `.sps`). + +## Interactive mode + +Run `init` without flags for an interactive wizard that prompts for each value: + +```bash +pkg-builder init --output ./my-package +``` + +The wizard walks through: + +1. **Package metadata** — name, version, revision, homepage, maintainer, section, summary +2. **Source type** — tarball, git, or virtual +3. **Source details** — URL, tag (for git), hash (for tarballs) +4. **Build target** — distribution and architecture +5. **Runtime** — language toolchain recipe and its required fields + +## Auto-resolution + +For some runtimes, `init` can automatically fetch the latest version and its verification data: + +| Runtime | Auto-resolved fields | +|---------|---------------------| +| Go | `binary_url`, `binary_checksum` (latest stable from go.dev) | +| Node.js | `binary_url`, `binary_checksum` (latest LTS from nodejs.org) | +| Rust | `binary_url`, `binary_gpg_asc` (fetches GPG signature for a given version) | +| Nim | `binary_url`, `binary_checksum` (downloads and hashes the archive) | + +When auto-resolution succeeds, the wizard shows the resolved values and lets you confirm or override with a different version. + +For tarball sources with remote URLs, `init` downloads the tarball to the output directory and computes its SHA-256 hash automatically. + +## Generated files + +`init` creates three files in the output directory: + +### `pkg-builder.toml` + +The main configuration file with all sections pre-populated: + +- `[package]` — name, version, revision, homepage, spec file path +- `[source]` — type-specific source configuration +- `[build]` — distribution, architecture, working directory +- `[runtime]` — recipe and toolchain fields (if applicable) +- `[tools]` — pinned to current tool versions + +### `.sss` (source service spec) + +A debcrafter source spec with: + +- Package name and maintainer +- Debian section +- Empty build dependencies and variants (to be filled in) +- Reference to the binary package spec + +### `.sps` (package spec) + +A debcrafter binary package spec with: + +- Package name and architecture +- Summary and long description (from the summary you provided) +- Empty dependency, conflict, and file lists (to be filled in) + +## Non-interactive mode + +Pass all values as CLI flags to skip all prompts: + +```bash +pkg-builder init \ + --name my-package \ + --version 1.0.0 \ + --revision 1 \ + --homepage https://example.com \ + --maintainer-name "Jane Doe" \ + --maintainer-email jane@example.com \ + --section net \ + --summary "My package description" \ + --source-type tarball \ + --url https://example.com/my-package-1.0.0.tar.gz \ + --distribution bookworm \ + --arch amd64 \ + --runtime none \ + --output ./my-package +``` + +## Runtimes that require manual setup + +The `.NET` runtimes (`dotnet-noble`, `dotnet-debian`, `dotnet-backup`) require manually specifying package lists in the `[runtime]` section after `init` generates the files. The wizard will inform you when this is the case. + +## Next steps + +After running `init`: + +1. Review and customize the generated `pkg-builder.toml` +2. Fill in build dependencies in the `.sss` file +3. Add installed files, dependencies, and descriptions in the `.sps` file +4. Create the build environment: `pkg-builder --config ./my-package/pkg-builder.toml env create` +5. Build the package: `pkg-builder --config ./my-package/pkg-builder.toml build` diff --git a/docs/src/guides/patching.md b/docs/src/guides/patching.md new file mode 100644 index 00000000..f71a8d8f --- /dev/null +++ b/docs/src/guides/patching.md @@ -0,0 +1,49 @@ +# Patching + +Sometimes the upstream source needs modifications to build correctly as a Debian package. pkg-builder uses [quilt](https://wiki.debian.org/UsingQuilt) for managing patches, the standard Debian patching tool. + +## Creating a patch + +First, build the package to get the unpacked source tree: + +```bash +pkg-builder --config path/to/pkg-builder.toml build +``` + +Then navigate to the unpacked source in the working directory: + +```bash +cd ~/.pkg-builder/packages//- +``` + +Apply any existing patches and create a new one: + +```bash +quilt push -a # Apply existing patches +quilt new your_patch.patch # Start a new patch +quilt add # Track a file for changes +``` + +Make your changes to the tracked file(s), then save: + +```bash +quilt refresh # Save the patch to debian/patches/ +``` + +## Copying patches back + +After creating the patch, copy the quilt state back to your packaging source directory: + +```bash +# Clean up quilt metadata +rm .pc/.quilt_patches +rm .pc/.quilt_series +rm .pc/.version +rm .pc/applied-patches + +# Copy back to your package source +cp -R .pc /src +cp -R patches /src/debian +``` + +Rebuild the package to verify the patch applies cleanly. diff --git a/docs/src/guides/runtime-recipes.md b/docs/src/guides/runtime-recipes.md new file mode 100644 index 00000000..d2398de4 --- /dev/null +++ b/docs/src/guides/runtime-recipes.md @@ -0,0 +1,165 @@ +# Runtime Recipes + +Languages that need external toolchains (compilers, runtimes, package managers) use the `[runtime]` section to install them into the sbuild chroot before the build runs. + +## How it works + +When you set `[runtime].recipe`, pkg-builder looks up the corresponding recipe template in `runtimes/.recipe`. The recipe contains commands to download, verify, and install the toolchain. Template variables like `{{binary_url}}` are filled in from the other fields in `[runtime]`. + +## Available recipes + +### C + +No `[runtime]` section needed — the C toolchain (gcc, make, etc.) is already available in the base sbuild chroot. + +### Rust + +```toml +[runtime] +recipe = "rust" +binary_url = "https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" +binary_gpg_asc = """-----BEGIN PGP SIGNATURE----- +... +-----END PGP SIGNATURE----- +""" +``` + +Downloads the official Rust release, verifies the GPG signature against the Rust project's key, and installs rustc, cargo, and the standard library. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the Rust release tarball | +| `binary_gpg_asc` | Detached GPG signature for the tarball | + +### Go + +```toml +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" +``` + +Downloads the official Go release, verifies the SHA-256 checksum, and installs to `/usr/local/go`. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the Go release tarball | +| `binary_checksum` | SHA-256 checksum of the tarball | + +### Node.js (JavaScript/TypeScript) + +```toml +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +``` + +Downloads Node.js, verifies the checksum, and installs node, npm, npx, and corepack. Use the same recipe for both JavaScript and TypeScript projects. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the Node.js release tarball | +| `binary_checksum` | SHA-256 checksum of the tarball | + +### Java + +```toml +[runtime] +recipe = "java" +binary_url = "https://download.oracle.com/java/21/archive/jdk-21.0.2_linux-x64_bin.tar.gz" +binary_checksum = "..." +jdk_version = "21.0.2" +``` + +Downloads a JDK, verifies the checksum, and installs java and javac. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the JDK tarball | +| `binary_checksum` | SHA-256 checksum of the tarball | +| `jdk_version` | JDK version (used for install paths) | + +### Java with Gradle + +```toml +[runtime] +recipe = "java-gradle" +binary_url = "https://download.oracle.com/java/21/archive/jdk-21.0.2_linux-x64_bin.tar.gz" +binary_checksum = "..." +jdk_version = "21.0.2" +gradle_version = "8.7" +gradle_binary_url = "https://services.gradle.org/distributions/gradle-8.7-bin.zip" +gradle_binary_checksum = "..." +``` + +Same as the Java recipe, but also installs Gradle. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the JDK tarball | +| `binary_checksum` | SHA-256 checksum of the JDK tarball | +| `jdk_version` | JDK version (used for install paths) | +| `gradle_version` | Gradle version (used for install paths) | +| `gradle_binary_url` | URL to the Gradle distribution zip | +| `gradle_binary_checksum` | SHA-256 checksum of the Gradle zip | + +### Nim + +```toml +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "..." +nim_version = "2.0.2" +``` + +Downloads a Nim release, verifies the checksum, and installs the nim compiler. + +| Field | Description | +|-------|-------------| +| `binary_url` | URL to the Nim release tarball | +| `binary_checksum` | SHA-256 checksum of the tarball | +| `nim_version` | Nim version (used for install paths) | + +### .NET (Ubuntu Noble) + +```toml +[runtime] +recipe = "dotnet-noble" +packages = [ + { name = "dotnet-sdk-8.0", apt_name = "dotnet-sdk-8.0", url = "...", hash = "..." }, +] +``` + +Installs .NET from the Ubuntu PPA backports repository. Each package is downloaded, installed, and verified by SHA-1 hash. + +### .NET (Debian) + +```toml +[runtime] +recipe = "dotnet-debian" +packages = [ + { name = "dotnet-sdk-8.0", apt_name = "dotnet-sdk-8.0", url = "...", hash = "..." }, +] +``` + +Installs .NET from the Microsoft Debian repository. + +### .NET (backup/direct) + +```toml +[runtime] +recipe = "dotnet-backup" +extra_deps = [ + { name = "libicu-dev" }, +] +packages = [ + { name = "dotnet-sdk-8.0", url = "...", hash = "..." }, +] +``` + +Installs .NET by directly downloading and installing `.deb` files. Used as a fallback when repository-based installation doesn't work. + +See also the [Recipes Reference](../reference/recipes.md) for a quick-reference table of all recipes and their fields. diff --git a/docs/src/guides/snapshot-pinning.md b/docs/src/guides/snapshot-pinning.md new file mode 100644 index 00000000..2d7aea96 --- /dev/null +++ b/docs/src/guides/snapshot-pinning.md @@ -0,0 +1,43 @@ +# Snapshot Pinning + +Snapshot pinning locks your build against a specific point-in-time copy of the Debian package archive. This ensures that dependency resolution produces the same result every time, regardless of when you run the build. + +## How it works + +Debian maintains daily snapshots of its archive at [snapshot.debian.org](https://snapshot.debian.org/). When you specify a snapshot date, pkg-builder configures the sbuild chroot to use that snapshot instead of the live mirror. This means `apt` inside the chroot sees exactly the same packages that were available on that date. + +## Configuration + +Add snapshot fields to the `[build]` section: + +```toml +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" +snapshot_date = "20250101" +snapshot_security_date = "20250115T000000Z" +``` + +| Field | Format | Description | +|-------|--------|-------------| +| `snapshot_date` | `YYYYMMDD` | Date of the main archive snapshot | +| `snapshot_security_date` | `YYYYMMDDTHHMMSSZ` | Date of the security archive snapshot | + +Both fields are optional. If omitted, the build uses the live mirrors. + +## When to use snapshot pinning + +- **Reproducible builds** — pin to a date to get deterministic dependency resolution +- **CI stability** — prevent builds from breaking when new package versions are uploaded +- **Auditing** — record exactly which dependencies were used for a specific build + +## Limitations + +- Snapshot pinning is only available for **Debian** distributions (bookworm, trixie). Ubuntu does not have an equivalent snapshot service. +- Snapshots may eventually be garbage-collected by snapshot.debian.org, though in practice they are retained for years. +- The security snapshot date is separate from the main archive date because security updates are published on a different cadence. + +## Choosing dates + +A good strategy is to set the snapshot date to the day you finalize the package, then record it in `pkg-builder.toml` for future builds. If you need a security fix that was published after your snapshot date, update `snapshot_security_date` to a date after the fix was released. diff --git a/docs/src/guides/source-types.md b/docs/src/guides/source-types.md new file mode 100644 index 00000000..e663111c --- /dev/null +++ b/docs/src/guides/source-types.md @@ -0,0 +1,76 @@ +# Source Types + +The `[source]` section of `pkg-builder.toml` tells pkg-builder where to get the source code for your package. There are three source types: tarball, git, and virtual. + +## Tarball + +The most common source type. Points to a `.tar.gz` or `.tar.xz` archive, either a local file or a remote URL. + +**Local file:** + +```toml +[source] +type = "tarball" +url = "hello-world-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3..." +``` + +**Remote URL:** + +```toml +[source] +type = "tarball" +url = "https://example.com/project-1.0.0.tar.gz" +hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc..." +``` + +The `hash` field is optional but recommended. It contains a SHA-512 hash of the tarball for integrity verification. + +## Git + +Clone a git repository at a specific tag. Useful when the upstream project doesn't publish release tarballs, or when you need to include git submodules. + +```toml +[source] +type = "git" +url = "https://github.com/org/repo.git" +tag = "v1.0.0" +``` + +### Submodule pinning + +For reproducible builds with git submodules, pin each submodule to a specific commit: + +```toml +[source] +type = "git" +url = "https://github.com/org/repo.git" +tag = "v1.0.0" +submodules = [ + { commit = "72523ee3f865...", path = "vendor/lib1" }, + { commit = "ab3ff9fad45f...", path = "vendor/lib2" }, +] +``` + +Each entry specifies the expected commit hash and the submodule path. pkg-builder verifies these during source preparation. + +## Virtual + +For meta-packages that don't contain any source code — they only declare dependencies on other packages. + +```toml +[source] +type = "virtual" +``` + +No other fields are needed. The resulting package will have no files of its own, just dependency relationships defined in the debcrafter spec. + +## Choosing a source type + +| Scenario | Source type | +|----------|------------| +| Upstream publishes release tarballs | `tarball` with remote URL | +| You maintain the source alongside the packaging | `tarball` with local file | +| Upstream uses git tags but no tarballs | `git` | +| Project has git submodules | `git` with submodule pinning | +| Dependency-only meta-package | `virtual` | diff --git a/docs/src/guides/verification.md b/docs/src/guides/verification.md new file mode 100644 index 00000000..1b3c0313 --- /dev/null +++ b/docs/src/guides/verification.md @@ -0,0 +1,52 @@ +# Verification + +pkg-builder supports hash verification to confirm that a build is reproducible — that the same configuration produces the same output files. + +## How it works + +The `[verify]` section in `pkg-builder.toml` stores expected SHA-1 hashes for the built `.dsc` (source package descriptor) and `.deb` (binary package) files: + +```toml +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "0843091f9e3cff991450c9687935e67644f6b032" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "acd656c4554f41eb2a0ad570ef99ff19db51273d" }, +] +``` + +Each entry specifies the expected filename and its SHA-1 hash. + +## Running verification + +```bash +pkg-builder verify +``` + +This computes the SHA-1 hash of each file listed in `package_hash` (looking in the workdir) and compares it against the expected value. If any hash doesn't match, the command reports which files differ. + +## Setting up verification for a new package + +1. Build the package without a `[verify]` section (or with empty hashes) +2. Run `pkg-builder verify` — it will report the actual hashes +3. Copy the actual hashes into your `pkg-builder.toml` +4. Rebuild and verify again to confirm reproducibility + +## File naming convention + +The expected filenames follow Debian conventions: + +- **`.dsc`**: `_-.dsc` +- **`.deb`**: `_-_.deb` + +For example, package `hello-world-c` version `1.0.0` revision `1` on amd64: +- `hello-world-c_1.0.0-1.dsc` +- `hello-world-c_1.0.0-1_amd64.deb` + +## Prerequisites for reproducibility + +For hashes to match across builds, you typically need: + +- **Snapshot pinning** — so dependencies are identical (see [Snapshot Pinning](snapshot-pinning.md)) +- **Pinned tool versions** — same sbuild, debcrafter, and pkg-builder versions +- **Same architecture** — cross-architecture builds produce different binaries +- **Normalized timestamps** — pkg-builder handles this automatically via `SOURCE_DATE_EPOCH` diff --git a/docs/src/reference/cli.md b/docs/src/reference/cli.md new file mode 100644 index 00000000..8c75acbb --- /dev/null +++ b/docs/src/reference/cli.md @@ -0,0 +1,105 @@ +# CLI Reference + +## Global options + +All commands accept global options before the subcommand: + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--config ` | string | `.` (current directory) | Path to `pkg-builder.toml` | +| `--resume` | flag | `false` | Skip build steps whose output artifacts already exist | +| `-V`, `--version` | flag | | Print version and exit | +| `-h`, `--help` | flag | | Print help | + +## `pkg-builder init` + +Interactive project setup wizard. When run without flags, prompts for each value interactively. Any flag provided skips the corresponding prompt. + +```bash +pkg-builder init [OPTIONS] +``` + +**Options:** + +| Flag | Type | Description | +|------|------|-------------| +| `--name` | string | Package name | +| `--version` | string | Package version | +| `--revision` | string | Package revision | +| `--homepage` | string | Homepage URL | +| `--maintainer-name` | string | Maintainer name | +| `--maintainer-email` | string | Maintainer email | +| `--section` | string | Debian section (e.g., `net`, `utils`, `devel`, `admin`, `libs`, `web`) | +| `--summary` | string | Short package description | +| `--source-type` | string | Source type: `tarball`, `git`, or `virtual` | +| `--url` | string | Source URL (tarball URL or git repo URL) | +| `--tag` | string | Git tag (for git source type) | +| `--distribution` | string | Target distribution: `bookworm`, `trixie`, or `noble` | +| `--arch` | string | Target architecture | +| `--runtime` | string | Runtime recipe: `go`, `rust`, `node`, `java`, `java-gradle`, `nim`, `c`, or `none` | +| `--output` | string | Output directory (default: current directory) | +| `--upstream-hash` | string | Expected upstream hash for tarball verification | + +**Example (fully non-interactive):** + +```bash +pkg-builder init \ + --name my-package \ + --version 1.0.0 \ + --revision 1 \ + --homepage https://example.com \ + --maintainer-name "Jane Doe" \ + --maintainer-email jane@example.com \ + --section net \ + --summary "My package description" \ + --source-type tarball \ + --url https://example.com/my-package-1.0.0.tar.gz \ + --distribution bookworm \ + --arch amd64 \ + --runtime none \ + --output ./my-package +``` + +## `pkg-builder build` + +Build a Debian package. Runs a 4-step pipeline: acquire source, extract, generate debian packaging (via debcrafter), and invoke sbuild. + +```bash +pkg-builder build +``` + +By default, `build` cleans the output directory and runs from scratch. Use `--resume` to skip steps whose output artifacts already exist (e.g., skip downloading if the tarball is present). + +## `pkg-builder env create` + +Create the sbuild chroot environment for the target distribution. + +```bash +pkg-builder env create +``` + +This must be run once per distribution before the first build. The chroot is reused for subsequent builds. + +## `pkg-builder env clean` + +Remove the sbuild chroot environment (chroot tarball only). + +```bash +pkg-builder env clean +``` + +## `pkg-builder verify` + +Verify package file hashes against the expected values in `[verify].package_hash`. + +```bash +pkg-builder verify +``` + +## `pkg-builder clean` + +Clean build artifacts from the working directory. + +```bash +pkg-builder clean +``` diff --git a/docs/src/reference/config.md b/docs/src/reference/config.md new file mode 100644 index 00000000..dcbd40d2 --- /dev/null +++ b/docs/src/reference/config.md @@ -0,0 +1,199 @@ +# Configuration Reference + +A `pkg-builder.toml` file defines everything needed to build a Debian package. This page documents every section and field. + +## `[package]` + +Package metadata. + +```toml +[package] +name = "hello-world-c" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-c.sss" +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `name` | string | yes | Debian package name | +| `version` | string | yes | Upstream version number | +| `revision` | string | yes | Debian revision number | +| `homepage` | string | yes | Project homepage URL | +| `spec` | path | yes | Path to the debcrafter `.sss` spec file | + +## `[source]` + +Source code location. The `type` field determines which other fields are available. + +### `type = "tarball"` + +```toml +[source] +type = "tarball" +url = "https://example.com/project-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e..." +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `type` | string | yes | Must be `"tarball"` | +| `url` | string | yes | URL or local path to the source tarball | +| `hash` | string | no | SHA-512 hash of the tarball | + +### `type = "git"` + +```toml +[source] +type = "git" +url = "https://github.com/org/repo.git" +tag = "v1.0.0" +submodules = [ + { commit = "72523ee3f865...", path = "vendor/lib1" }, +] +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `type` | string | yes | Must be `"git"` | +| `url` | string | yes | Git repository URL | +| `tag` | string | yes | Git tag to check out | +| `submodules` | array | no | List of pinned submodules | + +Each submodule entry: + +| Field | Type | Description | +|-------|------|-------------| +| `commit` | string | Expected commit hash | +| `path` | string | Submodule path within the repo | + +### `type = "virtual"` + +```toml +[source] +type = "virtual" +``` + +No additional fields. Used for meta-packages with no source code. + +## `[build]` + +Build environment configuration. + +```toml +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" +chroot_dir = "/srv/chroot" +snapshot_date = "20250101" +snapshot_security_date = "20250115T000000Z" +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `distribution` | string | yes | Target distribution: `"bookworm"`, `"trixie"`, or `"noble numbat"` | +| `arch` | string | yes | Target architecture (currently only `"amd64"`) | +| `workdir` | path | no | Working directory for build artifacts | +| `chroot_dir` | path | no | Path to the chroot directory | +| `snapshot_date` | string | no | Debian archive snapshot date (`YYYYMMDD`) | +| `snapshot_security_date` | string | no | Security archive snapshot date (`YYYYMMDDTHHMMSSZ`) | + +Snapshot fields are only available for Debian distributions. See [Snapshot Pinning](../guides/snapshot-pinning.md). + +## `[runtime]` + +Runtime toolchain configuration. Required for languages that need external compilers or runtimes. + +```toml +[runtime] +recipe = "rust" +binary_url = "https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" +binary_gpg_asc = "..." +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `recipe` | string | yes | Recipe name: `c`, `rust`, `go`, `node`, `java`, `java-gradle`, `nim`, `dotnet-noble`, `dotnet-debian`, `dotnet-backup` | + +All other fields depend on the recipe. The recipe template uses `{{field_name}}` placeholders that are filled from the remaining fields via a flat key-value mapping. See [Runtime Recipes](../guides/runtime-recipes.md) for the fields required by each recipe. + +## `[tools]` + +Pinned versions of external tools. Used for reproducibility — recording which tool versions produced the build. + +```toml +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `pkg_builder` | string | yes | pkg-builder version | +| `debcrafter` | string | yes | debcrafter version or commit hash | +| `sbuild` | string | yes | sbuild version | + +## `[verify]` + +Package hash verification. Optional — omit this section if you don't need reproducibility checking. + +```toml +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "0843091f9e3cff991450c9687935e67644f6b032" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "acd656c4554f41eb2a0ad570ef99ff19db51273d" }, +] +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `package_hash` | array | yes | List of expected output file hashes | + +Each entry: + +| Field | Type | Description | +|-------|------|-------------| +| `name` | string | Expected output filename | +| `hash` | string | Expected SHA-1 hash | + +See [Verification](../guides/verification.md) for usage. + +## Complete example + +```toml +[package] +name = "hello-world-go" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-go.sss" + +[source] +type = "tarball" +url = "hello-world-go-1.0.0.tar.gz" +hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a5..." + +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-go_1.0.0-1.dsc", hash = "af497430bbe28a04b0aba2b0cee0125894cdbbb5" }, + { name = "hello-world-go_1.0.0-1_amd64.deb", hash = "fb84917f1065d70cacb25bc41b9a13606710b3de" }, +] +``` diff --git a/docs/src/reference/recipes.md b/docs/src/reference/recipes.md new file mode 100644 index 00000000..8072f39f --- /dev/null +++ b/docs/src/reference/recipes.md @@ -0,0 +1,83 @@ +# Recipes Reference + +Quick-reference table of all runtime recipes and the `[runtime]` fields they require. + +## Recipe summary + +| Recipe | Language | Verification | Key fields | +|--------|----------|-------------|------------| +| `c` | C | — | *(none — no `[runtime]` needed)* | +| `rust` | Rust | GPG signature | `binary_url`, `binary_gpg_asc` | +| `go` | Go | SHA-256 | `binary_url`, `binary_checksum` | +| `node` | JavaScript, TypeScript | SHA-256 | `binary_url`, `binary_checksum` | +| `java` | Java | SHA-256 | `binary_url`, `binary_checksum`, `jdk_version` | +| `java-gradle` | Java + Gradle | SHA-256 | `binary_url`, `binary_checksum`, `jdk_version`, `gradle_version`, `gradle_binary_url`, `gradle_binary_checksum` | +| `nim` | Nim | SHA-256 | `binary_url`, `binary_checksum`, `nim_version` | +| `dotnet-noble` | .NET (Ubuntu) | SHA-1 | `packages[]` | +| `dotnet-debian` | .NET (Debian) | SHA-1 | `packages[]` | +| `dotnet-backup` | .NET (direct) | SHA-1 | `packages[]`, `extra_deps[]`? | + +Fields marked with `?` are optional. + +## Field details + +### Common fields + +| Field | Type | Description | +|-------|------|-------------| +| `recipe` | string | Recipe name (required for all) | +| `binary_url` | string | Download URL for the toolchain archive | +| `binary_checksum` | string | SHA-256 hash of the archive | +| `binary_gpg_asc` | string | Detached GPG signature (Rust only) | + +### Java fields + +| Field | Type | Description | +|-------|------|-------------| +| `jdk_version` | string | JDK version, used for install directory naming | +| `gradle_version` | string | Gradle version (java-gradle only) | +| `gradle_binary_url` | string | Gradle distribution download URL | +| `gradle_binary_checksum` | string | SHA-256 hash of the Gradle distribution | + +### Nim fields + +| Field | Type | Description | +|-------|------|-------------| +| `nim_version` | string | Nim version, used for install directory naming | + +### .NET package fields + +The `dotnet-*` recipes use a `packages` array instead of `binary_url`: + +```toml +[runtime] +recipe = "dotnet-noble" +packages = [ + { name = "dotnet-sdk-8.0", apt_name = "dotnet-sdk-8.0", url = "https://...", hash = "sha1..." }, +] +``` + +| Field | Type | Description | +|-------|------|-------------| +| `packages[].name` | string | Package filename (without `.deb`) | +| `packages[].apt_name` | string | APT package name (for `dotnet-noble` and `dotnet-debian`) | +| `packages[].url` | string | Download URL for the `.deb` file | +| `packages[].hash` | string | SHA-1 hash of the `.deb` file | + +The `dotnet-backup` recipe also supports: + +| Field | Type | Description | +|-------|------|-------------| +| `extra_deps[].name` | string | Additional APT packages to install | + +## Recipe template syntax + +Recipe files in `runtimes/` use a simple template language: + +- `{{field_name}}` — replaced with the value of `[runtime].field_name` +- `APT_INSTALL ` — install packages via apt +- `APT_REMOVE ` — remove packages via apt +- `DOWNLOAD ` — download a file +- `RUN ` — execute a shell command +- `SYMLINK ` — create a symbolic link +- `REPEAT IN {{list}}` / `END` — iterate over an array field diff --git a/docs/src/troubleshooting.md b/docs/src/troubleshooting.md new file mode 100644 index 00000000..28f7ba76 --- /dev/null +++ b/docs/src/troubleshooting.md @@ -0,0 +1,76 @@ +# Troubleshooting + +## Lintian errors + +### `build-depends-on-build-essential` + +```text +E: source: build-depends-on-build-essential Build-Depends +``` + +Remove `build-essential` from your dependencies. The `build-essential` packages are already present in the minimal chroot environment provided by sbuild. + +### Copyright file issues + +Lintian may report missing or incorrect copyright information. The copyright file must account for all licenses found in the source. + +To generate a starting point, check out the source and run: + +```bash +debmake -c > debian/copyright +``` + +A typical `debian/copyright` file: + +```text +Files: * +Copyright: 2022 ORIGINAL PACKAGE AUTHORS +License: GPL-3+ + +Files: debian/* +Copyright: 2022 MAINTAINER_NAME +License: GPL-3+ + +License: GPL-3+ + The full text of the GPL version 3 is distributed in + /usr/share/common-licenses/GPL-3 on Debian systems. +``` + +Some source files may have different licenses in their headers. Compare the generated output against the existing copyright file to find discrepancies. + +### Suppressing lintian warnings + +For warnings that don't apply to your package, add overrides: + +- **Binary package warnings**: `src/debian/.lintian-overrides` +- **Source package warnings**: `src/debian/source/lintian-overrides` + +## Build environment issues + +### Chroot not found + +If `pkg-builder build` fails because the chroot doesn't exist, create it first: + +```bash +pkg-builder --config path/to/pkg-builder.toml env create +``` + +### Stale chroot + +If builds fail due to stale packages in the chroot, clean and recreate it: + +```bash +pkg-builder --config path/to/pkg-builder.toml env clean +pkg-builder --config path/to/pkg-builder.toml env create +``` + +## Hash verification failures + +If `pkg-builder verify` reports mismatched hashes: + +1. **Check snapshot pinning** — without pinned snapshots, dependency versions may change between builds +2. **Check tool versions** — ensure the `[tools]` section matches the versions actually installed +3. **Check architecture** — hashes are architecture-specific +4. **Rebuild from clean** — run `pkg-builder clean` then rebuild with `pkg-builder build` + +See [Verification](guides/verification.md) for more on setting up reproducible builds. diff --git a/examples/bookworm/git-package/nimbus/hello-world.changelog b/examples/bookworm/c/hello-world/hello-world-c.changelog similarity index 65% rename from examples/bookworm/git-package/nimbus/hello-world.changelog rename to examples/bookworm/c/hello-world/hello-world-c.changelog index c23cbe39..73d8c862 100644 --- a/examples/bookworm/git-package/nimbus/hello-world.changelog +++ b/examples/bookworm/c/hello-world/hello-world-c.changelog @@ -1,4 +1,4 @@ -hello-world (1.0.0-1) bookworm; urgency=medium +hello-world-c (1.0.0-1) bookworm; urgency=medium * Initial packaging diff --git a/examples/bookworm/c/hello-world/hello-world.sps b/examples/bookworm/c/hello-world/hello-world-c.sps similarity index 96% rename from examples/bookworm/c/hello-world/hello-world.sps rename to examples/bookworm/c/hello-world/hello-world-c.sps index 386cacbf..212af3eb 100644 --- a/examples/bookworm/c/hello-world/hello-world.sps +++ b/examples/bookworm/c/hello-world/hello-world-c.sps @@ -1,4 +1,4 @@ -name = "hello-world" +name = "hello-world-c" architecture = "any" summary = """Example Package This is a short description of the package. It should provide a brief summary diff --git a/examples/bookworm/c/hello-world/hello-world.sss b/examples/bookworm/c/hello-world/hello-world-c.sss similarity index 69% rename from examples/bookworm/c/hello-world/hello-world.sss rename to examples/bookworm/c/hello-world/hello-world-c.sss index 26b5eb7b..9d3c3c1a 100644 --- a/examples/bookworm/c/hello-world/hello-world.sss +++ b/examples/bookworm/c/hello-world/hello-world-c.sss @@ -1,7 +1,7 @@ -name = "hello-world" +name = "hello-world-c" maintainer = "John Doe " section = "net" variants = [] build_depends = [] -packages = ["hello-world"] +packages = ["hello-world-c"] skip_debug_symbols = true \ No newline at end of file diff --git a/examples/bookworm/c/hello-world/pkg-builder-verify.toml b/examples/bookworm/c/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 6655797a..00000000 --- a/examples/bookworm/c/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,5 +0,0 @@ -[verify] -package_hash=[ - {name= "hello-world_1.0.0-1.dsc", hash="924c9e4711c1f05e42817ec25027e8a43887cddc"}, - {name= "hello-world_1.0.0-1_amd64.deb", hash="c39f8042ef79564dfe8e6ccac6c183187bf6da7a"} -] \ No newline at end of file diff --git a/examples/bookworm/c/hello-world/pkg-builder.toml b/examples/bookworm/c/hello-world/pkg-builder.toml index ca74b5d9..9a817aab 100644 --- a/examples/bookworm/c/hello-world/pkg-builder.toml +++ b/examples/bookworm/c/hello-world/pkg-builder.toml @@ -1,30 +1,27 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-c" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-c.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" +[source] +type = "tarball" +url = "hello-world-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" -[package_type.language_env] -language_env = "c" - -[build_env] -codename="bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" \ No newline at end of file +workdir = "~/.pkg-builder/packages/bookworm" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "f0131a2e588dcbbabf3258f16ddceedca9a0f9e6ce9d49667992b4a5a5d96c46" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "ddaca84a08136ae206b94d3c5a0d6e03839e9063a3e78954e3bd942ebb54fda5" }, +] diff --git a/examples/bookworm/c/hello-world/sbuild.conf b/examples/bookworm/c/hello-world/sbuild.conf new file mode 100644 index 00000000..d25ebb4a --- /dev/null +++ b/examples/bookworm/c/hello-world/sbuild.conf @@ -0,0 +1,18 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-c-1.0.0-1"; + + +1; diff --git a/examples/bookworm/c/hello-world/src/debian/hello-world-c.lintian-overrides b/examples/bookworm/c/hello-world/src/debian/hello-world-c.lintian-overrides new file mode 100644 index 00000000..19a57a51 --- /dev/null +++ b/examples/bookworm/c/hello-world/src/debian/hello-world-c.lintian-overrides @@ -0,0 +1,6 @@ +# not a bug +hello-world-c: initial-upload-closes-no-bugs [usr/share/doc/hello-world-c/changelog.Debian.gz:1] +# not a bug +hello-world-c: maintainer-script-ignores-errors [postrm] +# FIX this +hello-world-c: no-manual-page [usr/bin/hello_world] \ No newline at end of file diff --git a/examples/bookworm/c/hello-world/src/debian/hello-world.lintian-overrides b/examples/bookworm/c/hello-world/src/debian/hello-world.lintian-overrides deleted file mode 100644 index 12cdb019..00000000 --- a/examples/bookworm/c/hello-world/src/debian/hello-world.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -# not a bug -hello-world: initial-upload-closes-no-bugs [usr/share/doc/hello-world/changelog.Debian.gz:1] -# not a bug -hello-world: maintainer-script-ignores-errors [postrm] -# FIX this -hello-world: no-manual-page [usr/bin/hello_world] \ No newline at end of file diff --git a/examples/bookworm/dotnet/hello-world/pkg-builder-verify.toml b/examples/bookworm/dotnet/hello-world/pkg-builder-verify.toml deleted file mode 100644 index d7d3d6af..00000000 --- a/examples/bookworm/dotnet/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,8 +0,0 @@ -[verify] -package_hash=[ - { hash="59b0a3aa49c52e699b9b0c249b1ebd506af55f15", name= "hello-world-dotnet_1.0.0-1.dsc"}, - { hash="0ef2133c3ffe3239f70afcee13ce171a77ed7437", name= "hello-world-dotnet_1.0.0.orig.tar.gz"}, - { hash="97ce49a5e1c561037f89c812ac58d00e4e1a1644", name= "hello-world-dotnet_1.0.0-1.debian.tar.xz"}, -# { hash="6201935f6ce8c21980f8a3197503f2fbe20c0828", name= "hello-world-dotnet_1.0.0-1_amd64.buildinfo"}, - { hash="8bd73ae87a4677be383c7445fe21e2cb5f3b49e8", name= "hello-world-dotnet_1.0.0-1_amd64.deb"}, -] diff --git a/examples/bookworm/dotnet/hello-world/pkg-builder.toml b/examples/bookworm/dotnet/hello-world/pkg-builder.toml index 7eaf3cb7..4f516e58 100644 --- a/examples/bookworm/dotnet/hello-world/pkg-builder.toml +++ b/examples/bookworm/dotnet/hello-world/pkg-builder.toml @@ -1,45 +1,42 @@ -[package_fields] -spec_file = "hello-world-dotnet.sss" -package_name = "hello-world-dotnet" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-dotnet" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-dotnet.sss" -[package_type] -# virtual | git | default -package_type = "default" -tarball_url = "hello-world-dotnet-1.0.0.tar.gz" -tarball_hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" +[source] +type = "tarball" +url = "hello-world-dotnet-1.0.0.tar.gz" +hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" -[package_type.language_env] -language_env = "dotnet" -# Because MS force pushes the security update onto packages, without using revision numbers -dotnet_packages = [ +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "dotnet-backup" +packages = [ { name = "netstandard-targeting-pack-2.1_2.1.0-1_amd64", hash = "c849f17d5e8cdce4b068e2897939be7de4b839d3", url = "http://backup.eth-nodes.com/20240529/netstandard-targeting-pack-2.1_2.1.0-1_amd64.deb" }, { name = "dotnet-apphost-pack-8.0_8.0.5-1_amd64", hash = "18b0d4bed3b62495564c18a6d1c30181c33831b4", url = "http://backup.eth-nodes.com/20240529/dotnet-apphost-pack-8.0_8.0.5-1_amd64.deb" }, { name = "dotnet-targeting-pack-8.0_8.0.5-1_amd64", hash = "2727152580762a636e62f9c490c19e18339401a9", url = "http://backup.eth-nodes.com/20240529/dotnet-targeting-pack-8.0_8.0.5-1_amd64.deb" }, - { name = "dotnet-runtime-deps-8.0_8.0.5-1_amd64", hash="1f7f67a6fef920983ab2243c1c660d08e228cedf", url="http://backup.eth-nodes.com/20240529/dotnet-runtime-deps-8.0_8.0.5-1_amd64.deb"}, - { name = "dotnet-host_8.0.5-1_amd64", hash="87414e005e39785e1ba32ce8cca97878ca4c6828", url="http://backup.eth-nodes.com/20240529/dotnet-host_8.0.5-1_amd64.deb"}, - { name = "dotnet-hostfxr-8.0_8.0.5-1_amd64", hash="e1ec0e6b838dabfb5b47ae1b15706026996d6a7c", url="http://backup.eth-nodes.com/20240529/dotnet-hostfxr-8.0_8.0.5-1_amd64.deb"}, + { name = "dotnet-runtime-deps-8.0_8.0.5-1_amd64", hash = "1f7f67a6fef920983ab2243c1c660d08e228cedf", url = "http://backup.eth-nodes.com/20240529/dotnet-runtime-deps-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-host_8.0.5-1_amd64", hash = "87414e005e39785e1ba32ce8cca97878ca4c6828", url = "http://backup.eth-nodes.com/20240529/dotnet-host_8.0.5-1_amd64.deb" }, + { name = "dotnet-hostfxr-8.0_8.0.5-1_amd64", hash = "e1ec0e6b838dabfb5b47ae1b15706026996d6a7c", url = "http://backup.eth-nodes.com/20240529/dotnet-hostfxr-8.0_8.0.5-1_amd64.deb" }, { name = "dotnet-runtime-8.0_8.0.5-1_amd64", hash = "8d2443146631a861ade47a184a5b44446c6b636d", url = "http://backup.eth-nodes.com/20240529/dotnet-runtime-8.0_8.0.5-1_amd64.deb" }, - { name = "aspnetcore-targeting-pack-8.0_8.0.5-1_amd64", hash="4b6bcf15e50db2d177e6e0298a72eeae7c43d2a3", url="http://backup.eth-nodes.com/20240529/aspnetcore-targeting-pack-8.0_8.0.5-1_amd64.deb"}, - { name = "aspnetcore-runtime-8.0_8.0.5-1_amd64", hash = "7676b5b02bbc37393089418e8a03320b10e914fd", url = "http://backup.eth-nodes.com/20240529/aspnetcore-runtime-8.0_8.0.5-1_amd64.deb"}, + { name = "aspnetcore-targeting-pack-8.0_8.0.5-1_amd64", hash = "4b6bcf15e50db2d177e6e0298a72eeae7c43d2a3", url = "http://backup.eth-nodes.com/20240529/aspnetcore-targeting-pack-8.0_8.0.5-1_amd64.deb" }, + { name = "aspnetcore-runtime-8.0_8.0.5-1_amd64", hash = "7676b5b02bbc37393089418e8a03320b10e914fd", url = "http://backup.eth-nodes.com/20240529/aspnetcore-runtime-8.0_8.0.5-1_amd64.deb" }, { name = "dotnet-sdk-8.0_8.0.204-1_amd64", hash = "a94237cb852aae05b67a5c8428a6c4f9cfb4beaa", url = "http://backup.eth-nodes.com/20240529/dotnet-sdk-8.0_8.0.204-1_amd64.deb" }, ] -use_backup_version = true +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" -[build_env] -codename = "bookworm" -arch = "amd64" -pkg_builder_version = "0.3.1" -debcrafter_version = "8189263" -run_lintian = true -run_piuparts = true -run_autopkgtest = true -lintian_version = "2.116.3" -piuparts_version = "1.1.7" -autopkgtest_version = "5.28" -sbuild_version = "0.85.6" -# package directory -workdir = "~/.pkg-builder/packages/bookworm" \ No newline at end of file +[verify] +package_hash = [ + { name = "hello-world-dotnet_1.0.0-1.dsc", hash = "2400ea45de1582526a6746a7e364bddf68aff508" }, + { name = "hello-world-dotnet_1.0.0-1_amd64.deb", hash = "3e291bd51327485e7b55190c0fccb0f48ce929e6" }, +] diff --git a/examples/bookworm/python/hello-world/hello-world-python.changelog b/examples/bookworm/git-package/nimbus/hello-world-git-nim.changelog similarity index 62% rename from examples/bookworm/python/hello-world/hello-world-python.changelog rename to examples/bookworm/git-package/nimbus/hello-world-git-nim.changelog index deca6d52..b3130ccc 100644 --- a/examples/bookworm/python/hello-world/hello-world-python.changelog +++ b/examples/bookworm/git-package/nimbus/hello-world-git-nim.changelog @@ -1,4 +1,4 @@ -hello-world-python (1.0.0-1) bookworm; urgency=medium +hello-world-git-nim (1.0.0-1) bookworm; urgency=medium * Initial packaging diff --git a/examples/jammy/c/hello-world/hello-world.sps b/examples/bookworm/git-package/nimbus/hello-world-git-nim.sps similarity index 95% rename from examples/jammy/c/hello-world/hello-world.sps rename to examples/bookworm/git-package/nimbus/hello-world-git-nim.sps index 386cacbf..651f4875 100644 --- a/examples/jammy/c/hello-world/hello-world.sps +++ b/examples/bookworm/git-package/nimbus/hello-world-git-nim.sps @@ -1,4 +1,4 @@ -name = "hello-world" +name = "hello-world-git-nim" architecture = "any" summary = """Example Package This is a short description of the package. It should provide a brief summary diff --git a/examples/jammy/c/hello-world/hello-world.sss b/examples/bookworm/git-package/nimbus/hello-world-git-nim.sss similarity index 65% rename from examples/jammy/c/hello-world/hello-world.sss rename to examples/bookworm/git-package/nimbus/hello-world-git-nim.sss index 26b5eb7b..1f88c804 100644 --- a/examples/jammy/c/hello-world/hello-world.sss +++ b/examples/bookworm/git-package/nimbus/hello-world-git-nim.sss @@ -1,7 +1,7 @@ -name = "hello-world" +name = "hello-world-git-nim" maintainer = "John Doe " section = "net" variants = [] build_depends = [] -packages = ["hello-world"] +packages = ["hello-world-git-nim"] skip_debug_symbols = true \ No newline at end of file diff --git a/examples/bookworm/git-package/nimbus/pkg-builder-verify.toml b/examples/bookworm/git-package/nimbus/pkg-builder-verify.toml deleted file mode 100644 index 9099f583..00000000 --- a/examples/bookworm/git-package/nimbus/pkg-builder-verify.toml +++ /dev/null @@ -1,9 +0,0 @@ -[verify] -package_hash=[ - {"name"= "hello-world_1.0.0-1.dsc", hash="8d554d62f710de2c7865df51a4fa67c708719e0807cf04aafd10669feb10e4b2"}, - {"name"= "hello-world_1.0.0-1_amd64.deb", hash="bac691148118516d1689857952ab52cd4e9baa15ceb0f334c6c20bc692b74476"}, -] - - - - diff --git a/examples/bookworm/git-package/nimbus/pkg-builder.toml b/examples/bookworm/git-package/nimbus/pkg-builder.toml index abc2aa54..34e300e3 100644 --- a/examples/bookworm/git-package/nimbus/pkg-builder.toml +++ b/examples/bookworm/git-package/nimbus/pkg-builder.toml @@ -1,17 +1,15 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-git-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-git-nim.sss" -[package_type] -# virtual | git | default -package_type="git" -git_url="https://github.com/status-im/nimbus-eth2.git" -git_tag="v24.3.0" +[source] +type = "git" +url = "https://github.com/status-im/nimbus-eth2.git" +tag = "v24.3.0" submodules = [ - # vendor/EIPs commit is different as it was forced pushed :( {commit = "72523ee3f865e09f8a6117c1b5e74cbb2df4f60e", path = "vendor/EIPs"}, {commit = "ab3ff9fad45fa7e20d749d0a03a7567225f5dd4a", path = "vendor/NimYAML"}, {commit = "ab581251bcda11e3cc120cc9e9ad1ad679340949", path = "vendor/eth2-networks"}, @@ -57,31 +55,22 @@ submodules = [ {commit = "3866a8ab98fc6e0e6d406b88800aed72163d5fd4", path = "vendor/nimbus-build-system"}, {commit = "ce9945b1b159d4c9b628f8c4cd2d262964692810", path = "vendor/nimbus-security-resources"}, {commit = "0c6ddab03a99805239b7875f71d2ca95fbed6f85", path = "vendor/nimcrypto"}, - {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"} + {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"}, ] - -[package_type.language_env] -language_env = "nim" -nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" - -[build_env] -codename="bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "latest" -run_lintian=false -run_piuparts=false -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" - - +workdir = "~/.pkg-builder/packages/bookworm" +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" +nim_version = "2.0.2" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/bookworm/git-package/nimbus/src/debian/hello-world.lintian-overrides b/examples/bookworm/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides similarity index 100% rename from examples/bookworm/git-package/nimbus/src/debian/hello-world.lintian-overrides rename to examples/bookworm/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides diff --git a/examples/bookworm/go/hello-world/pkg-builder-verify.toml b/examples/bookworm/go/hello-world/pkg-builder-verify.toml deleted file mode 100644 index d74e7ab2..00000000 --- a/examples/bookworm/go/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="be38416d57cf486e6b1f66b474e69563a3ec8bcb", name= "hello-world-go_1.0.0-1.dsc"}, - { hash="e86b15349d902a2fabe356e386b034ed9e5a10c4", name= "hello-world-go_1.0.0.orig.tar.gz"}, - { hash="a54c95b2e96fb70a7152a3061e5fb297ba75c6c1", name= "hello-world-go_1.0.0-1.debian.tar.xz"}, - { hash="5dc4afdcf183dec51ad4962a226c42664a59133f", name= "hello-world-go_1.0.0-1_amd64.deb"}, -] diff --git a/examples/bookworm/go/hello-world/pkg-builder.toml b/examples/bookworm/go/hello-world/pkg-builder.toml index 2c232ccd..0989e474 100644 --- a/examples/bookworm/go/hello-world/pkg-builder.toml +++ b/examples/bookworm/go/hello-world/pkg-builder.toml @@ -1,33 +1,32 @@ -[package_fields] -spec_file = "hello-world-go.sss" -package_name = "hello-world-go" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-go" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-go.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-go-1.0.0.tar.gz" -tarball_hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" +[source] +type = "tarball" +url = "hello-world-go-1.0.0.tar.gz" +hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" -[package_type.language_env] -language_env = "go" -go_version = "1.22.2" -go_binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" -go_binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" - -[build_env] -codename="bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-go_1.0.0-1.dsc", hash = "e991a8b08e6f850b6facc9fca95bbbcab24cf118f31d9094f554ac4bbd47ab64" }, + { name = "hello-world-go_1.0.0-1_amd64.deb", hash = "e67ed267f79f818a6fbacebf276bb870b5cca90ccd87537b364e37a2fbf9908f" }, +] diff --git a/examples/bookworm/go/hello-world/sbuild.conf b/examples/bookworm/go/hello-world/sbuild.conf new file mode 100644 index 00000000..a980c660 --- /dev/null +++ b/examples/bookworm/go/hello-world/sbuild.conf @@ -0,0 +1,38 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: go | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-go-1.0.0-1"; + +# Runtime: Go +my $binary_url = 'https://go.dev/dl/go1.22.2.linux-amd64.tar.gz'; +my $binary_checksum = '5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/go.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/go.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm -f /tmp/go.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/local/go/bin/go /usr/bin/go', + 'chmod -R a+rwx /usr/local/go/pkg', + 'apt remove -y wget', + 'go version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/go/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/go/hello-world/src/debian/source/lintian-overrides index fa6b7e30..1266bed7 100644 --- a/examples/bookworm/go/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/go/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-go source: debian-rules-ignores-make-clean-error [debian/rules:25] +hello-world-go source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/java-gradle/hello-world/pkg-builder-verify.toml b/examples/bookworm/java-gradle/hello-world/pkg-builder-verify.toml deleted file mode 100644 index b7078148..00000000 --- a/examples/bookworm/java-gradle/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="a59da8a216ca0cb291b2eb0fb24f26beb22b86fe", name= "hello-world-java-gradle_1.0.0-1.dsc"}, - { hash="eef991395fabb27016cc1a2e37cbaa04fd869de8", name= "hello-world-java-gradle_1.0.0.orig.tar.gz"}, - { hash="cd3bec7ec76c3344ce4b9f6ec34c9895aa633599", name= "hello-world-java-gradle_1.0.0-1.debian.tar.xz"}, - { hash="a09043df4d893fcf5c50134e3b1e97bc040f10a4", name= "hello-world-java-gradle_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/java-gradle/hello-world/pkg-builder.toml b/examples/bookworm/java-gradle/hello-world/pkg-builder.toml index 89ddedce..392ada9e 100644 --- a/examples/bookworm/java-gradle/hello-world/pkg-builder.toml +++ b/examples/bookworm/java-gradle/hello-world/pkg-builder.toml @@ -1,39 +1,36 @@ -[package_fields] -spec_file = "hello-world-java-gradle.sss" -package_name = "hello-world-java-gradle" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-java-gradle" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java-gradle.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-gradle-1.0.0.tar.gz" -tarball_hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" +[source] +type = "tarball" +url = "hello-world-java-gradle-1.0.0.tar.gz" +hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" -[package_type.language_env.gradle] -gradle_version="8.7" -gradle_binary_url="https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" -gradle_binary_checksum="544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" +[runtime] +recipe = "java-gradle" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" +gradle_binary_url = "https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" +gradle_binary_checksum = "544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" +jdk_version = "17.0.10" +gradle_version = "8.7" -[build_env] -codename = "bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir = "~/.pkg-builder/packages" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java-gradle_1.0.0-1.dsc", hash = "446b21275eecfb3e2ab97ac4016e00f46ff95ae370a164f6b4663ea8b7939074" }, + { name = "hello-world-java-gradle_1.0.0-1_amd64.deb", hash = "7afd12e6dda840b6e321664b2bcb253c696d4d3f1d8b6b5b765a6d07691ce599" }, +] diff --git a/examples/bookworm/java-gradle/hello-world/sbuild.conf b/examples/bookworm/java-gradle/hello-world/sbuild.conf new file mode 100644 index 00000000..29bf79ab --- /dev/null +++ b/examples/bookworm/java-gradle/hello-world/sbuild.conf @@ -0,0 +1,50 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java-gradle | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-java-gradle-1.0.0-1"; + +# Runtime: Java with Gradle +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '17.0.10'; +my $gradle_binary_url = 'https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip'; +my $gradle_binary_checksum = '544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d'; +my $gradle_version = '8.7'; + +my @runtime_commands = ( + 'apt install -y wget unzip', + # JDK + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + # Gradle + "wget -q -O /tmp/gradle.zip $gradle_binary_url", + "echo \"$gradle_binary_checksum /tmp/gradle.zip\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "cd /tmp && unzip -q gradle.zip && mv gradle-${gradle_version} /opt/lib/ && rm -f /tmp/gradle.zip /tmp/hash_file.txt", + "ln -s /opt/lib/gradle-${gradle_version}/bin/gradle /usr/bin/gradle", + 'apt remove -y wget unzip', + 'java -version', + 'gradle -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/java-gradle/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/java-gradle/hello-world/src/debian/source/lintian-overrides index 083a9150..06318496 100644 --- a/examples/bookworm/java-gradle/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/java-gradle/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-java-gradle source: debian-rules-ignores-make-clean-error [debian/rules:19] +hello-world-java-gradle source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/java/hello-world/pkg-builder-verify.toml b/examples/bookworm/java/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 9ce2784e..00000000 --- a/examples/bookworm/java/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="e4e358c0f5444c1dc3bde520561b0d16e867c3b1", name= "hello-world-java_1.0.0-1.dsc"}, - { hash="8b017e7ea5f6653691e37d324faf40dc15b5cfd5", name= "hello-world-java_1.0.0.orig.tar.gz"}, - { hash="f9220aa6855f8e548d13c0a760a3ebc4f371d196", name= "hello-world-java_1.0.0-1.debian.tar.xz"}, - { hash="ff1ad66a164f01ecd60b7f49bfde88bd09624b9c", name= "hello-world-java_1.0.0-1_amd64.deb"}, -] diff --git a/examples/bookworm/java/hello-world/pkg-builder.toml b/examples/bookworm/java/hello-world/pkg-builder.toml index 680f6105..f750798e 100644 --- a/examples/bookworm/java/hello-world/pkg-builder.toml +++ b/examples/bookworm/java/hello-world/pkg-builder.toml @@ -1,34 +1,32 @@ -[package_fields] -spec_file = "hello-world-java.sss" -package_name = "hello-world-java" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-java" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-1.0.0.tar.gz" -tarball_hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" +[source] +type = "tarball" +url = "hello-world-java-1.0.0.tar.gz" +hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" - -[build_env] -codename = "bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir = "~/.pkg-builder/packages" \ No newline at end of file +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "java" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java_1.0.0-1.dsc", hash = "e35ca8aecd16268f1f42fbfed26a4e0cf4eb06cd3c281cd0cb47bcf3c951f7bb" }, + { name = "hello-world-java_1.0.0-1_amd64.deb", hash = "92a1d60b18c1adf8ef7ce9444021727f463f2f588f4d3e6c770534039b97f1b6" }, +] diff --git a/examples/bookworm/java/hello-world/sbuild.conf b/examples/bookworm/java/hello-world/sbuild.conf new file mode 100644 index 00000000..c2a574a7 --- /dev/null +++ b/examples/bookworm/java/hello-world/sbuild.conf @@ -0,0 +1,40 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-java-1.0.0-1"; + +# Runtime: Java (JDK only) +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '{{jdk_version}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + 'apt remove -y wget', + 'java -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/java/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/java/hello-world/src/debian/source/lintian-overrides index bf0fc1ba..62a3373c 100644 --- a/examples/bookworm/java/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/java/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-java source: debian-rules-ignores-make-clean-error [debian/rules:17] +hello-world-java source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/javascript/hello-world/pkg-builder-verify.toml b/examples/bookworm/javascript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 1b35c774..00000000 --- a/examples/bookworm/javascript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="ca0799b985835c9dff2f3110bcbe35fd96fcc647", name= "hello-world-javascript_1.0.0-1.dsc"}, - { hash="161b7ac1a3dea76b1f98b10f0ae57ea601b9e642", name= "hello-world-javascript_1.0.0.orig.tar.gz"}, - { hash="6e83c9ecadb34080ea12081bcca6c16db50b1cdd", name= "hello-world-javascript_1.0.0-1.debian.tar.xz"}, - { hash="24fe105ede4eaedcbe0fc5f3777879352a3831bc", name= "hello-world-javascript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/javascript/hello-world/pkg-builder.toml b/examples/bookworm/javascript/hello-world/pkg-builder.toml index 0396eb64..a0f938ce 100644 --- a/examples/bookworm/javascript/hello-world/pkg-builder.toml +++ b/examples/bookworm/javascript/hello-world/pkg-builder.toml @@ -1,34 +1,33 @@ -[package_fields] -spec_file = "hello-world-javascript.sss" -package_name = "hello-world-javascript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-javascript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-javascript.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-javascript-1.0.0.tar.gz" -tarball_hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" +[source] +type = "tarball" +url = "hello-world-javascript-1.0.0.tar.gz" +hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" yarn_version = "1.22.19" -[build_env] -codename="bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-javascript_1.0.0-1.dsc", hash = "0fd22a899b076864e1a11e7b991de81b212224c94e285d53da66aafd183cbd8a" }, + { name = "hello-world-javascript_1.0.0-1_amd64.deb", hash = "a63f538307d81a285dc13f748db2a150b57e40007dc8dcc0c5c83e77cc542206" }, +] diff --git a/examples/bookworm/javascript/hello-world/sbuild.conf b/examples/bookworm/javascript/hello-world/sbuild.conf new file mode 100644 index 00000000..e9148eee --- /dev/null +++ b/examples/bookworm/javascript/hello-world/sbuild.conf @@ -0,0 +1,41 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-javascript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/javascript/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/javascript/hello-world/src/debian/source/lintian-overrides index 0880cb91..10f2ad8d 100644 --- a/examples/bookworm/javascript/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/javascript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-javascript source: debian-rules-ignores-make-clean-error [debian/rules:18] +hello-world-javascript source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/nim/hello-world/pkg-builder-verify.toml b/examples/bookworm/nim/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 00b4344c..00000000 --- a/examples/bookworm/nim/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="7f193beb2ec74e4571fe6b035abfc124a431136e", name= "hello-world-nim_1.0.0-1.dsc"}, - { hash="a1b9eb72ce3b72094e6d815ff70208e7a88553cc", name= "hello-world-nim_1.0.0.orig.tar.gz"}, - { hash="abff1c040dab55f6cd93c68ea12dea5949ca8323", name= "hello-world-nim_1.0.0-1.debian.tar.xz"}, - { hash="bcdccba830294f424114257f475d50c7de0dfcb8", name= "hello-world-nim_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/nim/hello-world/pkg-builder.toml b/examples/bookworm/nim/hello-world/pkg-builder.toml index 046803b2..dbd911b3 100644 --- a/examples/bookworm/nim/hello-world/pkg-builder.toml +++ b/examples/bookworm/nim/hello-world/pkg-builder.toml @@ -1,33 +1,33 @@ -[package_fields] -spec_file = "hello-world-nim.sss" -package_name = "hello-world-nim" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-nim.sss" +[source] +type = "tarball" +url = "hello-world-nim-1.0.0.tar.gz" +hash = "b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" -[package_type] -package_type="default" -tarball_url = "hello-world-nim-1.0.0.tar.gz" -tarball_hash="b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" -[package_type.language_env] -language_env = "nim" +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" -[build_env] -codename="bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-nim_1.0.0-1.dsc", hash = "0f45fd60496a9cea5d69c33c9eec3505377fb77b087e902da8fd6d43777316e4" }, + { name = "hello-world-nim_1.0.0-1_amd64.deb", hash = "66cf4c2dfa450c3f35a4588b1dc911a3576b36be04c225e00c2bf5e81edd0e5a" }, +] diff --git a/examples/bookworm/nim/hello-world/sbuild.conf b/examples/bookworm/nim/hello-world/sbuild.conf new file mode 100644 index 00000000..32002f33 --- /dev/null +++ b/examples/bookworm/nim/hello-world/sbuild.conf @@ -0,0 +1,42 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: nim | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-nim-1.0.0-1"; + +# Runtime: Nim +# Note: binary_checksum includes the filename (e.g. "hash nim-VER-linux_x64.tar.xz") +my $binary_url = 'https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz'; +my $binary_checksum = '047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz'; +my $nim_version = '2.0.2'; + +my $nim_archive = "nim-${nim_version}-linux_x64.tar.xz"; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/$nim_archive $binary_url", + "cd /tmp && echo \"$binary_checksum\" > hash_file.txt && sha256sum -c hash_file.txt", + 'mkdir -p /opt/lib/nim', + "mkdir -p /tmp/nim-extract && tar xJf /tmp/$nim_archive -C /tmp/nim-extract --strip-components=1 && mv /tmp/nim-extract /opt/lib/nim/nim-${nim_version} && rm -f /tmp/$nim_archive /tmp/hash_file.txt", + "ln -s /opt/lib/nim/nim-${nim_version}/bin/nim /usr/bin/nim", + 'apt remove -y wget', + 'nim --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/nim/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/nim/hello-world/src/debian/source/lintian-overrides index 41777733..69356191 100644 --- a/examples/bookworm/nim/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/nim/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-nim source: debian-rules-ignores-make-clean-error [debian/rules:20] +hello-world-nim source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/python/hello-world/hello-world-1.0.0.tar.gz b/examples/bookworm/python/hello-world/hello-world-1.0.0.tar.gz deleted file mode 100644 index d9a397fc..00000000 Binary files a/examples/bookworm/python/hello-world/hello-world-1.0.0.tar.gz and /dev/null differ diff --git a/examples/bookworm/python/hello-world/hello-world-python.sps b/examples/bookworm/python/hello-world/hello-world-python.sps deleted file mode 100644 index 34d88650..00000000 --- a/examples/bookworm/python/hello-world/hello-world-python.sps +++ /dev/null @@ -1,21 +0,0 @@ -name = "hello-world-python" -architecture = "any" -summary = """Example Package -This is a short description of the package. It should provide a brief summary -of what the package does and its purpose. The short description should be -limited to a single line.""" -conflicts = [] -recommends = [] -provides = [] -suggests = [] -depends = ["python3"] -add_files = ["dist/hello_world /usr/bin"] -add_manpages = [] -long_doc = """ -Example Package - This is a short description of the package. It should provide a brief summary - of what the package does and its purpose. The short description should be - limited to a single line. - Long Description: - Example description. If not provided, lintian will fail. -""" \ No newline at end of file diff --git a/examples/bookworm/python/hello-world/hello-world-python.sss b/examples/bookworm/python/hello-world/hello-world-python.sss deleted file mode 100644 index 20761af0..00000000 --- a/examples/bookworm/python/hello-world/hello-world-python.sss +++ /dev/null @@ -1,7 +0,0 @@ -name = "hello-world-python" -maintainer = "John Doe " -section = "net" -variants = [] -build_depends = ["python3-all", "python3-pip", "python3-venv", "python3-dev"] -packages = ["hello-world-python"] -skip_debug_symbols = true \ No newline at end of file diff --git a/examples/bookworm/python/hello-world/pkg-builder-verify.toml b/examples/bookworm/python/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 235dd5d1..00000000 --- a/examples/bookworm/python/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="eb262154b73a7633ecfcb8b28c7e4282a6829fe4", name= "hello-world-python_1.0.0-1.dsc"}, - { hash="24cdab278a7c09be60caeca81b34b877c7f0b95e", name= "hello-world-python_1.0.0.orig.tar.gz"}, - { hash="6588fc2872b01ed14a555232756ec3b13d68ee73", name= "hello-world-python_1.0.0-1.debian.tar.xz"}, - { hash="e84d242836eb9f3d0ff48069afc76b82a24bddcd", name= "hello-world-python_1.0.0-1_amd64.deb"}, -] diff --git a/examples/bookworm/python/hello-world/pkg-builder.toml b/examples/bookworm/python/hello-world/pkg-builder.toml deleted file mode 100644 index 0665f6b4..00000000 --- a/examples/bookworm/python/hello-world/pkg-builder.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package_fields] -spec_file = "hello-world-python.sss" -package_name = "hello-world-python" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "1915a59fabb5859cfd4c14eb2cde7064acf3b9ff6e9e78fa68ed06f4acc482b5" - -[package_type.language_env] -language_env = "python" - -[build_env] -codename="bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" \ No newline at end of file diff --git a/examples/bookworm/python/hello-world/src/debian/hello-world-python.lintian-overrides b/examples/bookworm/python/hello-world/src/debian/hello-world-python.lintian-overrides deleted file mode 100644 index 28f28cb8..00000000 --- a/examples/bookworm/python/hello-world/src/debian/hello-world-python.lintian-overrides +++ /dev/null @@ -1,4 +0,0 @@ -hello-world-python: initial-upload-closes-no-bugs [usr/share/doc/hello-world-python/changelog.Debian.gz:1] -hello-world-python: maintainer-script-ignores-errors [postrm] -hello-world-python: hardening-no-pie [usr/bin/hello_world] -hello-world-python: no-manual-page [usr/bin/hello_world] \ No newline at end of file diff --git a/examples/bookworm/python/hello-world/src/debian/rules b/examples/bookworm/python/hello-world/src/debian/rules deleted file mode 100644 index 98e3886a..00000000 --- a/examples/bookworm/python/hello-world/src/debian/rules +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ - -override_dh_dwz: - -override_dh_auto_build: - python3 -m venv venv - . venv/bin/activate && pip install -r requirements.txt - . venv/bin/activate && pyinstaller --onefile main.py - mv dist/main dist/hello_world - chmod +x dist/hello_world diff --git a/examples/bookworm/rust/hello-world/pkg-builder-verify.toml b/examples/bookworm/rust/hello-world/pkg-builder-verify.toml deleted file mode 100644 index e1ae83ed..00000000 --- a/examples/bookworm/rust/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="d3aa1f40ca330f76b167d434f6bae999f50397e5", name= "hello-world-rust_1.0.0-1.dsc"}, - { hash="a9c7bea89015e52a5b4e24544873ec73a0c92af2", name= "hello-world-rust_1.0.0.orig.tar.gz"}, - { hash="6325d2f8fae0b4375e65960f85c524d7f09db8b4", name= "hello-world-rust_1.0.0-1.debian.tar.xz"}, - { hash="92a5b76ab75a980d92e1b52730425a3ff8c995ec", name= "hello-world-rust_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/rust/hello-world/pkg-builder.toml b/examples/bookworm/rust/hello-world/pkg-builder.toml index 43254be7..173d8277 100644 --- a/examples/bookworm/rust/hello-world/pkg-builder.toml +++ b/examples/bookworm/rust/hello-world/pkg-builder.toml @@ -1,22 +1,24 @@ -[package_fields] -spec_file = "hello-world-rust.sss" -package_name = "hello-world-rust" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-rust" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-rust.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-rust-1.0.0.tar.gz" -tarball_hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" +[source] +type = "tarball" +url = "hello-world-rust-1.0.0.tar.gz" +hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" -[package_type.language_env] -language_env = "rust" -rust_version="1.77.2" -rust_binary_url="https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" -rust_binary_gpg_asc=""" ------BEGIN PGP SIGNATURE----- +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "rust" +binary_url = "https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" +binary_gpg_asc = """-----BEGIN PGP SIGNATURE----- wsFcBAABCgAQBQJmFa+iCRCFq5bm+hvl/gAAc4oP/12rJYjE54yHsCgcpf6Lg+jz h8HPP4uCET7gt7LZPBPaQPEllssvBE+OZPNXs2J/Bf9Dk+3Za2uEfSaEwRkuf2TV @@ -34,17 +36,13 @@ KGFMBQELjcFWLGcBVE45DRuVR8E3XYunjSdgLFXjfZfeGF3uiS6fNHGCH41ryqfj -----END PGP SIGNATURE----- """ -[build_env] -codename="bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-rust_1.0.0-1.dsc", hash = "9908ad8472a085ffd98e6808e71c61592eb13dc0b7e53e33dfe2e95223ec2c93" }, + { name = "hello-world-rust_1.0.0-1_amd64.deb", hash = "1dcf3c1c84d77f7a90b8372cedcea2e48a3a529fc0328f27540413d80313a251" }, +] diff --git a/examples/bookworm/rust/hello-world/sbuild.conf b/examples/bookworm/rust/hello-world/sbuild.conf new file mode 100644 index 00000000..35098e28 --- /dev/null +++ b/examples/bookworm/rust/hello-world/sbuild.conf @@ -0,0 +1,57 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: rust | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-rust-1.0.0-1"; + +# Runtime: Rust (GPG-verified) +my $binary_url = 'https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz'; +my $binary_gpg_asc = '-----BEGIN PGP SIGNATURE----- + +wsFcBAABCgAQBQJmFa+iCRCFq5bm+hvl/gAAc4oP/12rJYjE54yHsCgcpf6Lg+jz +h8HPP4uCET7gt7LZPBPaQPEllssvBE+OZPNXs2J/Bf9Dk+3Za2uEfSaEwRkuf2TV +EjLRkbxxjAx6e5FczAV0Qdd9u8O2LimndsRPOpjvIJtU4+wXnlHpPQ0lydr0rJso +/K9wdxvA3NgmNBa0SAKtGBwuziMk5tR+7gFFebJikXqnBsGgdifszL41tKSl5VkK +FUyb6xn0tA+wGmCVNiCV8JeTacr7+upJhAcMEqYWH/AuhA2vgF21W5jDPeA3VfoJ +RgPYUkbTKSdmUd68sUS5pzixxnYa6LXMBewshTim/kbxlMHxrZ+YSoOjBSuMUA/9 +ZcvqR/fdVNLXI/2oFIT4VPNM1cYmR15xBI1G5AbfOzYWoPGU9OTu4hs11Y3DCTCz +E5obQCVAm4/H8gO3hTvDiJE0Rb2M0h1uV12LkCMymzuIBrhLkVhQeekDZadJmWq0 +XlT/N86YFd8P393xYE3fpKaGqZ0fBJfX4nLdZHdZeFrov6ADjf7NLsfY0S9AnRnK +SAytDb5EQMcBZXlNKnF+mLG9l0Y4JtijEsaiMaJgzVInTIUTtkW/GlgpAgzIBQ8m +KGFMBQELjcFWLGcBVE45DRuVR8E3XYunjSdgLFXjfZfeGF3uiS6fNHGCH41ryqfj +2jwoU0cewz4tgDucAWWC +=sCT4 +-----END PGP SIGNATURE----- +'; + +my @runtime_commands = ( + 'apt install -y wget gpg gpg-agent', + "wget -q -O /tmp/rust.tar.xz $binary_url", + "echo \"$binary_gpg_asc\" > /tmp/rust.tar.xz.asc", + 'wget -qO- https://keybase.io/rust/pgp_keys.asc | gpg --import', + 'gpg --verify /tmp/rust.tar.xz.asc /tmp/rust.tar.xz', + 'mkdir -p /tmp/rust-install && tar xJf /tmp/rust.tar.xz -C /tmp/rust-install --strip-components=1 && rm -f /tmp/rust.tar.xz /tmp/rust.tar.xz.asc', + '/bin/bash /tmp/rust-install/install.sh --components=rustc,cargo,rust-std-x86_64-unknown-linux-gnu', + 'rm -rf /tmp/rust-install', + 'apt remove -y wget gpg gpg-agent', + 'rustc --version', + 'cargo --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/rust/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/rust/hello-world/src/debian/source/lintian-overrides index 071ddf8c..8167aafb 100644 --- a/examples/bookworm/rust/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/rust/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-rust source: debian-rules-ignores-make-clean-error [debian/rules:16] \ No newline at end of file +hello-world-rust source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/typescript/hello-world/pkg-builder-verify.toml b/examples/bookworm/typescript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 1ab554e0..00000000 --- a/examples/bookworm/typescript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="48dac78546615d8f7d59fe37b11dc599ccc8f7df", name= "hello-world-typescript_1.0.0-1.dsc"}, - { hash="72dded9c5b23987ca3808e61dd33d09a2632cb86", name= "hello-world-typescript_1.0.0.orig.tar.gz"}, - { hash="7c485e87a43272660d51938662c61c12c9df9be1", name= "hello-world-typescript_1.0.0-1.debian.tar.xz"}, - { hash="f096d00dae8fd738a8d455424cb14c160cab0763", name= "hello-world-typescript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/typescript/hello-world/pkg-builder.toml b/examples/bookworm/typescript/hello-world/pkg-builder.toml index 5fafe49d..6f595de5 100644 --- a/examples/bookworm/typescript/hello-world/pkg-builder.toml +++ b/examples/bookworm/typescript/hello-world/pkg-builder.toml @@ -1,34 +1,33 @@ -[package_fields] -spec_file = "hello-world-typescript.sss" -package_name = "hello-world-typescript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-typescript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-typescript.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-typescript-1.0.0.tar.gz" -tarball_hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" +[source] +type = "tarball" +url = "hello-world-typescript-1.0.0.tar.gz" +hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +[build] +distribution = "bookworm" +arch = "amd64" +workdir = "~/.pkg-builder/packages/bookworm" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" yarn_version = "1.22.19" -[build_env] -codename="bookworm" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-typescript_1.0.0-1.dsc", hash = "962fa71a835802530c0827c45982a682b7132ba72fa7f0f683ca21328d3800e5" }, + { name = "hello-world-typescript_1.0.0-1_amd64.deb", hash = "964d3c976ce38656dbfbf1eb245620238a1cac50e79096ee9d705bd27c3d76ac" }, +] diff --git a/examples/bookworm/typescript/hello-world/sbuild.conf b/examples/bookworm/typescript/hello-world/sbuild.conf new file mode 100644 index 00000000..ac6224d7 --- /dev/null +++ b/examples/bookworm/typescript/hello-world/sbuild.conf @@ -0,0 +1,41 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/hello-world-typescript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/bookworm/typescript/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/typescript/hello-world/src/debian/source/lintian-overrides index 616c696a..4209707c 100644 --- a/examples/bookworm/typescript/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/typescript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-typescript source: debian-rules-ignores-make-clean-error [debian/rules:20] +hello-world-typescript source: debian-rules-ignores-make-clean-error diff --git a/examples/bookworm/virtual/hello-world/pkg-builder-verify.toml b/examples/bookworm/virtual/hello-world/pkg-builder-verify.toml deleted file mode 100644 index a3f8012e..00000000 --- a/examples/bookworm/virtual/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="b00c74407112844bbef28f7938d85fde3dfb00d0", name= "test-virtual-package_1.0.0-1.dsc"}, - { hash="b35f46d5fb424aee57b5d666e61b2eff83543aad", name= "test-virtual-package_1.0.0.orig.tar.gz"}, - { hash="64350e6a5fdf43d1e5cff811b3bf99655b82f41e", name= "test-virtual-package_1.0.0-1.debian.tar.xz"}, - { hash="d76eb65705876de40812e830926ee79683eb10e9", name= "test-virtual-package_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/bookworm/virtual/hello-world/pkg-builder.toml b/examples/bookworm/virtual/hello-world/pkg-builder.toml index 3a1b8c87..a0b1f8de 100644 --- a/examples/bookworm/virtual/hello-world/pkg-builder.toml +++ b/examples/bookworm/virtual/hello-world/pkg-builder.toml @@ -1,24 +1,25 @@ -[package_fields] -spec_file = "test-virtual-package.sss" -package_name = "test-virtual-package" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "test-virtual-package" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "test-virtual-package.sss" -[package_type] -package_type="virtual" +[source] +type = "virtual" -[build_env] -codename="bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/bookworm" \ No newline at end of file +workdir = "~/.pkg-builder/packages/bookworm" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "test-virtual-package_1.0.0-1.dsc", hash = "8afb82972b8536623a794177ed591b5a8301a770ad1ce9869645eef31bcfd349" }, + { name = "test-virtual-package_1.0.0-1_amd64.deb", hash = "d98b41e1e1163ebd2d8f2a2483a9892256759f47c1095ab28fe29ba280ce60e0" }, +] diff --git a/examples/bookworm/virtual/hello-world/sbuild.conf b/examples/bookworm/virtual/hello-world/sbuild.conf new file mode 100644 index 00000000..014da47e --- /dev/null +++ b/examples/bookworm/virtual/hello-world/sbuild.conf @@ -0,0 +1,18 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: bookworm + +$distribution = 'bookworm'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/bookworm/test-virtual-package-1.0.0-1"; + + +1; diff --git a/examples/bookworm/virtual/hello-world/src/debian/source/lintian-overrides b/examples/bookworm/virtual/hello-world/src/debian/source/lintian-overrides index c8db6d54..37776fb6 100644 --- a/examples/bookworm/virtual/hello-world/src/debian/source/lintian-overrides +++ b/examples/bookworm/virtual/hello-world/src/debian/source/lintian-overrides @@ -1,2 +1,2 @@ # Not a bug, this is a virtual package to serve as umbrella installation for others package deps -test-virtual-package source: empty-upstream-sources \ No newline at end of file +test-virtual-package source: empty-upstream-sources diff --git a/examples/jammy/c/hello-world/pkg-builder-verify.toml b/examples/jammy/c/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 49a8ed69..00000000 --- a/examples/jammy/c/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,5 +0,0 @@ -[verify] -package_hash = [ - { name = "hello-world_1.0.0-1.dsc", hash = "92a61ca32613ab6e985f10c8088dc7e20343fdaf" }, - { name = "hello-world_1.0.0-1_amd64.deb", hash = "7c618cde4aa874863d4638f626bae7837ef0231b" } -] \ No newline at end of file diff --git a/examples/jammy/c/hello-world/pkg-builder.toml b/examples/jammy/c/hello-world/pkg-builder.toml deleted file mode 100644 index 37b8cccd..00000000 --- a/examples/jammy/c/hello-world/pkg-builder.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" - -[package_type.language_env] -language_env = "c" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" \ No newline at end of file diff --git a/examples/jammy/c/hello-world/src/debian/hello-world.lintian-overrides b/examples/jammy/c/hello-world/src/debian/hello-world.lintian-overrides deleted file mode 100644 index c34ac7e5..00000000 --- a/examples/jammy/c/hello-world/src/debian/hello-world.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -# not a bug -hello-world: initial-upload-closes-no-bugs -# not a bug -hello-world: maintainer-script-ignores-errors [postrm] -# FIX this -hello-world: no-manual-page usr/bin/hello_world diff --git a/examples/jammy/c/hello-world/src/debian/source/lintian-overrides b/examples/jammy/c/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 74263261..00000000 --- a/examples/jammy/c/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world source: no-newline-at-end debian/rules \ No newline at end of file diff --git a/examples/jammy/c/hello-world/src/debian/tests/tests b/examples/jammy/c/hello-world/src/debian/tests/tests deleted file mode 100644 index 664a5900..00000000 --- a/examples/jammy/c/hello-world/src/debian/tests/tests +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env sh - -exec 2>&1 - -set -e - -test_binary_in_path(){ - output="$(which hello_world)" - assertEquals "/usr/bin/hello_world" "$output" -} - -test_invocation(){ - output="$(hello_world)" - assertEquals "Hello, World!" "$output" -} - -. shunit2 \ No newline at end of file diff --git a/examples/jammy/dotnet/hello-world/pkg-builder-verify.toml b/examples/jammy/dotnet/hello-world/pkg-builder-verify.toml deleted file mode 100644 index dcedc40e..00000000 --- a/examples/jammy/dotnet/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="d913d8c324439cf090930fbe4e3a2f5c64eeffe3", name= "hello-world-dotnet_1.0.0-1.dsc"}, - { hash="0ef2133c3ffe3239f70afcee13ce171a77ed7437", name= "hello-world-dotnet_1.0.0.orig.tar.gz"}, - { hash="122ceca25b02c93d39e3efa49ecbc97e0cc38944", name= "hello-world-dotnet_1.0.0-1.debian.tar.xz"}, - { hash="33d699cd154d47582cf83c760eea688ce097d3d1", name= "hello-world-dotnet_1.0.0-1_amd64.deb"}, -] diff --git a/examples/jammy/dotnet/hello-world/pkg-builder.toml b/examples/jammy/dotnet/hello-world/pkg-builder.toml deleted file mode 100644 index 560323ca..00000000 --- a/examples/jammy/dotnet/hello-world/pkg-builder.toml +++ /dev/null @@ -1,53 +0,0 @@ -[package_fields] -spec_file = "hello-world-dotnet.sss" -package_name = "hello-world-dotnet" -version_number = "1.0.0" -revision_number = "1" -homepage = "https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type = "default" -tarball_url = "hello-world-dotnet-1.0.0.tar.gz" -tarball_hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" - -[package_type.language_env] -language_env = "dotnet" -# Because MS force pushes the security update onto packages, without using revision numbers -dotnet_packages = [ - { name = "netstandard-targeting-pack-2.1_2.1.0-1_amd64", hash = "c849f17d5e8cdce4b068e2897939be7de4b839d3", url = "http://backup.eth-nodes.com/20240529/netstandard-targeting-pack-2.1_2.1.0-1_amd64.deb" }, - { name = "dotnet-apphost-pack-8.0_8.0.5-1_amd64", hash = "18b0d4bed3b62495564c18a6d1c30181c33831b4", url = "http://backup.eth-nodes.com/20240529/dotnet-apphost-pack-8.0_8.0.5-1_amd64.deb" }, - { name = "dotnet-targeting-pack-8.0_8.0.5-1_amd64", hash = "2727152580762a636e62f9c490c19e18339401a9", url = "http://backup.eth-nodes.com/20240529/dotnet-targeting-pack-8.0_8.0.5-1_amd64.deb" }, - { name = "dotnet-runtime-deps-8.0_8.0.5-1_amd64", hash="1f7f67a6fef920983ab2243c1c660d08e228cedf", url="http://backup.eth-nodes.com/20240529/dotnet-runtime-deps-8.0_8.0.5-1_amd64.deb"}, - { name = "dotnet-host_8.0.5-1_amd64", hash="87414e005e39785e1ba32ce8cca97878ca4c6828", url="http://backup.eth-nodes.com/20240529/dotnet-host_8.0.5-1_amd64.deb"}, - { name = "dotnet-hostfxr-8.0_8.0.5-1_amd64", hash="e1ec0e6b838dabfb5b47ae1b15706026996d6a7c", url="http://backup.eth-nodes.com/20240529/dotnet-hostfxr-8.0_8.0.5-1_amd64.deb"}, - { name = "dotnet-runtime-8.0_8.0.5-1_amd64", hash = "8d2443146631a861ade47a184a5b44446c6b636d", url = "http://backup.eth-nodes.com/20240529/dotnet-runtime-8.0_8.0.5-1_amd64.deb" }, - { name = "aspnetcore-targeting-pack-8.0_8.0.5-1_amd64", hash="4b6bcf15e50db2d177e6e0298a72eeae7c43d2a3", url="http://backup.eth-nodes.com/20240529/aspnetcore-targeting-pack-8.0_8.0.5-1_amd64.deb"}, - { name = "aspnetcore-runtime-8.0_8.0.5-1_amd64", hash = "7676b5b02bbc37393089418e8a03320b10e914fd", url = "http://backup.eth-nodes.com/20240529/aspnetcore-runtime-8.0_8.0.5-1_amd64.deb"}, - { name = "dotnet-sdk-8.0_8.0.204-1_amd64", hash = "a94237cb852aae05b67a5c8428a6c4f9cfb4beaa", url = "http://backup.eth-nodes.com/20240529/dotnet-sdk-8.0_8.0.204-1_amd64.deb" }, -] -use_backup_version = true - -[build_env] -codename = "jammy jellyfish" -arch = "amd64" -pkg_builder_version = "0.3.1" -debcrafter_version = "8189263" -run_lintian = true -run_piuparts = true -run_autopkgtest = true -lintian_version = "2.116.3" -piuparts_version = "1.1.7" -autopkgtest_version = "5.20" -sbuild_version = "0.85.6" -# package directory -workdir = "~/.pkg-builder/packages/jammy" - - -[verify] -# if tarball_url is specified -tarball_hash = "" -# if git_source is specified and package_is_git -git_commit = "" -# output hash -bin_bash = "" diff --git a/examples/jammy/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides b/examples/jammy/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides deleted file mode 100644 index fc35a8bb..00000000 --- a/examples/jammy/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides +++ /dev/null @@ -1,7 +0,0 @@ -# if you don't upload to debian this is not a bug -hello-world-dotnet: mismatched-override initial-upload-closes-no-bugs -# if you don't upload to debian this is not a bug -hello-world-dotnet: initial-upload-closes-no-bugs -hello-world-dotnet: maintainer-script-ignores-errors [postrm] -hello-world-dotnet: no-manual-page usr/bin/hello-world - diff --git a/examples/jammy/dotnet/hello-world/src/debian/source/lintian-overrides b/examples/jammy/dotnet/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/jammy/dotnet/hello-world/src/debian/tests/tests b/examples/jammy/dotnet/hello-world/src/debian/tests/tests deleted file mode 100644 index 8b682f83..00000000 --- a/examples/jammy/dotnet/hello-world/src/debian/tests/tests +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env sh - -exec 2>&1 - -set -e - -test_binary_in_path(){ - output="$(which hello-world)" - assertEquals "/usr/bin/hello-world" "$output" -} - -#test_invocation_without_dotnet(){ -# output="$(hello-world 2>&1 || true)" -# assertContains "$output" "You must install .NET to run this application." -#} - -. shunit2 \ No newline at end of file diff --git a/examples/jammy/git-package/nimbus/hello-world.changelog b/examples/jammy/git-package/nimbus/hello-world.changelog deleted file mode 100644 index f497698d..00000000 --- a/examples/jammy/git-package/nimbus/hello-world.changelog +++ /dev/null @@ -1,5 +0,0 @@ -hello-world (1.0.0-1) jammy; urgency=medium - - * Initial packaging - - -- John Doe Tue, 17 Oct 2023 13:19:27 +0700 diff --git a/examples/jammy/git-package/nimbus/pkg-builder-verify.toml b/examples/jammy/git-package/nimbus/pkg-builder-verify.toml deleted file mode 100644 index 9099f583..00000000 --- a/examples/jammy/git-package/nimbus/pkg-builder-verify.toml +++ /dev/null @@ -1,9 +0,0 @@ -[verify] -package_hash=[ - {"name"= "hello-world_1.0.0-1.dsc", hash="8d554d62f710de2c7865df51a4fa67c708719e0807cf04aafd10669feb10e4b2"}, - {"name"= "hello-world_1.0.0-1_amd64.deb", hash="bac691148118516d1689857952ab52cd4e9baa15ceb0f334c6c20bc692b74476"}, -] - - - - diff --git a/examples/jammy/go/hello-world/pkg-builder-verify.toml b/examples/jammy/go/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 62aa3783..00000000 --- a/examples/jammy/go/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="0da0980d1b177d3f6a9d52f5e53601cbc7074e9a", name= "hello-world-go_1.0.0-1.dsc"}, - { hash="e86b15349d902a2fabe356e386b034ed9e5a10c4", name= "hello-world-go_1.0.0.orig.tar.gz"}, - { hash="fa20b31be5eb970c08498090daf0b442a9ec60ad", name= "hello-world-go_1.0.0-1.debian.tar.xz"}, - { hash="5408d8c70982b64946ee49433774f4dd85f3d3b6", name= "hello-world-go_1.0.0-1_amd64.deb"}, -] diff --git a/examples/jammy/go/hello-world/pkg-builder.toml b/examples/jammy/go/hello-world/pkg-builder.toml deleted file mode 100644 index 5d46c58c..00000000 --- a/examples/jammy/go/hello-world/pkg-builder.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package_fields] -spec_file = "hello-world-go.sss" -package_name = "hello-world-go" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-go-1.0.0.tar.gz" -tarball_hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" - -[package_type.language_env] -language_env = "go" -go_version = "1.22.2" -go_binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" -go_binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" diff --git a/examples/jammy/go/hello-world/src/debian/hello-world-go.lintian-overrides b/examples/jammy/go/hello-world/src/debian/hello-world-go.lintian-overrides deleted file mode 100644 index cb297d0f..00000000 --- a/examples/jammy/go/hello-world/src/debian/hello-world-go.lintian-overrides +++ /dev/null @@ -1,4 +0,0 @@ -hello-world-go: initial-upload-closes-no-bugs -hello-world-go: maintainer-script-ignores-errors [postrm] -hello-world-go: no-manual-page -hello-world-go: statically-linked-binary usr/lib/hello-world-go/bin/hello-world diff --git a/examples/jammy/go/hello-world/src/debian/source/lintian-overrides b/examples/jammy/go/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 313c834b..00000000 --- a/examples/jammy/go/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world-go source: debian-rules-ignores-make-clean-error (line 25) \ No newline at end of file diff --git a/examples/jammy/java-gradle/hello-world/pkg-builder-verify.toml b/examples/jammy/java-gradle/hello-world/pkg-builder-verify.toml deleted file mode 100644 index da8ee897..00000000 --- a/examples/jammy/java-gradle/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="54e72dd7bedb0684dc9d18bc7c778e5e2ae171e9", name= "hello-world-java-gradle_1.0.0-1.dsc"}, - { hash="eef991395fabb27016cc1a2e37cbaa04fd869de8", name= "hello-world-java-gradle_1.0.0.orig.tar.gz"}, - { hash="32a890f29624389822a34e448f61ea3b8f45fb62", name= "hello-world-java-gradle_1.0.0-1.debian.tar.xz"}, - { hash="ca3cebd416595025728eb68e96d6dcd27c37899e", name= "hello-world-java-gradle_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/java-gradle/hello-world/pkg-builder.toml b/examples/jammy/java-gradle/hello-world/pkg-builder.toml deleted file mode 100644 index 0e3e57e3..00000000 --- a/examples/jammy/java-gradle/hello-world/pkg-builder.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package_fields] -spec_file = "hello-world-java-gradle.sss" -package_name = "hello-world-java-gradle" -version_number = "1.0.0" -revision_number = "1" -homepage = "https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-gradle-1.0.0.tar.gz" -tarball_hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" - -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" - -[package_type.language_env.gradle] -gradle_version="8.7" -gradle_binary_url="https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" -gradle_binary_checksum="544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir = "~/.pkg-builder/packages" diff --git a/examples/jammy/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides b/examples/jammy/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides deleted file mode 100644 index 1a7b0ffe..00000000 --- a/examples/jammy/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides +++ /dev/null @@ -1,9 +0,0 @@ -# if you don't upload to debian this is not a bug -hello-world-java-gradle: initial-upload-closes-no-bugs -hello-world-java-gradle: maintainer-script-ignores-errors [postrm] -hello-world-java-gradle: no-manual-page usr/bin/hello-world -hello-world-java-gradle: script-not-executable usr/lib/hello-world-java-gradle/bin/hello.sh -hello-world-java-gradle: jar-not-in-usr-share * -hello-world-java-gradle: codeless-jar * -hello-world-java-gradle: executable-not-elf-or-script usr/lib/hello-world-java-gradle/bin/app.bat -hello-world-java-gradle: unknown-java-class-version usr/lib/hello-world-java-gradle/lib/app.jar (org/example/App.class -> 61) \ No newline at end of file diff --git a/examples/jammy/java/hello-world/pkg-builder-verify.toml b/examples/jammy/java/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 6190aacd..00000000 --- a/examples/jammy/java/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="706da7be2ace6746f66736341c3a06aba6ed9928", name= "hello-world-java_1.0.0-1.dsc"}, - { hash="8b017e7ea5f6653691e37d324faf40dc15b5cfd5", name= "hello-world-java_1.0.0.orig.tar.gz"}, - { hash="64a9661c58f93c5ca1b6f34a715a9e81ef43d50b", name= "hello-world-java_1.0.0-1.debian.tar.xz"}, - { hash="637dd1eb469bb7301072fd0ad2901ce41c28a192", name= "hello-world-java_1.0.0-1_amd64.deb"}, -] diff --git a/examples/jammy/java/hello-world/pkg-builder.toml b/examples/jammy/java/hello-world/pkg-builder.toml deleted file mode 100644 index 69a5662e..00000000 --- a/examples/jammy/java/hello-world/pkg-builder.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package_fields] -spec_file = "hello-world-java.sss" -package_name = "hello-world-java" -version_number = "1.0.0" -revision_number = "1" -homepage = "https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-1.0.0.tar.gz" -tarball_hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" - -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir = "~/.pkg-builder/packages" \ No newline at end of file diff --git a/examples/jammy/java/hello-world/src/debian/hello-world-java.lintian-overrides b/examples/jammy/java/hello-world/src/debian/hello-world-java.lintian-overrides deleted file mode 100644 index 6d2d0a34..00000000 --- a/examples/jammy/java/hello-world/src/debian/hello-world-java.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -# if you don't upload to debian this is not a bug -hello-world-java: initial-upload-closes-no-bugs -hello-world-java: maintainer-script-ignores-errors [postrm] -hello-world-java: no-manual-page usr/bin/hello-world -hello-world-java: script-not-executable [usr/lib/hello-world-java/bin/hello.sh] - diff --git a/examples/jammy/java/hello-world/src/debian/source/lintian-overrides b/examples/jammy/java/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 7fcce95a..00000000 --- a/examples/jammy/java/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world-java source: debian-rules-ignores-make-clean-error (line 17) \ No newline at end of file diff --git a/examples/jammy/javascript/hello-world/pkg-builder-verify.toml b/examples/jammy/javascript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index e233d0ed..00000000 --- a/examples/jammy/javascript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="1c931f597324d38193f78646a1b49c3715542143", name= "hello-world-javascript_1.0.0-1.dsc"}, - { hash="161b7ac1a3dea76b1f98b10f0ae57ea601b9e642", name= "hello-world-javascript_1.0.0.orig.tar.gz"}, - { hash="dcf05c19c65d06a2bcea789e03e012765f3fdae7", name= "hello-world-javascript_1.0.0-1.debian.tar.xz"}, - { hash="f5e4a08b1b823edbbe9438b2469eac62f3ca515b", name= "hello-world-javascript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/javascript/hello-world/pkg-builder.toml b/examples/jammy/javascript/hello-world/pkg-builder.toml deleted file mode 100644 index ef2a2fbc..00000000 --- a/examples/jammy/javascript/hello-world/pkg-builder.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package_fields] -spec_file = "hello-world-javascript.sss" -package_name = "hello-world-javascript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-javascript-1.0.0.tar.gz" -tarball_hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" - -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" -yarn_version = "1.22.19" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" diff --git a/examples/jammy/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides b/examples/jammy/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides deleted file mode 100644 index f0772b9c..00000000 --- a/examples/jammy/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides +++ /dev/null @@ -1,4 +0,0 @@ -hello-world-javascript: initial-upload-closes-no-bugs -hello-world-javascript: maintainer-script-ignores-errors [postrm] -hello-world-javascript: no-manual-page usr/bin/hello-world -hello-world-javascript: script-not-executable [usr/lib/hello-world-javascript/src/hello.sh] \ No newline at end of file diff --git a/examples/jammy/nim/hello-world/pkg-builder-verify.toml b/examples/jammy/nim/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 38da9948..00000000 --- a/examples/jammy/nim/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="f16b7bccffd215da7a604625b7fa877d9d3f8c67", name= "hello-world-nim_1.0.0-1.dsc"}, - { hash="a1b9eb72ce3b72094e6d815ff70208e7a88553cc", name= "hello-world-nim_1.0.0.orig.tar.gz"}, - { hash="ac5115f8dc9239f9c420708a195bb122ef39aeaf", name= "hello-world-nim_1.0.0-1.debian.tar.xz"}, - { hash="c9c11bdb2385997b13c94c34e60088389736db2b", name= "hello-world-nim_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/nim/hello-world/pkg-builder.toml b/examples/jammy/nim/hello-world/pkg-builder.toml deleted file mode 100644 index 0597ba5b..00000000 --- a/examples/jammy/nim/hello-world/pkg-builder.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package_fields] -spec_file = "hello-world-nim.sss" -package_name = "hello-world-nim" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - - -[package_type] -package_type="default" -tarball_url = "hello-world-nim-1.0.0.tar.gz" -tarball_hash="b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" - -[package_type.language_env] -language_env = "nim" -nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" diff --git a/examples/jammy/nim/hello-world/src/debian/hello-world-nim.lintian-overrides b/examples/jammy/nim/hello-world/src/debian/hello-world-nim.lintian-overrides deleted file mode 100644 index 5484f327..00000000 --- a/examples/jammy/nim/hello-world/src/debian/hello-world-nim.lintian-overrides +++ /dev/null @@ -1,3 +0,0 @@ -hello-world-nim: initial-upload-closes-no-bugs -hello-world-nim: maintainer-script-ignores-errors [postrm] -hello-world-nim: no-manual-page usr/bin/hello-world diff --git a/examples/jammy/nim/hello-world/src/debian/source/lintian-overrides b/examples/jammy/nim/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 5fe4bd8d..00000000 --- a/examples/jammy/nim/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world-nim source: debian-rules-ignores-make-clean-error (line 20) diff --git a/examples/jammy/rust/hello-world/pkg-builder-verify.toml b/examples/jammy/rust/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 62a6abdc..00000000 --- a/examples/jammy/rust/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="157cf3cea96100bcfaccde24f85c21bcd50a5c70", name= "hello-world-rust_1.0.0-1.dsc"}, - { hash="a9c7bea89015e52a5b4e24544873ec73a0c92af2", name= "hello-world-rust_1.0.0.orig.tar.gz"}, - { hash="41ebc33bc1a2d014450a3c1b81579b8e77da9148", name= "hello-world-rust_1.0.0-1.debian.tar.xz"}, - { hash="07280b8766450766a287c0c92028bda0491c446f", name= "hello-world-rust_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/rust/hello-world/pkg-builder.toml b/examples/jammy/rust/hello-world/pkg-builder.toml deleted file mode 100644 index 1b82c334..00000000 --- a/examples/jammy/rust/hello-world/pkg-builder.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package_fields] -spec_file = "hello-world-rust.sss" -package_name = "hello-world-rust" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-rust-1.0.0.tar.gz" -tarball_hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" - -[package_type.language_env] -language_env = "rust" -rust_version="1.77.2" -rust_binary_url="https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" -rust_binary_gpg_asc=""" ------BEGIN PGP SIGNATURE----- - -wsFcBAABCgAQBQJmFa+iCRCFq5bm+hvl/gAAc4oP/12rJYjE54yHsCgcpf6Lg+jz -h8HPP4uCET7gt7LZPBPaQPEllssvBE+OZPNXs2J/Bf9Dk+3Za2uEfSaEwRkuf2TV -EjLRkbxxjAx6e5FczAV0Qdd9u8O2LimndsRPOpjvIJtU4+wXnlHpPQ0lydr0rJso -/K9wdxvA3NgmNBa0SAKtGBwuziMk5tR+7gFFebJikXqnBsGgdifszL41tKSl5VkK -FUyb6xn0tA+wGmCVNiCV8JeTacr7+upJhAcMEqYWH/AuhA2vgF21W5jDPeA3VfoJ -RgPYUkbTKSdmUd68sUS5pzixxnYa6LXMBewshTim/kbxlMHxrZ+YSoOjBSuMUA/9 -ZcvqR/fdVNLXI/2oFIT4VPNM1cYmR15xBI1G5AbfOzYWoPGU9OTu4hs11Y3DCTCz -E5obQCVAm4/H8gO3hTvDiJE0Rb2M0h1uV12LkCMymzuIBrhLkVhQeekDZadJmWq0 -XlT/N86YFd8P393xYE3fpKaGqZ0fBJfX4nLdZHdZeFrov6ADjf7NLsfY0S9AnRnK -SAytDb5EQMcBZXlNKnF+mLG9l0Y4JtijEsaiMaJgzVInTIUTtkW/GlgpAgzIBQ8m -KGFMBQELjcFWLGcBVE45DRuVR8E3XYunjSdgLFXjfZfeGF3uiS6fNHGCH41ryqfj -2jwoU0cewz4tgDucAWWC -=sCT4 ------END PGP SIGNATURE----- -""" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" diff --git a/examples/jammy/rust/hello-world/src/debian/hello-world-rust.lintian-overrides b/examples/jammy/rust/hello-world/src/debian/hello-world-rust.lintian-overrides deleted file mode 100644 index fd56f794..00000000 --- a/examples/jammy/rust/hello-world/src/debian/hello-world-rust.lintian-overrides +++ /dev/null @@ -1,3 +0,0 @@ -hello-world-rust: initial-upload-closes-no-bugs -hello-world-rust: maintainer-script-ignores-errors [postrm] -hello-world-rust: no-manual-page usr/bin/hello-world diff --git a/examples/jammy/rust/hello-world/src/debian/source/lintian-overrides b/examples/jammy/rust/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index b326110c..00000000 --- a/examples/jammy/rust/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world-rust source: debian-rules-ignores-make-clean-error (line 16) \ No newline at end of file diff --git a/examples/jammy/rust/hello-world/src/debian/tests/control b/examples/jammy/rust/hello-world/src/debian/tests/control deleted file mode 100644 index 29a6ac18..00000000 --- a/examples/jammy/rust/hello-world/src/debian/tests/control +++ /dev/null @@ -1,4 +0,0 @@ -# These tests are run by autopkgtests - -Tests: tests -Depends: @, shunit2 \ No newline at end of file diff --git a/examples/jammy/typescript/hello-world/pkg-builder-verify.toml b/examples/jammy/typescript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 2c579840..00000000 --- a/examples/jammy/typescript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="a6cd528ae2ab880c0bceccbdbdfe9f73b96b5e0a", name= "hello-world-typescript_1.0.0-1.dsc"}, - { hash="72dded9c5b23987ca3808e61dd33d09a2632cb86", name= "hello-world-typescript_1.0.0.orig.tar.gz"}, - { hash="00010ca257464f3877ac3c281f7b8b6c476546b5", name= "hello-world-typescript_1.0.0-1.debian.tar.xz"}, - { hash="ad16d631771e8b120d32a28a6df93e0e27071e67", name= "hello-world-typescript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/typescript/hello-world/pkg-builder.toml b/examples/jammy/typescript/hello-world/pkg-builder.toml deleted file mode 100644 index 63713a20..00000000 --- a/examples/jammy/typescript/hello-world/pkg-builder.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package_fields] -spec_file = "hello-world-typescript.sss" -package_name = "hello-world-typescript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-typescript-1.0.0.tar.gz" -tarball_hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" - -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" -yarn_version = "1.22.19" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" diff --git a/examples/jammy/typescript/hello-world/src/debian/source/lintian-overrides b/examples/jammy/typescript/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 840f50ad..00000000 --- a/examples/jammy/typescript/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ - hello-world-typescript source: debian-rules-ignores-make-clean-error (line 20) diff --git a/examples/jammy/virtual/hello-world/pkg-builder-verify.toml b/examples/jammy/virtual/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 37b19bb8..00000000 --- a/examples/jammy/virtual/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="b4aafc174cc4a3f5454c20138f750c4262f97277", name= "test-virtual-package_1.0.0-1.dsc"}, - { hash="b35f46d5fb424aee57b5d666e61b2eff83543aad", name= "test-virtual-package_1.0.0.orig.tar.gz"}, - { hash="77f05bd3bd632509f1adc1d2d6e02093761f0385", name= "test-virtual-package_1.0.0-1.debian.tar.xz"}, - { hash="2bd0cfba1e1b8a2a454f5b152408311a2b4eceb9", name= "test-virtual-package_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/jammy/virtual/hello-world/pkg-builder.toml b/examples/jammy/virtual/hello-world/pkg-builder.toml deleted file mode 100644 index 81d402b7..00000000 --- a/examples/jammy/virtual/hello-world/pkg-builder.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package_fields] -spec_file = "test-virtual-package.sss" -package_name = "test-virtual-package" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -package_type="virtual" - -[build_env] -codename="jammy jellyfish" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" \ No newline at end of file diff --git a/examples/jammy/virtual/hello-world/src/debian/copyright b/examples/jammy/virtual/hello-world/src/debian/copyright deleted file mode 100644 index f5888d9f..00000000 --- a/examples/jammy/virtual/hello-world/src/debian/copyright +++ /dev/null @@ -1,11 +0,0 @@ -Files: * -Copyright: 2022 John Doe -License: GPL-3+ - -Files: debian/* -Copyright: 2022 John Doe -License: GPL-3+ - -License: GPL-3+ - The full text of the GPL version 3 is distributed in - /usr/share/common-licenses/GPL-3 on Debian systems. diff --git a/examples/jammy/virtual/hello-world/src/debian/source/lintian-overrides b/examples/jammy/virtual/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 901bc117..00000000 --- a/examples/jammy/virtual/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -test-virtual-package source: empty-upstream-sources diff --git a/examples/jammy/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides b/examples/jammy/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides deleted file mode 100644 index c915439c..00000000 --- a/examples/jammy/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides +++ /dev/null @@ -1,2 +0,0 @@ -test-virtual-package: initial-upload-closes-no-bugs -test-virtual-package: maintainer-script-ignores-errors [postrm] \ No newline at end of file diff --git a/examples/noble/c/hello-world/hello-world.changelog b/examples/noble/c/hello-world/hello-world-c.changelog similarity index 66% rename from examples/noble/c/hello-world/hello-world.changelog rename to examples/noble/c/hello-world/hello-world-c.changelog index f659e5c9..77fdc6f7 100644 --- a/examples/noble/c/hello-world/hello-world.changelog +++ b/examples/noble/c/hello-world/hello-world-c.changelog @@ -1,4 +1,4 @@ -hello-world (1.0.0-1) noble; urgency=medium +hello-world-c (1.0.0-1) noble; urgency=medium * Initial packaging diff --git a/examples/bookworm/git-package/nimbus/hello-world.sps b/examples/noble/c/hello-world/hello-world-c.sps similarity index 96% rename from examples/bookworm/git-package/nimbus/hello-world.sps rename to examples/noble/c/hello-world/hello-world-c.sps index 386cacbf..212af3eb 100644 --- a/examples/bookworm/git-package/nimbus/hello-world.sps +++ b/examples/noble/c/hello-world/hello-world-c.sps @@ -1,4 +1,4 @@ -name = "hello-world" +name = "hello-world-c" architecture = "any" summary = """Example Package This is a short description of the package. It should provide a brief summary diff --git a/examples/bookworm/git-package/nimbus/hello-world.sss b/examples/noble/c/hello-world/hello-world-c.sss similarity index 69% rename from examples/bookworm/git-package/nimbus/hello-world.sss rename to examples/noble/c/hello-world/hello-world-c.sss index 26b5eb7b..9d3c3c1a 100644 --- a/examples/bookworm/git-package/nimbus/hello-world.sss +++ b/examples/noble/c/hello-world/hello-world-c.sss @@ -1,7 +1,7 @@ -name = "hello-world" +name = "hello-world-c" maintainer = "John Doe " section = "net" variants = [] build_depends = [] -packages = ["hello-world"] +packages = ["hello-world-c"] skip_debug_symbols = true \ No newline at end of file diff --git a/examples/noble/c/hello-world/hello-world.sps b/examples/noble/c/hello-world/hello-world.sps deleted file mode 100644 index 386cacbf..00000000 --- a/examples/noble/c/hello-world/hello-world.sps +++ /dev/null @@ -1,21 +0,0 @@ -name = "hello-world" -architecture = "any" -summary = """Example Package -This is a short description of the package. It should provide a brief summary -of what the package does and its purpose. The short description should be -limited to a single line.""" -conflicts = [] -recommends = [] -provides = [] -suggests = [] -depends = [] -add_files = [] -add_manpages = [] -long_doc = """ -Example Package - This is a short description of the package. It should provide a brief summary - of what the package does and its purpose. The short description should be - limited to a single line. - Long Description: - Example description. If not provided, lintian will fail. -""" \ No newline at end of file diff --git a/examples/noble/c/hello-world/hello-world.sss b/examples/noble/c/hello-world/hello-world.sss deleted file mode 100644 index 26b5eb7b..00000000 --- a/examples/noble/c/hello-world/hello-world.sss +++ /dev/null @@ -1,7 +0,0 @@ -name = "hello-world" -maintainer = "John Doe " -section = "net" -variants = [] -build_depends = [] -packages = ["hello-world"] -skip_debug_symbols = true \ No newline at end of file diff --git a/examples/noble/c/hello-world/pkg-builder-verify.toml b/examples/noble/c/hello-world/pkg-builder-verify.toml deleted file mode 100644 index eec4d102..00000000 --- a/examples/noble/c/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,5 +0,0 @@ -[verify] -package_hash = [ - { name = "hello-world_1.0.0-1.dsc", hash = "f21ea2f31213c86b5ae1bb8e76870943857fe555" }, - { name = "hello-world_1.0.0-1_amd64.deb", hash = "2dab7f211ecb1e09c18ae580d44ec352ed4d1062" } -] \ No newline at end of file diff --git a/examples/noble/c/hello-world/pkg-builder.toml b/examples/noble/c/hello-world/pkg-builder.toml index 60ab9c7e..ea28513c 100644 --- a/examples/noble/c/hello-world/pkg-builder.toml +++ b/examples/noble/c/hello-world/pkg-builder.toml @@ -1,30 +1,27 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-c" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-c.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" +[source] +type = "tarball" +url = "hello-world-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" -[package_type.language_env] -language_env = "c" - -[build_env] -codename="noble numbat" +[build] +distribution = "noble numbat" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" \ No newline at end of file +workdir = "~/.pkg-builder/packages/noble" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "005f98c83cfc5f48c7e24d1dea07d4e4df916a8f217231896882b7d4968ea69d" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "004a6bd8c348f63e33d48aac5db16dc44adee319b715c57ff236df2ce2650ecd" }, +] diff --git a/examples/noble/c/hello-world/sbuild.conf b/examples/noble/c/hello-world/sbuild.conf new file mode 100644 index 00000000..b5a8c455 --- /dev/null +++ b/examples/noble/c/hello-world/sbuild.conf @@ -0,0 +1,27 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-c-1.0.0-1"; + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + ], +}; + +1; diff --git a/examples/noble/c/hello-world/src/debian/hello-world-c.lintian-overrides b/examples/noble/c/hello-world/src/debian/hello-world-c.lintian-overrides new file mode 100644 index 00000000..da55ad1e --- /dev/null +++ b/examples/noble/c/hello-world/src/debian/hello-world-c.lintian-overrides @@ -0,0 +1,6 @@ +# not a bug +hello-world-c: initial-upload-closes-no-bugs +# not a bug +hello-world-c: maintainer-script-ignores-errors [postrm] +# FIX this +hello-world-c: no-manual-page [usr/bin/hello_world] diff --git a/examples/noble/c/hello-world/src/debian/hello-world.lintian-overrides b/examples/noble/c/hello-world/src/debian/hello-world.lintian-overrides deleted file mode 100644 index 4872b60d..00000000 --- a/examples/noble/c/hello-world/src/debian/hello-world.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -# not a bug -hello-world: initial-upload-closes-no-bugs -# not a bug -hello-world: maintainer-script-ignores-errors [postrm] -# FIX this -hello-world: no-manual-page [usr/bin/hello_world] diff --git a/examples/noble/c/hello-world/src/debian/source/lintian-overrides b/examples/noble/c/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index 74263261..00000000 --- a/examples/noble/c/hello-world/src/debian/source/lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -hello-world source: no-newline-at-end debian/rules \ No newline at end of file diff --git a/examples/noble/dotnet-9/hello-world/pkg-builder-verify.toml b/examples/noble/dotnet-9/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 8c5c6907..00000000 --- a/examples/noble/dotnet-9/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="f289c6160485ed4b3a666ae24f225bdf8b7ff5f1", name= "hello-world-dotnet_1.0.0-1.dsc"}, - { hash="0ef2133c3ffe3239f70afcee13ce171a77ed7437", name= "hello-world-dotnet_1.0.0.orig.tar.gz"}, - { hash="592dd2d28fdd1bdff6de0af90b4a4cba660daebe", name= "hello-world-dotnet_1.0.0-1.debian.tar.xz"}, - { hash="106929f7970e1f6ce4b26dda668b7cba21e39bd6", name= "hello-world-dotnet_1.0.0-1_amd64.deb"}, -] diff --git a/examples/noble/dotnet-9/hello-world/pkg-builder.toml b/examples/noble/dotnet-9/hello-world/pkg-builder.toml index 3a7c13da..13e38717 100644 --- a/examples/noble/dotnet-9/hello-world/pkg-builder.toml +++ b/examples/noble/dotnet-9/hello-world/pkg-builder.toml @@ -1,21 +1,24 @@ -[package_fields] -spec_file = "hello-world-dotnet.sss" -package_name = "hello-world-dotnet" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-dotnet" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-dotnet.sss" -[package_type] -# virtual | git | default -package_type = "default" -tarball_url = "hello-world-dotnet-1.0.0.tar.gz" -tarball_hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" +[source] +type = "tarball" +url = "hello-world-dotnet-1.0.0.tar.gz" +hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" -[package_type.language_env] -language_env = "dotnet" -deps=["libbrotli1", "liblttng-ust1t64", "libunwind8"] -# see available list in apt-cache madison, which lists which versions you can install -dotnet_packages = [ +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "dotnet-backup" +deps = ["libbrotli1", "liblttng-ust1t64", "libunwind8"] +packages = [ { name = "dotnet-host-9.0_9.0.0-rtm+build1-0ubuntu1~24.04.1~ppa1_amd64", hash = "a4b6f4eedbef7523ad2c8927f2baf79a437aa664", url = "http://backup.eth-nodes.com/noble/20250107/dotnet-host-9.0_9.0.0-rtm%2Bbuild1-0ubuntu1~24.04.1~ppa1_amd64.deb" }, { name = "dotnet-hostfxr-9.0_9.0.0-rtm+build1-0ubuntu1~24.04.1~ppa1_amd64", hash = "7da909a17153494b0b391e8693f34063e25160f4", url = "http://backup.eth-nodes.com/noble/20250107/dotnet-hostfxr-9.0_9.0.0-rtm%2Bbuild1-0ubuntu1~24.04.1~ppa1_amd64.deb" }, { name = "dotnet-runtime-9.0_9.0.0-rtm+build1-0ubuntu1~24.04.1~ppa1_amd64", hash = "aa377e9742c43222b6db063f01b06a7f68bc400b", url = "http://backup.eth-nodes.com/noble/20250107/dotnet-runtime-9.0_9.0.0-rtm%2Bbuild1-0ubuntu1~24.04.1~ppa1_amd64.deb" }, @@ -27,19 +30,9 @@ dotnet_packages = [ { name = "netstandard-targeting-pack-2.1-9.0_9.0.101-0ubuntu1~24.04.1~ppa1_amd64", hash = "14b6d57f5f56e092d87744b61969e99761f95024", url = "http://backup.eth-nodes.com/noble/20250107/netstandard-targeting-pack-2.1-9.0_9.0.101-0ubuntu1~24.04.1~ppa1_amd64.deb" }, { name = "dotnet-sdk-9.0_9.0.101-0ubuntu1~24.04.1~ppa1_amd64", hash = "7ffd077e478049cce63ad14a3d1d21b30a1922d7", url = "http://backup.eth-nodes.com/noble/20250107/dotnet-sdk-9.0_9.0.101-0ubuntu1~24.04.1~ppa1_amd64.deb" }, ] -use_backup_version = true -[build_env] -codename = "noble numbat" -arch = "amd64" -pkg_builder_version = "0.3.1" -debcrafter_version = "8189263" -run_lintian = true -run_piuparts = true -run_autopkgtest = true -lintian_version = "2.116.3" -piuparts_version = "1.1.7" -autopkgtest_version = "5.20" -sbuild_version = "0.85.6" -# package directory -workdir = "~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/noble/dotnet-9/hello-world/src/debian/source/lintian-overrides b/examples/noble/dotnet-9/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/noble/dotnet/hello-world/pkg-builder-verify.toml b/examples/noble/dotnet/hello-world/pkg-builder-verify.toml deleted file mode 100644 index ed1268e5..00000000 --- a/examples/noble/dotnet/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="f289c6160485ed4b3a666ae24f225bdf8b7ff5f1", name= "hello-world-dotnet_1.0.0-1.dsc"}, - { hash="0ef2133c3ffe3239f70afcee13ce171a77ed7437", name= "hello-world-dotnet_1.0.0.orig.tar.gz"}, - { hash="592dd2d28fdd1bdff6de0af90b4a4cba660daebe", name= "hello-world-dotnet_1.0.0-1.debian.tar.xz"}, - { hash="d4cdccee15a580f9b79d42a01d0a845a4f7a7056", name= "hello-world-dotnet_1.0.0-1_amd64.deb"}, -] diff --git a/examples/noble/dotnet/hello-world/pkg-builder.toml b/examples/noble/dotnet/hello-world/pkg-builder.toml index 8d2d5627..232e9f30 100644 --- a/examples/noble/dotnet/hello-world/pkg-builder.toml +++ b/examples/noble/dotnet/hello-world/pkg-builder.toml @@ -1,20 +1,23 @@ -[package_fields] -spec_file = "hello-world-dotnet.sss" -package_name = "hello-world-dotnet" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-dotnet" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-dotnet.sss" -[package_type] -# virtual | git | default -package_type = "default" -tarball_url = "hello-world-dotnet-1.0.0.tar.gz" -tarball_hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" +[source] +type = "tarball" +url = "hello-world-dotnet-1.0.0.tar.gz" +hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" -[package_type.language_env] -language_env = "dotnet" -# see available list in apt-cache madison, which lists which versions you can install -dotnet_packages = [ +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "dotnet-backup" +packages = [ { name = "netstandard-targeting-pack-2.1-8.0_8.0.104-0ubuntu1_amd64", hash = "a6ae63e8976c79fe9ef531b986d8fb111e877503", url = "http://backup.eth-nodes.com/20240529-noble/netstandard-targeting-pack-2.1-8.0_8.0.104-0ubuntu1_amd64.deb" }, { name = "dotnet-apphost-pack-8.0_8.0.4-0ubuntu1_amd64", hash = "ece9f96b2cac32af01b7f9c146daada89bc6310f", url = "http://backup.eth-nodes.com/20240529-noble/dotnet-apphost-pack-8.0_8.0.4-0ubuntu1_amd64.deb" }, { name = "dotnet-targeting-pack-8.0_8.0.4-0ubuntu1_amd64", hash = "852d5128329fb83f32f61cc921a68494f6181370", url = "http://backup.eth-nodes.com/20240529-noble/dotnet-targeting-pack-8.0_8.0.4-0ubuntu1_amd64.deb" }, @@ -27,23 +30,13 @@ dotnet_packages = [ { name = "dotnet-runtime-8.0_8.0.4-0ubuntu1_amd64", hash = "4bb4c314fd3315f0cb872ba116908be299e7e429", url = "http://backup.eth-nodes.com/20240529-noble/dotnet-runtime-8.0_8.0.4-0ubuntu1_amd64.deb" }, { name = "aspnetcore-targeting-pack-8.0_8.0.4-0ubuntu1_amd64", hash = "76c84a5e08f12af30f6764ea773f2dd8c756a920", url = "http://backup.eth-nodes.com/20240529-noble/aspnetcore-targeting-pack-8.0_8.0.4-0ubuntu1_amd64.deb" }, { name = "aspnetcore-runtime-8.0_8.0.4-0ubuntu1_amd64", hash = "17f4b7c511729bb1424ec760cd035d91fe51cb79", url = "http://backup.eth-nodes.com/20240529-noble/aspnetcore-runtime-8.0_8.0.4-0ubuntu1_amd64.deb" }, - { name = "dotnet-templates-8.0_8.0.104-0ubuntu1_amd64", hash = "c1b234dcf4ac1db094600d5636590ff53d9225cd", url="http://backup.eth-nodes.com/20240529-noble/dotnet-templates-8.0_8.0.104-0ubuntu1_amd64.deb"}, + { name = "dotnet-templates-8.0_8.0.104-0ubuntu1_amd64", hash = "c1b234dcf4ac1db094600d5636590ff53d9225cd", url = "http://backup.eth-nodes.com/20240529-noble/dotnet-templates-8.0_8.0.104-0ubuntu1_amd64.deb" }, { name = "dotnet-sdk-8.0_8.0.104-0ubuntu1_amd64", hash = "d5bc66de113c1798283839006317182b44bce338", url = "http://backup.eth-nodes.com/20240529-noble/dotnet-sdk-8.0_8.0.104-0ubuntu1_amd64.deb" }, { name = "dotnet8_8.0.104-8.0.4-0ubuntu1_amd64", hash = "a2ada74cdc4a74a7f22aa48205cfc45999c94974", url = "http://backup.eth-nodes.com/20240529-noble/dotnet8_8.0.104-8.0.4-0ubuntu1_amd64.deb" }, ] -use_backup_version = true -[build_env] -codename = "noble numbat" -arch = "amd64" -pkg_builder_version = "0.3.1" -debcrafter_version = "8189263" -run_lintian = true -run_piuparts = true -run_autopkgtest = true -lintian_version = "2.116.3" -piuparts_version = "1.1.7" -autopkgtest_version = "5.20" -sbuild_version = "0.85.6" -# package directory -workdir = "~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/noble/dotnet/hello-world/src/debian/source/lintian-overrides b/examples/noble/dotnet/hello-world/src/debian/source/lintian-overrides deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/jammy/c/hello-world/hello-world.changelog b/examples/noble/git-package/nimbus/hello-world-git-nim.changelog similarity index 63% rename from examples/jammy/c/hello-world/hello-world.changelog rename to examples/noble/git-package/nimbus/hello-world-git-nim.changelog index f497698d..2b39af1c 100644 --- a/examples/jammy/c/hello-world/hello-world.changelog +++ b/examples/noble/git-package/nimbus/hello-world-git-nim.changelog @@ -1,4 +1,4 @@ -hello-world (1.0.0-1) jammy; urgency=medium +hello-world-git-nim (1.0.0-1) noble; urgency=medium * Initial packaging diff --git a/examples/noble/git-package/nimbus/hello-world-git-nim.sps b/examples/noble/git-package/nimbus/hello-world-git-nim.sps new file mode 100644 index 00000000..651f4875 --- /dev/null +++ b/examples/noble/git-package/nimbus/hello-world-git-nim.sps @@ -0,0 +1,21 @@ +name = "hello-world-git-nim" +architecture = "any" +summary = """Example Package +This is a short description of the package. It should provide a brief summary +of what the package does and its purpose. The short description should be +limited to a single line.""" +conflicts = [] +recommends = [] +provides = [] +suggests = [] +depends = [] +add_files = [] +add_manpages = [] +long_doc = """ +Example Package + This is a short description of the package. It should provide a brief summary + of what the package does and its purpose. The short description should be + limited to a single line. + Long Description: + Example description. If not provided, lintian will fail. +""" \ No newline at end of file diff --git a/examples/noble/git-package/nimbus/hello-world-git-nim.sss b/examples/noble/git-package/nimbus/hello-world-git-nim.sss new file mode 100644 index 00000000..1f88c804 --- /dev/null +++ b/examples/noble/git-package/nimbus/hello-world-git-nim.sss @@ -0,0 +1,7 @@ +name = "hello-world-git-nim" +maintainer = "John Doe " +section = "net" +variants = [] +build_depends = [] +packages = ["hello-world-git-nim"] +skip_debug_symbols = true \ No newline at end of file diff --git a/examples/noble/git-package/nimbus/hello-world.changelog b/examples/noble/git-package/nimbus/hello-world.changelog deleted file mode 100644 index f659e5c9..00000000 --- a/examples/noble/git-package/nimbus/hello-world.changelog +++ /dev/null @@ -1,5 +0,0 @@ -hello-world (1.0.0-1) noble; urgency=medium - - * Initial packaging - - -- John Doe Tue, 17 Oct 2023 13:19:27 +0700 diff --git a/examples/noble/git-package/nimbus/hello-world.sps b/examples/noble/git-package/nimbus/hello-world.sps deleted file mode 100644 index 386cacbf..00000000 --- a/examples/noble/git-package/nimbus/hello-world.sps +++ /dev/null @@ -1,21 +0,0 @@ -name = "hello-world" -architecture = "any" -summary = """Example Package -This is a short description of the package. It should provide a brief summary -of what the package does and its purpose. The short description should be -limited to a single line.""" -conflicts = [] -recommends = [] -provides = [] -suggests = [] -depends = [] -add_files = [] -add_manpages = [] -long_doc = """ -Example Package - This is a short description of the package. It should provide a brief summary - of what the package does and its purpose. The short description should be - limited to a single line. - Long Description: - Example description. If not provided, lintian will fail. -""" \ No newline at end of file diff --git a/examples/noble/git-package/nimbus/hello-world.sss b/examples/noble/git-package/nimbus/hello-world.sss deleted file mode 100644 index 26b5eb7b..00000000 --- a/examples/noble/git-package/nimbus/hello-world.sss +++ /dev/null @@ -1,7 +0,0 @@ -name = "hello-world" -maintainer = "John Doe " -section = "net" -variants = [] -build_depends = [] -packages = ["hello-world"] -skip_debug_symbols = true \ No newline at end of file diff --git a/examples/noble/git-package/nimbus/pkg-builder-verify.toml b/examples/noble/git-package/nimbus/pkg-builder-verify.toml deleted file mode 100644 index 9099f583..00000000 --- a/examples/noble/git-package/nimbus/pkg-builder-verify.toml +++ /dev/null @@ -1,9 +0,0 @@ -[verify] -package_hash=[ - {"name"= "hello-world_1.0.0-1.dsc", hash="8d554d62f710de2c7865df51a4fa67c708719e0807cf04aafd10669feb10e4b2"}, - {"name"= "hello-world_1.0.0-1_amd64.deb", hash="bac691148118516d1689857952ab52cd4e9baa15ceb0f334c6c20bc692b74476"}, -] - - - - diff --git a/examples/noble/git-package/nimbus/pkg-builder.toml b/examples/noble/git-package/nimbus/pkg-builder.toml index 3713ea40..00778478 100644 --- a/examples/noble/git-package/nimbus/pkg-builder.toml +++ b/examples/noble/git-package/nimbus/pkg-builder.toml @@ -1,17 +1,15 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-git-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-git-nim.sss" -[package_type] -# virtual | git | default -package_type="git" -git_url="https://github.com/status-im/nimbus-eth2.git" -git_tag="v24.3.0" +[source] +type = "git" +url = "https://github.com/status-im/nimbus-eth2.git" +tag = "v24.3.0" submodules = [ - # vendor/EIPs commit is different as it was forced pushed :( {commit = "72523ee3f865e09f8a6117c1b5e74cbb2df4f60e", path = "vendor/EIPs"}, {commit = "ab3ff9fad45fa7e20d749d0a03a7567225f5dd4a", path = "vendor/NimYAML"}, {commit = "ab581251bcda11e3cc120cc9e9ad1ad679340949", path = "vendor/eth2-networks"}, @@ -57,31 +55,22 @@ submodules = [ {commit = "3866a8ab98fc6e0e6d406b88800aed72163d5fd4", path = "vendor/nimbus-build-system"}, {commit = "ce9945b1b159d4c9b628f8c4cd2d262964692810", path = "vendor/nimbus-security-resources"}, {commit = "0c6ddab03a99805239b7875f71d2ca95fbed6f85", path = "vendor/nimcrypto"}, - {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"} + {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"}, ] - -[package_type.language_env] -language_env = "nim" -nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" - -[build_env] -codename="bookworm" +[build] +distribution = "bookworm" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "latest" -run_lintian=false -run_piuparts=false -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" - - +workdir = "~/.pkg-builder/packages/noble" +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" +nim_version = "2.0.2" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/jammy/git-package/nimbus/src/debian/hello-world.lintian-overrides b/examples/noble/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides similarity index 100% rename from examples/jammy/git-package/nimbus/src/debian/hello-world.lintian-overrides rename to examples/noble/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides diff --git a/examples/noble/go/hello-world/pkg-builder-verify.toml b/examples/noble/go/hello-world/pkg-builder-verify.toml deleted file mode 100644 index d5b99d19..00000000 --- a/examples/noble/go/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="f4537a41b132f6a20a9501aa9d34e1914f5c42ac", name= "hello-world-go_1.0.0-1.dsc"}, - { hash="e86b15349d902a2fabe356e386b034ed9e5a10c4", name= "hello-world-go_1.0.0.orig.tar.gz"}, - { hash="b9c86cf6fa3c4f4294dbae59d2cc1309fd1b4c9c", name= "hello-world-go_1.0.0-1.debian.tar.xz"}, - { hash="1c61a54d42deb2d80e0a20187263f80c4f662917", name= "hello-world-go_1.0.0-1_amd64.deb"}, -] diff --git a/examples/noble/go/hello-world/pkg-builder.toml b/examples/noble/go/hello-world/pkg-builder.toml index 6e40b3cf..78a7a228 100644 --- a/examples/noble/go/hello-world/pkg-builder.toml +++ b/examples/noble/go/hello-world/pkg-builder.toml @@ -1,33 +1,32 @@ -[package_fields] -spec_file = "hello-world-go.sss" -package_name = "hello-world-go" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-go" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-go.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-go-1.0.0.tar.gz" -tarball_hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" +[source] +type = "tarball" +url = "hello-world-go-1.0.0.tar.gz" +hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" -[package_type.language_env] -language_env = "go" -go_version = "1.22.2" -go_binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" -go_binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" - -[build_env] -codename="noble numbat" +[build] +distribution = "noble numbat" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-go_1.0.0-1.dsc", hash = "0aa148a575b4f01a165dadf16b056032c87804fabc53495185c805dc7de27983" }, + { name = "hello-world-go_1.0.0-1_amd64.deb", hash = "9a74c0213f5fd16553c990e8a60dce235e768f0725526223d4323e3e2e42710e" }, +] diff --git a/examples/noble/go/hello-world/sbuild.conf b/examples/noble/go/hello-world/sbuild.conf new file mode 100644 index 00000000..fe5aa73e --- /dev/null +++ b/examples/noble/go/hello-world/sbuild.conf @@ -0,0 +1,43 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: go | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-go-1.0.0-1"; + +# Runtime: Go +my $binary_url = 'https://go.dev/dl/go1.22.2.linux-amd64.tar.gz'; +my $binary_checksum = '5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/go.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/go.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm -f /tmp/go.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/local/go/bin/go /usr/bin/go', + 'chmod -R a+rwx /usr/local/go/pkg', + 'apt remove -y wget', + 'go version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/go/hello-world/src/debian/source/lintian-overrides b/examples/noble/go/hello-world/src/debian/source/lintian-overrides index fa6b7e30..1266bed7 100644 --- a/examples/noble/go/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/go/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-go source: debian-rules-ignores-make-clean-error [debian/rules:25] +hello-world-go source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/java-gradle/hello-world/pkg-builder-verify.toml b/examples/noble/java-gradle/hello-world/pkg-builder-verify.toml deleted file mode 100644 index b74837ed..00000000 --- a/examples/noble/java-gradle/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="20e1b0feaea0b63f1a9a22903badfefcfae24a43", name= "hello-world-java-gradle_1.0.0-1.dsc"}, - { hash="eef991395fabb27016cc1a2e37cbaa04fd869de8", name= "hello-world-java-gradle_1.0.0.orig.tar.gz"}, - { hash="97a27c6776bcea32326b055ef93f22fa666d56ae", name= "hello-world-java-gradle_1.0.0-1.debian.tar.xz"}, - { hash="fa1bc2cf145e1ddb50aa2d9f2cbf972841af030d", name= "hello-world-java-gradle_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/java-gradle/hello-world/pkg-builder.toml b/examples/noble/java-gradle/hello-world/pkg-builder.toml index 3507e7e9..fc066677 100644 --- a/examples/noble/java-gradle/hello-world/pkg-builder.toml +++ b/examples/noble/java-gradle/hello-world/pkg-builder.toml @@ -1,39 +1,36 @@ -[package_fields] -spec_file = "hello-world-java-gradle.sss" -package_name = "hello-world-java-gradle" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-java-gradle" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java-gradle.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-gradle-1.0.0.tar.gz" -tarball_hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" +[source] +type = "tarball" +url = "hello-world-java-gradle-1.0.0.tar.gz" +hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" - -[package_type.language_env.gradle] -gradle_version="8.7" -gradle_binary_url="https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" -gradle_binary_checksum="544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" - -[build_env] -codename="noble numbat" +[build] +distribution = "noble numbat" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory workdir = "~/.pkg-builder/packages" + +[runtime] +recipe = "java-gradle" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" +gradle_binary_url = "https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" +gradle_binary_checksum = "544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" +jdk_version = "17.0.10" +gradle_version = "8.7" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java-gradle_1.0.0-1.dsc", hash = "d3b802acfb68127255f796b32e77abd30a1e4476fe44d34ce3eb46a9a9fc8f17" }, + { name = "hello-world-java-gradle_1.0.0-1_amd64.deb", hash = "e36240cb8e216a78360887d2e4f9a76da6999cbd28d9c71cd281398641ce7f41" }, +] diff --git a/examples/noble/java-gradle/hello-world/sbuild.conf b/examples/noble/java-gradle/hello-world/sbuild.conf new file mode 100644 index 00000000..f11e3697 --- /dev/null +++ b/examples/noble/java-gradle/hello-world/sbuild.conf @@ -0,0 +1,55 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java-gradle | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/hello-world-java-gradle-1.0.0-1"; + +# Runtime: Java with Gradle +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '17.0.10'; +my $gradle_binary_url = 'https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip'; +my $gradle_binary_checksum = '544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d'; +my $gradle_version = '8.7'; + +my @runtime_commands = ( + 'apt install -y wget unzip', + # JDK + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + # Gradle + "wget -q -O /tmp/gradle.zip $gradle_binary_url", + "echo \"$gradle_binary_checksum /tmp/gradle.zip\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "cd /tmp && unzip -q gradle.zip && mv gradle-${gradle_version} /opt/lib/ && rm -f /tmp/gradle.zip /tmp/hash_file.txt", + "ln -s /opt/lib/gradle-${gradle_version}/bin/gradle /usr/bin/gradle", + 'apt remove -y wget unzip', + 'java -version', + 'gradle -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/java-gradle/hello-world/src/debian/source/lintian-overrides b/examples/noble/java-gradle/hello-world/src/debian/source/lintian-overrides index 8f48e87b..06318496 100644 --- a/examples/noble/java-gradle/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/java-gradle/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-java-gradle source: debian-rules-ignores-make-clean-error [debian/rules:19] \ No newline at end of file +hello-world-java-gradle source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/java/hello-world/pkg-builder-verify.toml b/examples/noble/java/hello-world/pkg-builder-verify.toml deleted file mode 100644 index e01a0fea..00000000 --- a/examples/noble/java/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="b22c549801ec2344b2cef49c4ea50d5712660d85", name= "hello-world-java_1.0.0-1.dsc"}, - { hash="8b017e7ea5f6653691e37d324faf40dc15b5cfd5", name= "hello-world-java_1.0.0.orig.tar.gz"}, - { hash="2fe5e69e72089ab41479995f079c7653bfbe0e62", name= "hello-world-java_1.0.0-1.debian.tar.xz"}, - { hash="ea16593dfd9767d32dbeb4774e05dc46b98f3f1e", name= "hello-world-java_1.0.0-1_amd64.deb"}, -] diff --git a/examples/noble/java/hello-world/pkg-builder.toml b/examples/noble/java/hello-world/pkg-builder.toml index 0a579113..5152f4cb 100644 --- a/examples/noble/java/hello-world/pkg-builder.toml +++ b/examples/noble/java/hello-world/pkg-builder.toml @@ -1,34 +1,32 @@ -[package_fields] -spec_file = "hello-world-java.sss" -package_name = "hello-world-java" -version_number = "1.0.0" -revision_number = "1" +[package] +name = "hello-world-java" +version = "1.0.0" +revision = "1" homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-java-1.0.0.tar.gz" -tarball_hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" +[source] +type = "tarball" +url = "hello-world-java-1.0.0.tar.gz" +hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" -[package_type.language_env] -language_env = "java" -is_oracle=true -jdk_version="17.0" -jdk_binary_url="https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" -jdk_binary_checksum="e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" - -[build_env] -codename="noble numbat" +[build] +distribution = "noble numbat" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir = "~/.pkg-builder/packages" \ No newline at end of file +workdir = "~/.pkg-builder/packages" + +[runtime] +recipe = "java" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java_1.0.0-1.dsc", hash = "52e0ffed8dcbd6925668dcb463effaf1deba107ae22684ddcdc25c30d2f115b0" }, + { name = "hello-world-java_1.0.0-1_amd64.deb", hash = "9c504720f446f7e6db72a670f65610d1b37283b95cd52935fafb340f55de2ddb" }, +] diff --git a/examples/noble/java/hello-world/sbuild.conf b/examples/noble/java/hello-world/sbuild.conf new file mode 100644 index 00000000..21bd3603 --- /dev/null +++ b/examples/noble/java/hello-world/sbuild.conf @@ -0,0 +1,45 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/hello-world-java-1.0.0-1"; + +# Runtime: Java (JDK only) +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '{{jdk_version}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + 'apt remove -y wget', + 'java -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/java/hello-world/src/debian/source/lintian-overrides b/examples/noble/java/hello-world/src/debian/source/lintian-overrides index be11627e..62a3373c 100644 --- a/examples/noble/java/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/java/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-java source: debian-rules-ignores-make-clean-error [debian/rules:17] \ No newline at end of file +hello-world-java source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/javascript/hello-world/pkg-builder-verify.toml b/examples/noble/javascript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 4ec9291e..00000000 --- a/examples/noble/javascript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="b412063aba24b8b69e547da9acbb35a731f5fea3", name= "hello-world-javascript_1.0.0-1.dsc"}, - { hash="161b7ac1a3dea76b1f98b10f0ae57ea601b9e642", name= "hello-world-javascript_1.0.0.orig.tar.gz"}, - { hash="72af03cb50436408638f4d78d60af701cc250463", name= "hello-world-javascript_1.0.0-1.debian.tar.xz"}, - { hash="688a54d15003bc9d849a898533cb142e3f64d7f3", name= "hello-world-javascript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/javascript/hello-world/pkg-builder.toml b/examples/noble/javascript/hello-world/pkg-builder.toml index 6cc8380e..c3a53646 100644 --- a/examples/noble/javascript/hello-world/pkg-builder.toml +++ b/examples/noble/javascript/hello-world/pkg-builder.toml @@ -1,34 +1,33 @@ -[package_fields] -spec_file = "hello-world-javascript.sss" -package_name = "hello-world-javascript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-javascript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-javascript.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-javascript-1.0.0.tar.gz" -tarball_hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" +[source] +type = "tarball" +url = "hello-world-javascript-1.0.0.tar.gz" +hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" yarn_version = "1.22.19" -[build_env] -codename="noble numbat" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-javascript_1.0.0-1.dsc", hash = "f42009d089b5ce899b5bdfff46bf6aead71589a54cfcb971cf960dd179ddf37b" }, + { name = "hello-world-javascript_1.0.0-1_amd64.deb", hash = "f8aa266a34dd99d4bf9c515bfc1bd342ac98946efd140a7232faf527a2c7df78" }, +] diff --git a/examples/noble/javascript/hello-world/sbuild.conf b/examples/noble/javascript/hello-world/sbuild.conf new file mode 100644 index 00000000..0b3983e2 --- /dev/null +++ b/examples/noble/javascript/hello-world/sbuild.conf @@ -0,0 +1,46 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-javascript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/javascript/hello-world/src/debian/source/lintian-overrides b/examples/noble/javascript/hello-world/src/debian/source/lintian-overrides index f6402c59..10f2ad8d 100644 --- a/examples/noble/javascript/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/javascript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-javascript source: debian-rules-ignores-make-clean-error [debian/rules:18] \ No newline at end of file +hello-world-javascript source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/nim/hello-world/pkg-builder-verify.toml b/examples/noble/nim/hello-world/pkg-builder-verify.toml deleted file mode 100644 index c47c129e..00000000 --- a/examples/noble/nim/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="40374c945fe1da6c4ef3e9c15407ada7a9db1f5e", name= "hello-world-nim_1.0.0-1.dsc"}, - { hash="a1b9eb72ce3b72094e6d815ff70208e7a88553cc", name= "hello-world-nim_1.0.0.orig.tar.gz"}, - { hash="6978b8fcb3d4bbf4736e21782d163c9479e77586", name= "hello-world-nim_1.0.0-1.debian.tar.xz"}, - { hash="18ee898764dc09fd93c363497f2b3caba308f893", name= "hello-world-nim_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/nim/hello-world/pkg-builder.toml b/examples/noble/nim/hello-world/pkg-builder.toml index 3157c521..3233a0aa 100644 --- a/examples/noble/nim/hello-world/pkg-builder.toml +++ b/examples/noble/nim/hello-world/pkg-builder.toml @@ -1,33 +1,33 @@ -[package_fields] -spec_file = "hello-world-nim.sss" -package_name = "hello-world-nim" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-nim.sss" +[source] +type = "tarball" +url = "hello-world-nim-1.0.0.tar.gz" +hash = "b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" -[package_type] -package_type="default" -tarball_url = "hello-world-nim-1.0.0.tar.gz" -tarball_hash="b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" -[package_type.language_env] -language_env = "nim" +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" -[build_env] -codename="noble numbat" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-nim_1.0.0-1.dsc", hash = "2383682bc8d608e920f39e6e7b0896118d4173e566accc46a2e781bd6e146490" }, + { name = "hello-world-nim_1.0.0-1_amd64.deb", hash = "29d6d3072a5d7fe6e0a21e4e1007409db1af89632132cb2a736d20619e7cd501" }, +] diff --git a/examples/noble/nim/hello-world/sbuild.conf b/examples/noble/nim/hello-world/sbuild.conf new file mode 100644 index 00000000..db29aa06 --- /dev/null +++ b/examples/noble/nim/hello-world/sbuild.conf @@ -0,0 +1,47 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: nim | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-nim-1.0.0-1"; + +# Runtime: Nim +# Note: binary_checksum includes the filename (e.g. "hash nim-VER-linux_x64.tar.xz") +my $binary_url = 'https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz'; +my $binary_checksum = '047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz'; +my $nim_version = '2.0.2'; + +my $nim_archive = "nim-${nim_version}-linux_x64.tar.xz"; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/$nim_archive $binary_url", + "cd /tmp && echo \"$binary_checksum\" > hash_file.txt && sha256sum -c hash_file.txt", + 'mkdir -p /opt/lib/nim', + "mkdir -p /tmp/nim-extract && tar xJf /tmp/$nim_archive -C /tmp/nim-extract --strip-components=1 && mv /tmp/nim-extract /opt/lib/nim/nim-${nim_version} && rm -f /tmp/$nim_archive /tmp/hash_file.txt", + "ln -s /opt/lib/nim/nim-${nim_version}/bin/nim /usr/bin/nim", + 'apt remove -y wget', + 'nim --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/nim/hello-world/src/debian/source/lintian-overrides b/examples/noble/nim/hello-world/src/debian/source/lintian-overrides index 41777733..69356191 100644 --- a/examples/noble/nim/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/nim/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-nim source: debian-rules-ignores-make-clean-error [debian/rules:20] +hello-world-nim source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/python/hello-world/hello-world-1.0.0.tar.gz b/examples/noble/python/hello-world/hello-world-1.0.0.tar.gz deleted file mode 100644 index d9a397fc..00000000 Binary files a/examples/noble/python/hello-world/hello-world-1.0.0.tar.gz and /dev/null differ diff --git a/examples/noble/python/hello-world/hello-world-python.changelog b/examples/noble/python/hello-world/hello-world-python.changelog deleted file mode 100644 index 99ef7f24..00000000 --- a/examples/noble/python/hello-world/hello-world-python.changelog +++ /dev/null @@ -1,5 +0,0 @@ -hello-world-python (1.0.0-1) noble; urgency=medium - - * Initial packaging - - -- John Doe Tue, 17 Oct 2023 13:19:27 +0700 diff --git a/examples/noble/python/hello-world/hello-world-python.sps b/examples/noble/python/hello-world/hello-world-python.sps deleted file mode 100644 index 34d88650..00000000 --- a/examples/noble/python/hello-world/hello-world-python.sps +++ /dev/null @@ -1,21 +0,0 @@ -name = "hello-world-python" -architecture = "any" -summary = """Example Package -This is a short description of the package. It should provide a brief summary -of what the package does and its purpose. The short description should be -limited to a single line.""" -conflicts = [] -recommends = [] -provides = [] -suggests = [] -depends = ["python3"] -add_files = ["dist/hello_world /usr/bin"] -add_manpages = [] -long_doc = """ -Example Package - This is a short description of the package. It should provide a brief summary - of what the package does and its purpose. The short description should be - limited to a single line. - Long Description: - Example description. If not provided, lintian will fail. -""" \ No newline at end of file diff --git a/examples/noble/python/hello-world/hello-world-python.sss b/examples/noble/python/hello-world/hello-world-python.sss deleted file mode 100644 index 20761af0..00000000 --- a/examples/noble/python/hello-world/hello-world-python.sss +++ /dev/null @@ -1,7 +0,0 @@ -name = "hello-world-python" -maintainer = "John Doe " -section = "net" -variants = [] -build_depends = ["python3-all", "python3-pip", "python3-venv", "python3-dev"] -packages = ["hello-world-python"] -skip_debug_symbols = true \ No newline at end of file diff --git a/examples/noble/python/hello-world/pkg-builder-verify.toml b/examples/noble/python/hello-world/pkg-builder-verify.toml deleted file mode 100644 index e5be562e..00000000 --- a/examples/noble/python/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="935dc9dc940996cd4ad029940e78c42d6f4cc9f3", name= "hello-world-python_1.0.0-1.dsc"}, - { hash="24cdab278a7c09be60caeca81b34b877c7f0b95e", name= "hello-world-python_1.0.0.orig.tar.gz"}, - { hash="2a98ecce25b41329aa16461e72ecca991d9b0a9e", name= "hello-world-python_1.0.0-1.debian.tar.xz"}, - { hash="3bf77a204ab09189ef30aa6c1a1b13c59e1142ff", name= "hello-world-python_1.0.0-1_amd64.deb"}, -] diff --git a/examples/noble/python/hello-world/pkg-builder.toml b/examples/noble/python/hello-world/pkg-builder.toml deleted file mode 100644 index e14d7ebc..00000000 --- a/examples/noble/python/hello-world/pkg-builder.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package_fields] -spec_file = "hello-world-python.sss" -package_name = "hello-world-python" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" - -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-1.0.0.tar.gz" -tarball_hash = "1915a59fabb5859cfd4c14eb2cde7064acf3b9ff6e9e78fa68ed06f4acc482b5" - -[package_type.language_env] -language_env = "python" - -[build_env] -codename="noble numbat" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.28" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" \ No newline at end of file diff --git a/examples/noble/python/hello-world/src/debian/copyright b/examples/noble/python/hello-world/src/debian/copyright deleted file mode 100644 index f5888d9f..00000000 --- a/examples/noble/python/hello-world/src/debian/copyright +++ /dev/null @@ -1,11 +0,0 @@ -Files: * -Copyright: 2022 John Doe -License: GPL-3+ - -Files: debian/* -Copyright: 2022 John Doe -License: GPL-3+ - -License: GPL-3+ - The full text of the GPL version 3 is distributed in - /usr/share/common-licenses/GPL-3 on Debian systems. diff --git a/examples/noble/python/hello-world/src/debian/hello-world-python.lintian-overrides b/examples/noble/python/hello-world/src/debian/hello-world-python.lintian-overrides deleted file mode 100644 index 28f28cb8..00000000 --- a/examples/noble/python/hello-world/src/debian/hello-world-python.lintian-overrides +++ /dev/null @@ -1,4 +0,0 @@ -hello-world-python: initial-upload-closes-no-bugs [usr/share/doc/hello-world-python/changelog.Debian.gz:1] -hello-world-python: maintainer-script-ignores-errors [postrm] -hello-world-python: hardening-no-pie [usr/bin/hello_world] -hello-world-python: no-manual-page [usr/bin/hello_world] \ No newline at end of file diff --git a/examples/noble/python/hello-world/src/debian/rules b/examples/noble/python/hello-world/src/debian/rules deleted file mode 100644 index 98e3886a..00000000 --- a/examples/noble/python/hello-world/src/debian/rules +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ - -override_dh_dwz: - -override_dh_auto_build: - python3 -m venv venv - . venv/bin/activate && pip install -r requirements.txt - . venv/bin/activate && pyinstaller --onefile main.py - mv dist/main dist/hello_world - chmod +x dist/hello_world diff --git a/examples/noble/python/hello-world/src/debian/tests/control b/examples/noble/python/hello-world/src/debian/tests/control deleted file mode 100644 index 29a6ac18..00000000 --- a/examples/noble/python/hello-world/src/debian/tests/control +++ /dev/null @@ -1,4 +0,0 @@ -# These tests are run by autopkgtests - -Tests: tests -Depends: @, shunit2 \ No newline at end of file diff --git a/examples/noble/python/hello-world/src/debian/tests/tests b/examples/noble/python/hello-world/src/debian/tests/tests deleted file mode 100644 index 664a5900..00000000 --- a/examples/noble/python/hello-world/src/debian/tests/tests +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env sh - -exec 2>&1 - -set -e - -test_binary_in_path(){ - output="$(which hello_world)" - assertEquals "/usr/bin/hello_world" "$output" -} - -test_invocation(){ - output="$(hello_world)" - assertEquals "Hello, World!" "$output" -} - -. shunit2 \ No newline at end of file diff --git a/examples/noble/rust/hello-world/pkg-builder-verify.toml b/examples/noble/rust/hello-world/pkg-builder-verify.toml deleted file mode 100644 index 58a54070..00000000 --- a/examples/noble/rust/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="3e4a25acb4add9d7dca4af1c213412bd47de33df", name= "hello-world-rust_1.0.0-1.dsc"}, - { hash="a9c7bea89015e52a5b4e24544873ec73a0c92af2", name= "hello-world-rust_1.0.0.orig.tar.gz"}, - { hash="e43e157fd21bf261645d334d8f3d553d924f1471", name= "hello-world-rust_1.0.0-1.debian.tar.xz"}, - { hash="234da303375c3747771aefc9572c6c7ae3a08b19", name= "hello-world-rust_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/rust/hello-world/pkg-builder.toml b/examples/noble/rust/hello-world/pkg-builder.toml index 820e8635..ab4c2fe9 100644 --- a/examples/noble/rust/hello-world/pkg-builder.toml +++ b/examples/noble/rust/hello-world/pkg-builder.toml @@ -1,22 +1,24 @@ -[package_fields] -spec_file = "hello-world-rust.sss" -package_name = "hello-world-rust" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-rust" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-rust.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-rust-1.0.0.tar.gz" -tarball_hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" +[source] +type = "tarball" +url = "hello-world-rust-1.0.0.tar.gz" +hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" -[package_type.language_env] -language_env = "rust" -rust_version="1.77.2" -rust_binary_url="https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" -rust_binary_gpg_asc=""" ------BEGIN PGP SIGNATURE----- +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "rust" +binary_url = "https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz" +binary_gpg_asc = """-----BEGIN PGP SIGNATURE----- wsFcBAABCgAQBQJmFa+iCRCFq5bm+hvl/gAAc4oP/12rJYjE54yHsCgcpf6Lg+jz h8HPP4uCET7gt7LZPBPaQPEllssvBE+OZPNXs2J/Bf9Dk+3Za2uEfSaEwRkuf2TV @@ -34,17 +36,13 @@ KGFMBQELjcFWLGcBVE45DRuVR8E3XYunjSdgLFXjfZfeGF3uiS6fNHGCH41ryqfj -----END PGP SIGNATURE----- """ -[build_env] -codename="noble numbat" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-rust_1.0.0-1.dsc", hash = "dd60e219d1dfa2a2dc7ac5c8c846633ce1afba1f13679394e30281cf704abcae" }, + { name = "hello-world-rust_1.0.0-1_amd64.deb", hash = "56cb23a3ce5a08f36117cac33cd1651416f26fc6ff393fb3a68321bba0b52c1e" }, +] diff --git a/examples/noble/rust/hello-world/sbuild.conf b/examples/noble/rust/hello-world/sbuild.conf new file mode 100644 index 00000000..a7325f2c --- /dev/null +++ b/examples/noble/rust/hello-world/sbuild.conf @@ -0,0 +1,62 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: rust | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-rust-1.0.0-1"; + +# Runtime: Rust (GPG-verified) +my $binary_url = 'https://static.rust-lang.org/dist/rust-1.77.2-x86_64-unknown-linux-gnu.tar.xz'; +my $binary_gpg_asc = '-----BEGIN PGP SIGNATURE----- + +wsFcBAABCgAQBQJmFa+iCRCFq5bm+hvl/gAAc4oP/12rJYjE54yHsCgcpf6Lg+jz +h8HPP4uCET7gt7LZPBPaQPEllssvBE+OZPNXs2J/Bf9Dk+3Za2uEfSaEwRkuf2TV +EjLRkbxxjAx6e5FczAV0Qdd9u8O2LimndsRPOpjvIJtU4+wXnlHpPQ0lydr0rJso +/K9wdxvA3NgmNBa0SAKtGBwuziMk5tR+7gFFebJikXqnBsGgdifszL41tKSl5VkK +FUyb6xn0tA+wGmCVNiCV8JeTacr7+upJhAcMEqYWH/AuhA2vgF21W5jDPeA3VfoJ +RgPYUkbTKSdmUd68sUS5pzixxnYa6LXMBewshTim/kbxlMHxrZ+YSoOjBSuMUA/9 +ZcvqR/fdVNLXI/2oFIT4VPNM1cYmR15xBI1G5AbfOzYWoPGU9OTu4hs11Y3DCTCz +E5obQCVAm4/H8gO3hTvDiJE0Rb2M0h1uV12LkCMymzuIBrhLkVhQeekDZadJmWq0 +XlT/N86YFd8P393xYE3fpKaGqZ0fBJfX4nLdZHdZeFrov6ADjf7NLsfY0S9AnRnK +SAytDb5EQMcBZXlNKnF+mLG9l0Y4JtijEsaiMaJgzVInTIUTtkW/GlgpAgzIBQ8m +KGFMBQELjcFWLGcBVE45DRuVR8E3XYunjSdgLFXjfZfeGF3uiS6fNHGCH41ryqfj +2jwoU0cewz4tgDucAWWC +=sCT4 +-----END PGP SIGNATURE----- +'; + +my @runtime_commands = ( + 'apt install -y wget gpg gpg-agent', + "wget -q -O /tmp/rust.tar.xz $binary_url", + "echo \"$binary_gpg_asc\" > /tmp/rust.tar.xz.asc", + 'wget -qO- https://keybase.io/rust/pgp_keys.asc | gpg --import', + 'gpg --verify /tmp/rust.tar.xz.asc /tmp/rust.tar.xz', + 'mkdir -p /tmp/rust-install && tar xJf /tmp/rust.tar.xz -C /tmp/rust-install --strip-components=1 && rm -f /tmp/rust.tar.xz /tmp/rust.tar.xz.asc', + '/bin/bash /tmp/rust-install/install.sh --components=rustc,cargo,rust-std-x86_64-unknown-linux-gnu', + 'rm -rf /tmp/rust-install', + 'apt remove -y wget gpg gpg-agent', + 'rustc --version', + 'cargo --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/rust/hello-world/src/debian/source/lintian-overrides b/examples/noble/rust/hello-world/src/debian/source/lintian-overrides index 071ddf8c..8167aafb 100644 --- a/examples/noble/rust/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/rust/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-rust source: debian-rules-ignores-make-clean-error [debian/rules:16] \ No newline at end of file +hello-world-rust source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/typescript/hello-world/pkg-builder-verify.toml b/examples/noble/typescript/hello-world/pkg-builder-verify.toml deleted file mode 100644 index da7a168d..00000000 --- a/examples/noble/typescript/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="c3af7529404453f930d4b94ebc38e1e2bd6ac40d", name= "hello-world-typescript_1.0.0-1.dsc"}, - { hash="72dded9c5b23987ca3808e61dd33d09a2632cb86", name= "hello-world-typescript_1.0.0.orig.tar.gz"}, - { hash="8d72558fcbc5665aabaccb45b992a7ea134372bd", name= "hello-world-typescript_1.0.0-1.debian.tar.xz"}, - { hash="a8fac0be289043622252ac3f79dad87fd3deda19", name= "hello-world-typescript_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/typescript/hello-world/pkg-builder.toml b/examples/noble/typescript/hello-world/pkg-builder.toml index 78dd60ab..78342ae7 100644 --- a/examples/noble/typescript/hello-world/pkg-builder.toml +++ b/examples/noble/typescript/hello-world/pkg-builder.toml @@ -1,34 +1,33 @@ -[package_fields] -spec_file = "hello-world-typescript.sss" -package_name = "hello-world-typescript" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-typescript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-typescript.sss" -[package_type] -# virtual | git | default -package_type="default" -tarball_url = "hello-world-typescript-1.0.0.tar.gz" -tarball_hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" +[source] +type = "tarball" +url = "hello-world-typescript-1.0.0.tar.gz" +hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" -[package_type.language_env] -language_env = "javascript" -node_version = "20.12.2" -node_binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" -node_binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +[build] +distribution = "noble numbat" +arch = "amd64" +workdir = "~/.pkg-builder/packages/noble" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" yarn_version = "1.22.19" -[build_env] -codename="noble numbat" -arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=true -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-typescript_1.0.0-1.dsc", hash = "4afa9d6a6ea95d7baad3d7f4ea8bf251d7f9b2ff01e13a0b44867a63203fc815" }, + { name = "hello-world-typescript_1.0.0-1_amd64.deb", hash = "d6666c47e0a3f1b9198cbba1f234ec5fa305da9bc69d9180bac201d1e13240ca" }, +] diff --git a/examples/noble/typescript/hello-world/sbuild.conf b/examples/noble/typescript/hello-world/sbuild.conf new file mode 100644 index 00000000..846d46d9 --- /dev/null +++ b/examples/noble/typescript/hello-world/sbuild.conf @@ -0,0 +1,46 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/hello-world-typescript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + @runtime_commands, + ], +}; + +1; diff --git a/examples/noble/typescript/hello-world/src/debian/source/lintian-overrides b/examples/noble/typescript/hello-world/src/debian/source/lintian-overrides index 616c696a..4209707c 100644 --- a/examples/noble/typescript/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/typescript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-typescript source: debian-rules-ignores-make-clean-error [debian/rules:20] +hello-world-typescript source: debian-rules-ignores-make-clean-error diff --git a/examples/noble/virtual/hello-world/pkg-builder-verify.toml b/examples/noble/virtual/hello-world/pkg-builder-verify.toml deleted file mode 100644 index e2939a34..00000000 --- a/examples/noble/virtual/hello-world/pkg-builder-verify.toml +++ /dev/null @@ -1,7 +0,0 @@ -[verify] -package_hash=[ - { hash="4d1af802d1df0fc59f23137c5ceb02b9d9c7a25d", name= "test-virtual-package_1.0.0-1.dsc"}, - { hash="b35f46d5fb424aee57b5d666e61b2eff83543aad", name= "test-virtual-package_1.0.0.orig.tar.gz"}, - { hash="d72a2a5752372d6c8ceee4a59754f5d35048a8c3", name= "test-virtual-package_1.0.0-1.debian.tar.xz"}, - { hash="b067249705ed091bffc42a2f5291445c6140a979", name= "test-virtual-package_1.0.0-1_amd64.deb"}, -] \ No newline at end of file diff --git a/examples/noble/virtual/hello-world/pkg-builder.toml b/examples/noble/virtual/hello-world/pkg-builder.toml index e0b0e3eb..c8fc0621 100644 --- a/examples/noble/virtual/hello-world/pkg-builder.toml +++ b/examples/noble/virtual/hello-world/pkg-builder.toml @@ -1,24 +1,25 @@ -[package_fields] -spec_file = "test-virtual-package.sss" -package_name = "test-virtual-package" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "test-virtual-package" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "test-virtual-package.sss" -[package_type] -package_type="virtual" +[source] +type = "virtual" -[build_env] -codename="noble numbat" +[build] +distribution = "noble numbat" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "8189263" -run_lintian=true -run_piuparts=true -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/noble" \ No newline at end of file +workdir = "~/.pkg-builder/packages/noble" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "test-virtual-package_1.0.0-1.dsc", hash = "8ca174829ea2e72a650007cfcfe9fb07cd20cc8fdfcbaac2a58b198f78632acd" }, + { name = "test-virtual-package_1.0.0-1_amd64.deb", hash = "2c519f82ac82c53790e7aa6bea365864aefc28d4e33cadd374b41cfa98fc1878" }, +] diff --git a/examples/noble/virtual/hello-world/sbuild.conf b/examples/noble/virtual/hello-world/sbuild.conf new file mode 100644 index 00000000..004afc13 --- /dev/null +++ b/examples/noble/virtual/hello-world/sbuild.conf @@ -0,0 +1,27 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: noble + +$distribution = 'noble'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/noble/test-virtual-package-1.0.0-1"; + +$external_commands = { + 'chroot-setup-commands' => [ + 'apt install -y software-properties-common', + 'add-apt-repository universe', + 'add-apt-repository restricted', + 'add-apt-repository multiverse', + 'apt update', + ], +}; + +1; diff --git a/examples/noble/virtual/hello-world/src/debian/source/lintian-overrides b/examples/noble/virtual/hello-world/src/debian/source/lintian-overrides index d6f1eb13..37776fb6 100644 --- a/examples/noble/virtual/hello-world/src/debian/source/lintian-overrides +++ b/examples/noble/virtual/hello-world/src/debian/source/lintian-overrides @@ -1 +1,2 @@ -test-virtual-package source: empty-upstream-sources \ No newline at end of file +# Not a bug, this is a virtual package to serve as umbrella installation for others package deps +test-virtual-package source: empty-upstream-sources diff --git a/examples/jammy/c/hello-world/hello-world-1.0.0.tar.gz b/examples/trixie/c/hello-world/hello-world-1.0.0.tar.gz similarity index 100% rename from examples/jammy/c/hello-world/hello-world-1.0.0.tar.gz rename to examples/trixie/c/hello-world/hello-world-1.0.0.tar.gz diff --git a/examples/bookworm/c/hello-world/hello-world.changelog b/examples/trixie/c/hello-world/hello-world-c.changelog similarity index 66% rename from examples/bookworm/c/hello-world/hello-world.changelog rename to examples/trixie/c/hello-world/hello-world-c.changelog index c23cbe39..3629bd1f 100644 --- a/examples/bookworm/c/hello-world/hello-world.changelog +++ b/examples/trixie/c/hello-world/hello-world-c.changelog @@ -1,4 +1,4 @@ -hello-world (1.0.0-1) bookworm; urgency=medium +hello-world-c (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/git-package/nimbus/hello-world.sps b/examples/trixie/c/hello-world/hello-world-c.sps similarity index 96% rename from examples/jammy/git-package/nimbus/hello-world.sps rename to examples/trixie/c/hello-world/hello-world-c.sps index 386cacbf..212af3eb 100644 --- a/examples/jammy/git-package/nimbus/hello-world.sps +++ b/examples/trixie/c/hello-world/hello-world-c.sps @@ -1,4 +1,4 @@ -name = "hello-world" +name = "hello-world-c" architecture = "any" summary = """Example Package This is a short description of the package. It should provide a brief summary diff --git a/examples/jammy/git-package/nimbus/hello-world.sss b/examples/trixie/c/hello-world/hello-world-c.sss similarity index 69% rename from examples/jammy/git-package/nimbus/hello-world.sss rename to examples/trixie/c/hello-world/hello-world-c.sss index 26b5eb7b..9d3c3c1a 100644 --- a/examples/jammy/git-package/nimbus/hello-world.sss +++ b/examples/trixie/c/hello-world/hello-world-c.sss @@ -1,7 +1,7 @@ -name = "hello-world" +name = "hello-world-c" maintainer = "John Doe " section = "net" variants = [] build_depends = [] -packages = ["hello-world"] +packages = ["hello-world-c"] skip_debug_symbols = true \ No newline at end of file diff --git a/examples/trixie/c/hello-world/pkg-builder.toml b/examples/trixie/c/hello-world/pkg-builder.toml new file mode 100644 index 00000000..23558668 --- /dev/null +++ b/examples/trixie/c/hello-world/pkg-builder.toml @@ -0,0 +1,27 @@ +[package] +name = "hello-world-c" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-c.sss" + +[source] +type = "tarball" +url = "hello-world-1.0.0.tar.gz" +hash = "c93bdd829eca65af1e303d4a0b31cde0c3d3c2003fa1ca985393c412264b42c3b30c7893eb1d49ea654ca4f68269c30b3cca3db66d6b112f2be14f54c3d0edff" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-c_1.0.0-1.dsc", hash = "d07172b2ebb70a937b91ae45bbfc68e9f6e78fd8960828fac491369ba041ec0c" }, + { name = "hello-world-c_1.0.0-1_amd64.deb", hash = "5c86c412e700ac287ec2129bd855c036d9654a364a86d9c763f2cb60196c6a0a" }, +] diff --git a/examples/trixie/c/hello-world/sbuild.conf b/examples/trixie/c/hello-world/sbuild.conf new file mode 100644 index 00000000..4d134f6c --- /dev/null +++ b/examples/trixie/c/hello-world/sbuild.conf @@ -0,0 +1,18 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-c-1.0.0-1"; + + +1; diff --git a/examples/bookworm/python/hello-world/src/debian/copyright b/examples/trixie/c/hello-world/src/debian/copyright similarity index 100% rename from examples/bookworm/python/hello-world/src/debian/copyright rename to examples/trixie/c/hello-world/src/debian/copyright diff --git a/examples/trixie/c/hello-world/src/debian/hello-world-c.lintian-overrides b/examples/trixie/c/hello-world/src/debian/hello-world-c.lintian-overrides new file mode 100644 index 00000000..19a57a51 --- /dev/null +++ b/examples/trixie/c/hello-world/src/debian/hello-world-c.lintian-overrides @@ -0,0 +1,6 @@ +# not a bug +hello-world-c: initial-upload-closes-no-bugs [usr/share/doc/hello-world-c/changelog.Debian.gz:1] +# not a bug +hello-world-c: maintainer-script-ignores-errors [postrm] +# FIX this +hello-world-c: no-manual-page [usr/bin/hello_world] \ No newline at end of file diff --git a/examples/jammy/c/hello-world/src/debian/rules b/examples/trixie/c/hello-world/src/debian/rules similarity index 80% rename from examples/jammy/c/hello-world/src/debian/rules rename to examples/trixie/c/hello-world/src/debian/rules index 154ab1e3..87a7449b 100644 --- a/examples/jammy/c/hello-world/src/debian/rules +++ b/examples/trixie/c/hello-world/src/debian/rules @@ -9,6 +9,3 @@ override_dh_auto_install: # This relies on make install script # if there is no install script, you have define your own rules dh_auto_install -- prefix=/usr - -override_dh_strip: - dh_strip --no-automatic-dbgsym \ No newline at end of file diff --git a/examples/bookworm/python/hello-world/src/debian/tests/control b/examples/trixie/c/hello-world/src/debian/tests/control similarity index 100% rename from examples/bookworm/python/hello-world/src/debian/tests/control rename to examples/trixie/c/hello-world/src/debian/tests/control diff --git a/examples/bookworm/python/hello-world/src/debian/tests/tests b/examples/trixie/c/hello-world/src/debian/tests/tests similarity index 100% rename from examples/bookworm/python/hello-world/src/debian/tests/tests rename to examples/trixie/c/hello-world/src/debian/tests/tests diff --git a/examples/jammy/dotnet/hello-world/hello-world-dotnet-1.0.0.tar.gz b/examples/trixie/dotnet/hello-world/hello-world-dotnet-1.0.0.tar.gz similarity index 100% rename from examples/jammy/dotnet/hello-world/hello-world-dotnet-1.0.0.tar.gz rename to examples/trixie/dotnet/hello-world/hello-world-dotnet-1.0.0.tar.gz diff --git a/examples/jammy/dotnet/hello-world/hello-world-dotnet.changelog b/examples/trixie/dotnet/hello-world/hello-world-dotnet.changelog similarity index 63% rename from examples/jammy/dotnet/hello-world/hello-world-dotnet.changelog rename to examples/trixie/dotnet/hello-world/hello-world-dotnet.changelog index 86ea091c..8adc099c 100644 --- a/examples/jammy/dotnet/hello-world/hello-world-dotnet.changelog +++ b/examples/trixie/dotnet/hello-world/hello-world-dotnet.changelog @@ -1,4 +1,4 @@ -hello-world-dotnet (1.0.0-1) jammy; urgency=medium +hello-world-dotnet (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/dotnet/hello-world/hello-world-dotnet.sps b/examples/trixie/dotnet/hello-world/hello-world-dotnet.sps similarity index 100% rename from examples/jammy/dotnet/hello-world/hello-world-dotnet.sps rename to examples/trixie/dotnet/hello-world/hello-world-dotnet.sps diff --git a/examples/jammy/dotnet/hello-world/hello-world-dotnet.sss b/examples/trixie/dotnet/hello-world/hello-world-dotnet.sss similarity index 100% rename from examples/jammy/dotnet/hello-world/hello-world-dotnet.sss rename to examples/trixie/dotnet/hello-world/hello-world-dotnet.sss diff --git a/examples/trixie/dotnet/hello-world/pkg-builder.toml b/examples/trixie/dotnet/hello-world/pkg-builder.toml new file mode 100644 index 00000000..33e77ff2 --- /dev/null +++ b/examples/trixie/dotnet/hello-world/pkg-builder.toml @@ -0,0 +1,37 @@ +[package] +name = "hello-world-dotnet" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-dotnet.sss" + +[source] +type = "tarball" +url = "hello-world-dotnet-1.0.0.tar.gz" +hash = "f263892f5ed6cbcd82f31d60058eed359686d7e745c3da97fea917ee2f44867c4db9bd374f224e89e6efc7ffad4eadb244eefe7c95d25983f8a5a4086dadb78d" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "dotnet-backup" +packages = [ + { name = "netstandard-targeting-pack-2.1_2.1.0-1_amd64", hash = "c849f17d5e8cdce4b068e2897939be7de4b839d3", url = "http://backup.eth-nodes.com/20240529/netstandard-targeting-pack-2.1_2.1.0-1_amd64.deb" }, + { name = "dotnet-apphost-pack-8.0_8.0.5-1_amd64", hash = "18b0d4bed3b62495564c18a6d1c30181c33831b4", url = "http://backup.eth-nodes.com/20240529/dotnet-apphost-pack-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-targeting-pack-8.0_8.0.5-1_amd64", hash = "2727152580762a636e62f9c490c19e18339401a9", url = "http://backup.eth-nodes.com/20240529/dotnet-targeting-pack-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-runtime-deps-8.0_8.0.5-1_amd64", hash = "1f7f67a6fef920983ab2243c1c660d08e228cedf", url = "http://backup.eth-nodes.com/20240529/dotnet-runtime-deps-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-host_8.0.5-1_amd64", hash = "87414e005e39785e1ba32ce8cca97878ca4c6828", url = "http://backup.eth-nodes.com/20240529/dotnet-host_8.0.5-1_amd64.deb" }, + { name = "dotnet-hostfxr-8.0_8.0.5-1_amd64", hash = "e1ec0e6b838dabfb5b47ae1b15706026996d6a7c", url = "http://backup.eth-nodes.com/20240529/dotnet-hostfxr-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-runtime-8.0_8.0.5-1_amd64", hash = "8d2443146631a861ade47a184a5b44446c6b636d", url = "http://backup.eth-nodes.com/20240529/dotnet-runtime-8.0_8.0.5-1_amd64.deb" }, + { name = "aspnetcore-targeting-pack-8.0_8.0.5-1_amd64", hash = "4b6bcf15e50db2d177e6e0298a72eeae7c43d2a3", url = "http://backup.eth-nodes.com/20240529/aspnetcore-targeting-pack-8.0_8.0.5-1_amd64.deb" }, + { name = "aspnetcore-runtime-8.0_8.0.5-1_amd64", hash = "7676b5b02bbc37393089418e8a03320b10e914fd", url = "http://backup.eth-nodes.com/20240529/aspnetcore-runtime-8.0_8.0.5-1_amd64.deb" }, + { name = "dotnet-sdk-8.0_8.0.204-1_amd64", hash = "a94237cb852aae05b67a5c8428a6c4f9cfb4beaa", url = "http://backup.eth-nodes.com/20240529/dotnet-sdk-8.0_8.0.204-1_amd64.deb" }, +] + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/jammy/c/hello-world/src/debian/copyright b/examples/trixie/dotnet/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/c/hello-world/src/debian/copyright rename to examples/trixie/dotnet/hello-world/src/debian/copyright diff --git a/examples/trixie/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides b/examples/trixie/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides new file mode 100644 index 00000000..c562d45f --- /dev/null +++ b/examples/trixie/dotnet/hello-world/src/debian/hello-world-dotnet.lintian-overrides @@ -0,0 +1,5 @@ +# if you don't upload to debian this is not a bug +hello-world-dotnet: initial-upload-closes-no-bugs [usr/share/doc/hello-world-dotnet/changelog.Debian.gz:1] +hello-world-dotnet: maintainer-script-ignores-errors [postrm] +hello-world-dotnet: no-manual-page [usr/bin/hello-world] + diff --git a/examples/jammy/dotnet/hello-world/src/debian/rules b/examples/trixie/dotnet/hello-world/src/debian/rules similarity index 90% rename from examples/jammy/dotnet/hello-world/src/debian/rules rename to examples/trixie/dotnet/hello-world/src/debian/rules index 448e7e9a..5d8c06f5 100644 --- a/examples/jammy/dotnet/hello-world/src/debian/rules +++ b/examples/trixie/dotnet/hello-world/src/debian/rules @@ -19,6 +19,6 @@ override_dh_auto_install: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed #do not delete obj folder #make -j1 clean diff --git a/examples/jammy/dotnet/hello-world/src/debian/tests/control b/examples/trixie/dotnet/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/dotnet/hello-world/src/debian/tests/control rename to examples/trixie/dotnet/hello-world/src/debian/tests/control diff --git a/examples/trixie/dotnet/hello-world/src/debian/tests/tests b/examples/trixie/dotnet/hello-world/src/debian/tests/tests new file mode 100644 index 00000000..261b53e1 --- /dev/null +++ b/examples/trixie/dotnet/hello-world/src/debian/tests/tests @@ -0,0 +1,17 @@ +#!/usr/bin/env sh + +exec 2>&1 + +set -e + +test_binary_in_path(){ + output="$(which hello-world)" + assertEquals "/usr/bin/hello-world" "$output" +} + +test_invocation_without_dotnet(){ + output="$(hello-world 2>&1 || true)" + assertContains "You must install .NET to run this application." "$output" +} + +. shunit2 \ No newline at end of file diff --git a/examples/jammy/dotnet/hello-world/src/debian/tests/tests-with-dotnet b/examples/trixie/dotnet/hello-world/src/debian/tests/tests-with-dotnet similarity index 83% rename from examples/jammy/dotnet/hello-world/src/debian/tests/tests-with-dotnet rename to examples/trixie/dotnet/hello-world/src/debian/tests/tests-with-dotnet index 8835cf5c..fa535d68 100644 --- a/examples/jammy/dotnet/hello-world/src/debian/tests/tests-with-dotnet +++ b/examples/trixie/dotnet/hello-world/src/debian/tests/tests-with-dotnet @@ -11,7 +11,7 @@ test_binary_in_path(){ test_invocation_with_dotnet(){ output="$(hello-world)" - assertEquals "Hello, World!" "$output" + assertContains "Hello, World!" "$output" } . shunit2 \ No newline at end of file diff --git a/examples/trixie/git-package/nimbus/hello-world-git-nim.changelog b/examples/trixie/git-package/nimbus/hello-world-git-nim.changelog new file mode 100644 index 00000000..0a41c52b --- /dev/null +++ b/examples/trixie/git-package/nimbus/hello-world-git-nim.changelog @@ -0,0 +1,5 @@ +hello-world-git-nim (1.0.0-1) trixie; urgency=medium + + * Initial packaging + + -- John Doe Tue, 17 Oct 2023 13:19:27 +0700 diff --git a/examples/trixie/git-package/nimbus/hello-world-git-nim.sps b/examples/trixie/git-package/nimbus/hello-world-git-nim.sps new file mode 100644 index 00000000..651f4875 --- /dev/null +++ b/examples/trixie/git-package/nimbus/hello-world-git-nim.sps @@ -0,0 +1,21 @@ +name = "hello-world-git-nim" +architecture = "any" +summary = """Example Package +This is a short description of the package. It should provide a brief summary +of what the package does and its purpose. The short description should be +limited to a single line.""" +conflicts = [] +recommends = [] +provides = [] +suggests = [] +depends = [] +add_files = [] +add_manpages = [] +long_doc = """ +Example Package + This is a short description of the package. It should provide a brief summary + of what the package does and its purpose. The short description should be + limited to a single line. + Long Description: + Example description. If not provided, lintian will fail. +""" \ No newline at end of file diff --git a/examples/trixie/git-package/nimbus/hello-world-git-nim.sss b/examples/trixie/git-package/nimbus/hello-world-git-nim.sss new file mode 100644 index 00000000..1f88c804 --- /dev/null +++ b/examples/trixie/git-package/nimbus/hello-world-git-nim.sss @@ -0,0 +1,7 @@ +name = "hello-world-git-nim" +maintainer = "John Doe " +section = "net" +variants = [] +build_depends = [] +packages = ["hello-world-git-nim"] +skip_debug_symbols = true \ No newline at end of file diff --git a/examples/jammy/git-package/nimbus/pkg-builder.toml b/examples/trixie/git-package/nimbus/pkg-builder.toml similarity index 81% rename from examples/jammy/git-package/nimbus/pkg-builder.toml rename to examples/trixie/git-package/nimbus/pkg-builder.toml index cf65c5c3..04327eef 100644 --- a/examples/jammy/git-package/nimbus/pkg-builder.toml +++ b/examples/trixie/git-package/nimbus/pkg-builder.toml @@ -1,17 +1,15 @@ -[package_fields] -spec_file = "hello-world.sss" -package_name = "hello-world" -version_number = "1.0.0" -revision_number = "1" -homepage="https://github.com/eth-pkg/pkg-builder#examples" +[package] +name = "hello-world-git-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-git-nim.sss" -[package_type] -# virtual | git | default -package_type="git" -git_url="https://github.com/status-im/nimbus-eth2.git" -git_tag="v24.3.0" +[source] +type = "git" +url = "https://github.com/status-im/nimbus-eth2.git" +tag = "v24.3.0" submodules = [ - # vendor/EIPs commit is different as it was forced pushed :( {commit = "72523ee3f865e09f8a6117c1b5e74cbb2df4f60e", path = "vendor/EIPs"}, {commit = "ab3ff9fad45fa7e20d749d0a03a7567225f5dd4a", path = "vendor/NimYAML"}, {commit = "ab581251bcda11e3cc120cc9e9ad1ad679340949", path = "vendor/eth2-networks"}, @@ -57,31 +55,22 @@ submodules = [ {commit = "3866a8ab98fc6e0e6d406b88800aed72163d5fd4", path = "vendor/nimbus-build-system"}, {commit = "ce9945b1b159d4c9b628f8c4cd2d262964692810", path = "vendor/nimbus-security-resources"}, {commit = "0c6ddab03a99805239b7875f71d2ca95fbed6f85", path = "vendor/nimcrypto"}, - {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"} + {commit = "ff09a161f61959285c64b355d452cd25eae094bd", path = "vendor/sepolia"}, ] - -[package_type.language_env] -language_env = "nim" -nim_version = "2.0.2" -nim_binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" -nim_version_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" - -[build_env] -codename="bookworm" +[build] +distribution = "trixie" arch = "amd64" -pkg_builder_version="0.3.1" -debcrafter_version = "latest" -run_lintian=false -run_piuparts=false -run_autopkgtest=false -lintian_version="2.116.3" -piuparts_version="1.1.7" -autopkgtest_version="5.20" -sbuild_version="0.85.6" -# package directory -workdir="~/.pkg-builder/packages/jammy" - - +workdir = "~/.pkg-builder/packages/trixie" +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" +nim_version = "2.0.2" +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" +# [verify] hashes not yet populated — run build + verify to generate diff --git a/examples/jammy/dotnet/hello-world/src/debian/copyright b/examples/trixie/git-package/nimbus/src/debian/copyright similarity index 100% rename from examples/jammy/dotnet/hello-world/src/debian/copyright rename to examples/trixie/git-package/nimbus/src/debian/copyright diff --git a/examples/noble/git-package/nimbus/src/debian/hello-world.lintian-overrides b/examples/trixie/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides similarity index 100% rename from examples/noble/git-package/nimbus/src/debian/hello-world.lintian-overrides rename to examples/trixie/git-package/nimbus/src/debian/hello-world-git-nim.lintian-overrides diff --git a/examples/jammy/git-package/nimbus/src/debian/rules b/examples/trixie/git-package/nimbus/src/debian/rules similarity index 81% rename from examples/jammy/git-package/nimbus/src/debian/rules rename to examples/trixie/git-package/nimbus/src/debian/rules index 705bbe56..721f366a 100644 --- a/examples/jammy/git-package/nimbus/src/debian/rules +++ b/examples/trixie/git-package/nimbus/src/debian/rules @@ -10,5 +10,5 @@ override_dh_auto_install: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/jammy/go/hello-world/hello-world-go-1.0.0.tar.gz b/examples/trixie/go/hello-world/hello-world-go-1.0.0.tar.gz similarity index 100% rename from examples/jammy/go/hello-world/hello-world-go-1.0.0.tar.gz rename to examples/trixie/go/hello-world/hello-world-go-1.0.0.tar.gz diff --git a/examples/jammy/go/hello-world/hello-world-go.changelog b/examples/trixie/go/hello-world/hello-world-go.changelog similarity index 65% rename from examples/jammy/go/hello-world/hello-world-go.changelog rename to examples/trixie/go/hello-world/hello-world-go.changelog index ed3ddce2..94b59d48 100644 --- a/examples/jammy/go/hello-world/hello-world-go.changelog +++ b/examples/trixie/go/hello-world/hello-world-go.changelog @@ -1,4 +1,4 @@ -hello-world-go (1.0.0-1) jammy; urgency=medium +hello-world-go (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/go/hello-world/hello-world-go.sps b/examples/trixie/go/hello-world/hello-world-go.sps similarity index 100% rename from examples/jammy/go/hello-world/hello-world-go.sps rename to examples/trixie/go/hello-world/hello-world-go.sps diff --git a/examples/jammy/go/hello-world/hello-world-go.sss b/examples/trixie/go/hello-world/hello-world-go.sss similarity index 100% rename from examples/jammy/go/hello-world/hello-world-go.sss rename to examples/trixie/go/hello-world/hello-world-go.sss diff --git a/examples/trixie/go/hello-world/pkg-builder.toml b/examples/trixie/go/hello-world/pkg-builder.toml new file mode 100644 index 00000000..a02c6c57 --- /dev/null +++ b/examples/trixie/go/hello-world/pkg-builder.toml @@ -0,0 +1,32 @@ +[package] +name = "hello-world-go" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-go.sss" + +[source] +type = "tarball" +url = "hello-world-go-1.0.0.tar.gz" +hash = "c268da86e5489a61491313aac237baf895cf269da477cbe9dc8bf4afdf0847a52b4d15ffb763f2f3ea6022116e3ce44df25384522fbdd40dd79a3a84252640cb" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "go" +binary_url = "https://go.dev/dl/go1.22.2.linux-amd64.tar.gz" +binary_checksum = "5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-go_1.0.0-1.dsc", hash = "8fe9a6abe6f495805dce7cbcf37a5db0d4dfd96b404fe7350196062f6eccc133" }, + { name = "hello-world-go_1.0.0-1_amd64.deb", hash = "7a30bbafc1a0d40ebf66a52e3bae9719aa1644653636cbcc1c4030216b369502" }, +] diff --git a/examples/trixie/go/hello-world/sbuild.conf b/examples/trixie/go/hello-world/sbuild.conf new file mode 100644 index 00000000..fc9d8ffa --- /dev/null +++ b/examples/trixie/go/hello-world/sbuild.conf @@ -0,0 +1,38 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: go | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-go-1.0.0-1"; + +# Runtime: Go +my $binary_url = 'https://go.dev/dl/go1.22.2.linux-amd64.tar.gz'; +my $binary_checksum = '5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/go.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/go.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm -f /tmp/go.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/local/go/bin/go /usr/bin/go', + 'chmod -R a+rwx /usr/local/go/pkg', + 'apt remove -y wget', + 'go version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/git-package/nimbus/src/debian/copyright b/examples/trixie/go/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/git-package/nimbus/src/debian/copyright rename to examples/trixie/go/hello-world/src/debian/copyright diff --git a/examples/trixie/go/hello-world/src/debian/hello-world-go.lintian-overrides b/examples/trixie/go/hello-world/src/debian/hello-world-go.lintian-overrides new file mode 100644 index 00000000..a73ded17 --- /dev/null +++ b/examples/trixie/go/hello-world/src/debian/hello-world-go.lintian-overrides @@ -0,0 +1,4 @@ +hello-world-go: initial-upload-closes-no-bugs [usr/share/doc/hello-world-go/changelog.Debian.gz:1] +hello-world-go: maintainer-script-ignores-errors [postrm] +hello-world-go: no-manual-page [usr/bin/hello-world] +hello-world-go: statically-linked-binary [usr/lib/hello-world-go/bin/hello-world] diff --git a/examples/jammy/go/hello-world/src/debian/rules b/examples/trixie/go/hello-world/src/debian/rules similarity index 88% rename from examples/jammy/go/hello-world/src/debian/rules rename to examples/trixie/go/hello-world/src/debian/rules index d41182a7..cf503d42 100644 --- a/examples/jammy/go/hello-world/src/debian/rules +++ b/examples/trixie/go/hello-world/src/debian/rules @@ -21,5 +21,5 @@ override_dh_auto_install: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/trixie/go/hello-world/src/debian/source/lintian-overrides b/examples/trixie/go/hello-world/src/debian/source/lintian-overrides new file mode 100644 index 00000000..1266bed7 --- /dev/null +++ b/examples/trixie/go/hello-world/src/debian/source/lintian-overrides @@ -0,0 +1 @@ +hello-world-go source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/c/hello-world/src/debian/tests/control b/examples/trixie/go/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/c/hello-world/src/debian/tests/control rename to examples/trixie/go/hello-world/src/debian/tests/control diff --git a/examples/jammy/go/hello-world/src/debian/tests/tests b/examples/trixie/go/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/go/hello-world/src/debian/tests/tests rename to examples/trixie/go/hello-world/src/debian/tests/tests diff --git a/examples/jammy/java-gradle/hello-world/hello-world-java-gradle-1.0.0.tar.gz b/examples/trixie/java-gradle/hello-world/hello-world-java-gradle-1.0.0.tar.gz similarity index 100% rename from examples/jammy/java-gradle/hello-world/hello-world-java-gradle-1.0.0.tar.gz rename to examples/trixie/java-gradle/hello-world/hello-world-java-gradle-1.0.0.tar.gz diff --git a/examples/jammy/java-gradle/hello-world/hello-world-java-gradle.changelog b/examples/trixie/java-gradle/hello-world/hello-world-java-gradle.changelog similarity index 61% rename from examples/jammy/java-gradle/hello-world/hello-world-java-gradle.changelog rename to examples/trixie/java-gradle/hello-world/hello-world-java-gradle.changelog index 34743f3a..f98110de 100644 --- a/examples/jammy/java-gradle/hello-world/hello-world-java-gradle.changelog +++ b/examples/trixie/java-gradle/hello-world/hello-world-java-gradle.changelog @@ -1,4 +1,4 @@ -hello-world-java-gradle (1.0.0-1) jammy; urgency=medium +hello-world-java-gradle (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/java-gradle/hello-world/hello-world-java-gradle.sps b/examples/trixie/java-gradle/hello-world/hello-world-java-gradle.sps similarity index 100% rename from examples/jammy/java-gradle/hello-world/hello-world-java-gradle.sps rename to examples/trixie/java-gradle/hello-world/hello-world-java-gradle.sps diff --git a/examples/jammy/java-gradle/hello-world/hello-world-java-gradle.sss b/examples/trixie/java-gradle/hello-world/hello-world-java-gradle.sss similarity index 100% rename from examples/jammy/java-gradle/hello-world/hello-world-java-gradle.sss rename to examples/trixie/java-gradle/hello-world/hello-world-java-gradle.sss diff --git a/examples/trixie/java-gradle/hello-world/pkg-builder.toml b/examples/trixie/java-gradle/hello-world/pkg-builder.toml new file mode 100644 index 00000000..add88874 --- /dev/null +++ b/examples/trixie/java-gradle/hello-world/pkg-builder.toml @@ -0,0 +1,36 @@ +[package] +name = "hello-world-java-gradle" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java-gradle.sss" + +[source] +type = "tarball" +url = "hello-world-java-gradle-1.0.0.tar.gz" +hash = "9838986aeb5fbf1e24fc20da08772c2264b5e0ace8a09b423c39cdc8774b0c04" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages" + +[runtime] +recipe = "java-gradle" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" +gradle_binary_url = "https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip" +gradle_binary_checksum = "544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d" +jdk_version = "17.0.10" +gradle_version = "8.7" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java-gradle_1.0.0-1.dsc", hash = "706d9aa0629b3939987bc4f480ed62e85e8417039327590a1c99000aa21b2f6e" }, + { name = "hello-world-java-gradle_1.0.0-1_amd64.deb", hash = "e35d6086c35016d86a59f56472ac04148000ab9ec9bbe3de6e070991d8ba9bd3" }, +] diff --git a/examples/trixie/java-gradle/hello-world/sbuild.conf b/examples/trixie/java-gradle/hello-world/sbuild.conf new file mode 100644 index 00000000..758939f2 --- /dev/null +++ b/examples/trixie/java-gradle/hello-world/sbuild.conf @@ -0,0 +1,50 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java-gradle | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/hello-world-java-gradle-1.0.0-1"; + +# Runtime: Java with Gradle +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '17.0.10'; +my $gradle_binary_url = 'https://github.com/gradle/gradle-distributions/releases/download/v8.7.0/gradle-8.7-bin.zip'; +my $gradle_binary_checksum = '544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d'; +my $gradle_version = '8.7'; + +my @runtime_commands = ( + 'apt install -y wget unzip', + # JDK + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + # Gradle + "wget -q -O /tmp/gradle.zip $gradle_binary_url", + "echo \"$gradle_binary_checksum /tmp/gradle.zip\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "cd /tmp && unzip -q gradle.zip && mv gradle-${gradle_version} /opt/lib/ && rm -f /tmp/gradle.zip /tmp/hash_file.txt", + "ln -s /opt/lib/gradle-${gradle_version}/bin/gradle /usr/bin/gradle", + 'apt remove -y wget unzip', + 'java -version', + 'gradle -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/go/hello-world/src/debian/copyright b/examples/trixie/java-gradle/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/go/hello-world/src/debian/copyright rename to examples/trixie/java-gradle/hello-world/src/debian/copyright diff --git a/examples/trixie/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides b/examples/trixie/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides new file mode 100644 index 00000000..aa80286f --- /dev/null +++ b/examples/trixie/java-gradle/hello-world/src/debian/hello-world-java-gradle.lintian-overrides @@ -0,0 +1,9 @@ +# if you don't upload to debian this is not a bug +hello-world-java-gradle: initial-upload-closes-no-bugs [usr/share/doc/hello-world-java-gradle/changelog.Debian.gz:1] +hello-world-java-gradle: maintainer-script-ignores-errors [postrm] +hello-world-java-gradle: mismatched-override initial-upload-closes-no-bugs [usr/share/doc/hello-world/changelog.Debian.gz:1] [usr/share/lintian/overrides/hello-world-java-gradle:2] +hello-world-java-gradle: no-manual-page [usr/bin/hello-world] +hello-world-java-gradle: script-not-executable [usr/lib/hello-world-java-gradle/bin/hello.sh] +hello-world-java-gradle: jar-not-in-usr-share * +hello-world-java-gradle: codeless-jar [usr/lib/hello-world-java-gradle/lib/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar] +hello-world-java-gradle: executable-not-elf-or-script [usr/lib/hello-world-java-gradle/bin/app.bat] diff --git a/examples/jammy/java-gradle/hello-world/src/debian/rules b/examples/trixie/java-gradle/hello-world/src/debian/rules similarity index 81% rename from examples/jammy/java-gradle/hello-world/src/debian/rules rename to examples/trixie/java-gradle/hello-world/src/debian/rules index 5499a337..df95bea0 100644 --- a/examples/jammy/java-gradle/hello-world/src/debian/rules +++ b/examples/trixie/java-gradle/hello-world/src/debian/rules @@ -15,5 +15,5 @@ override_dh_auto_build: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/jammy/java-gradle/hello-world/src/debian/source/lintian-overrides b/examples/trixie/java-gradle/hello-world/src/debian/source/lintian-overrides similarity index 80% rename from examples/jammy/java-gradle/hello-world/src/debian/source/lintian-overrides rename to examples/trixie/java-gradle/hello-world/src/debian/source/lintian-overrides index 8a82d062..06318496 100644 --- a/examples/jammy/java-gradle/hello-world/src/debian/source/lintian-overrides +++ b/examples/trixie/java-gradle/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-java-gradle source: debian-rules-ignores-make-clean-error (line 19) +hello-world-java-gradle source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/java-gradle/hello-world/src/debian/tests/control b/examples/trixie/java-gradle/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/java-gradle/hello-world/src/debian/tests/control rename to examples/trixie/java-gradle/hello-world/src/debian/tests/control diff --git a/examples/jammy/java-gradle/hello-world/src/debian/tests/tests-with-open-jre b/examples/trixie/java-gradle/hello-world/src/debian/tests/tests-with-open-jre similarity index 100% rename from examples/jammy/java-gradle/hello-world/src/debian/tests/tests-with-open-jre rename to examples/trixie/java-gradle/hello-world/src/debian/tests/tests-with-open-jre diff --git a/examples/jammy/java-gradle/hello-world/src/debian/tests/tests-with-oracle-jre b/examples/trixie/java-gradle/hello-world/src/debian/tests/tests-with-oracle-jre similarity index 100% rename from examples/jammy/java-gradle/hello-world/src/debian/tests/tests-with-oracle-jre rename to examples/trixie/java-gradle/hello-world/src/debian/tests/tests-with-oracle-jre diff --git a/examples/jammy/java-gradle/hello-world/src/debian/tests/tests-without-java b/examples/trixie/java-gradle/hello-world/src/debian/tests/tests-without-java similarity index 100% rename from examples/jammy/java-gradle/hello-world/src/debian/tests/tests-without-java rename to examples/trixie/java-gradle/hello-world/src/debian/tests/tests-without-java diff --git a/examples/jammy/java/hello-world/hello-world-java-1.0.0.tar.gz b/examples/trixie/java/hello-world/hello-world-java-1.0.0.tar.gz similarity index 100% rename from examples/jammy/java/hello-world/hello-world-java-1.0.0.tar.gz rename to examples/trixie/java/hello-world/hello-world-java-1.0.0.tar.gz diff --git a/examples/jammy/java/hello-world/hello-world-java.changelog b/examples/trixie/java/hello-world/hello-world-java.changelog similarity index 64% rename from examples/jammy/java/hello-world/hello-world-java.changelog rename to examples/trixie/java/hello-world/hello-world-java.changelog index 8e8f8a6e..08f0e1c6 100644 --- a/examples/jammy/java/hello-world/hello-world-java.changelog +++ b/examples/trixie/java/hello-world/hello-world-java.changelog @@ -1,4 +1,4 @@ -hello-world-java (1.0.0-1) jammy; urgency=medium +hello-world-java (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/java/hello-world/hello-world-java.sps b/examples/trixie/java/hello-world/hello-world-java.sps similarity index 100% rename from examples/jammy/java/hello-world/hello-world-java.sps rename to examples/trixie/java/hello-world/hello-world-java.sps diff --git a/examples/jammy/java/hello-world/hello-world-java.sss b/examples/trixie/java/hello-world/hello-world-java.sss similarity index 100% rename from examples/jammy/java/hello-world/hello-world-java.sss rename to examples/trixie/java/hello-world/hello-world-java.sss diff --git a/examples/trixie/java/hello-world/pkg-builder.toml b/examples/trixie/java/hello-world/pkg-builder.toml new file mode 100644 index 00000000..e5d64bad --- /dev/null +++ b/examples/trixie/java/hello-world/pkg-builder.toml @@ -0,0 +1,32 @@ +[package] +name = "hello-world-java" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-java.sss" + +[source] +type = "tarball" +url = "hello-world-java-1.0.0.tar.gz" +hash = "c361ad7853f4eb1e272eb10fe70ac8a5fd40677da5d23e205e1808f2c6f3bed7" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages" + +[runtime] +recipe = "java" +binary_url = "https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz" +binary_checksum = "e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-java_1.0.0-1.dsc", hash = "31248c92451ea4aaee0090e615d9ae837e99383d6333be20dc018727ca8b8b80" }, + { name = "hello-world-java_1.0.0-1_amd64.deb", hash = "a91c2a3dd0307ee98bdd2a836e8cf0412de42d700c56143977dd0c71491e3aad" }, +] diff --git a/examples/trixie/java/hello-world/sbuild.conf b/examples/trixie/java/hello-world/sbuild.conf new file mode 100644 index 00000000..eb0e645a --- /dev/null +++ b/examples/trixie/java/hello-world/sbuild.conf @@ -0,0 +1,40 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: java | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/hello-world-java-1.0.0-1"; + +# Runtime: Java (JDK only) +my $binary_url = 'https://download.oracle.com/java/17/archive/jdk-17.0.10_linux-x64_bin.tar.gz'; +my $binary_checksum = 'e4fb2df9a32a876afb0a6e17f54c594c2780e18badfa2e8fc99bc2656b0a57b1'; +my $jdk_version = '{{jdk_version}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + 'apt remove -y wget', + 'java -version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/java-gradle/hello-world/src/debian/copyright b/examples/trixie/java/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/java-gradle/hello-world/src/debian/copyright rename to examples/trixie/java/hello-world/src/debian/copyright diff --git a/examples/trixie/java/hello-world/src/debian/hello-world-java.lintian-overrides b/examples/trixie/java/hello-world/src/debian/hello-world-java.lintian-overrides new file mode 100644 index 00000000..8a5dd9ee --- /dev/null +++ b/examples/trixie/java/hello-world/src/debian/hello-world-java.lintian-overrides @@ -0,0 +1,7 @@ +# if you don't upload to debian this is not a bug +hello-world-java: initial-upload-closes-no-bugs [usr/share/doc/hello-world-java/changelog.Debian.gz:1] +hello-world-java: maintainer-script-ignores-errors [postrm] +hello-world-java: mismatched-override initial-upload-closes-no-bugs [usr/share/doc/hello-world/changelog.Debian.gz:1] [usr/share/lintian/overrides/hello-world-java:2] +hello-world-java: no-manual-page [usr/bin/hello-world] +hello-world-java: script-not-executable [usr/lib/hello-world-java/bin/hello.sh] + diff --git a/examples/jammy/java/hello-world/src/debian/hello-world.sh b/examples/trixie/java/hello-world/src/debian/hello-world.sh similarity index 100% rename from examples/jammy/java/hello-world/src/debian/hello-world.sh rename to examples/trixie/java/hello-world/src/debian/hello-world.sh diff --git a/examples/jammy/java/hello-world/src/debian/rules b/examples/trixie/java/hello-world/src/debian/rules similarity index 78% rename from examples/jammy/java/hello-world/src/debian/rules rename to examples/trixie/java/hello-world/src/debian/rules index 8025be50..cc5766f2 100644 --- a/examples/jammy/java/hello-world/src/debian/rules +++ b/examples/trixie/java/hello-world/src/debian/rules @@ -13,5 +13,5 @@ override_dh_auto_build: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/trixie/java/hello-world/src/debian/source/lintian-overrides b/examples/trixie/java/hello-world/src/debian/source/lintian-overrides new file mode 100644 index 00000000..62a3373c --- /dev/null +++ b/examples/trixie/java/hello-world/src/debian/source/lintian-overrides @@ -0,0 +1 @@ +hello-world-java source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/java/hello-world/src/debian/tests/control b/examples/trixie/java/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/java/hello-world/src/debian/tests/control rename to examples/trixie/java/hello-world/src/debian/tests/control diff --git a/examples/jammy/java/hello-world/src/debian/tests/tests-with-open-jre b/examples/trixie/java/hello-world/src/debian/tests/tests-with-open-jre similarity index 100% rename from examples/jammy/java/hello-world/src/debian/tests/tests-with-open-jre rename to examples/trixie/java/hello-world/src/debian/tests/tests-with-open-jre diff --git a/examples/jammy/java/hello-world/src/debian/tests/tests-with-oracle-jre b/examples/trixie/java/hello-world/src/debian/tests/tests-with-oracle-jre similarity index 100% rename from examples/jammy/java/hello-world/src/debian/tests/tests-with-oracle-jre rename to examples/trixie/java/hello-world/src/debian/tests/tests-with-oracle-jre diff --git a/examples/jammy/java/hello-world/src/debian/tests/tests-without-java b/examples/trixie/java/hello-world/src/debian/tests/tests-without-java similarity index 100% rename from examples/jammy/java/hello-world/src/debian/tests/tests-without-java rename to examples/trixie/java/hello-world/src/debian/tests/tests-without-java diff --git a/examples/jammy/javascript/hello-world/hello-world-javascript-1.0.0.tar.gz b/examples/trixie/javascript/hello-world/hello-world-javascript-1.0.0.tar.gz similarity index 100% rename from examples/jammy/javascript/hello-world/hello-world-javascript-1.0.0.tar.gz rename to examples/trixie/javascript/hello-world/hello-world-javascript-1.0.0.tar.gz diff --git a/examples/jammy/javascript/hello-world/hello-world-javascript.changelog b/examples/trixie/javascript/hello-world/hello-world-javascript.changelog similarity index 62% rename from examples/jammy/javascript/hello-world/hello-world-javascript.changelog rename to examples/trixie/javascript/hello-world/hello-world-javascript.changelog index 26853f1d..d83f839a 100644 --- a/examples/jammy/javascript/hello-world/hello-world-javascript.changelog +++ b/examples/trixie/javascript/hello-world/hello-world-javascript.changelog @@ -1,4 +1,4 @@ -hello-world-javascript (1.0.0-1) jammy; urgency=medium +hello-world-javascript (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/javascript/hello-world/hello-world-javascript.sps b/examples/trixie/javascript/hello-world/hello-world-javascript.sps similarity index 100% rename from examples/jammy/javascript/hello-world/hello-world-javascript.sps rename to examples/trixie/javascript/hello-world/hello-world-javascript.sps diff --git a/examples/jammy/javascript/hello-world/hello-world-javascript.sss b/examples/trixie/javascript/hello-world/hello-world-javascript.sss similarity index 100% rename from examples/jammy/javascript/hello-world/hello-world-javascript.sss rename to examples/trixie/javascript/hello-world/hello-world-javascript.sss diff --git a/examples/trixie/javascript/hello-world/pkg-builder.toml b/examples/trixie/javascript/hello-world/pkg-builder.toml new file mode 100644 index 00000000..d544ee8a --- /dev/null +++ b/examples/trixie/javascript/hello-world/pkg-builder.toml @@ -0,0 +1,33 @@ +[package] +name = "hello-world-javascript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-javascript.sss" + +[source] +type = "tarball" +url = "hello-world-javascript-1.0.0.tar.gz" +hash = "a7c7eb7779e319cc9c884128a64bd0997481c16aab75824b7f6a02844f847cbc46c5a04a21efcb024661ed0795fe9908fd8c00954ffdbff80337dcb6471d53f0" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +yarn_version = "1.22.19" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-javascript_1.0.0-1.dsc", hash = "0bfd1099e12db3c8e640d1c7b146ab3973e258fe10c2e2b7d5b14267f2f5a354" }, + { name = "hello-world-javascript_1.0.0-1_amd64.deb", hash = "3f62bfae072d15935032476fda216cdacdcc898bc2196801949dfd4eff838857" }, +] diff --git a/examples/trixie/javascript/hello-world/sbuild.conf b/examples/trixie/javascript/hello-world/sbuild.conf new file mode 100644 index 00000000..677ec290 --- /dev/null +++ b/examples/trixie/javascript/hello-world/sbuild.conf @@ -0,0 +1,41 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-javascript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/java/hello-world/src/debian/copyright b/examples/trixie/javascript/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/java/hello-world/src/debian/copyright rename to examples/trixie/javascript/hello-world/src/debian/copyright diff --git a/examples/trixie/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides b/examples/trixie/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides new file mode 100644 index 00000000..6b886a3f --- /dev/null +++ b/examples/trixie/javascript/hello-world/src/debian/hello-world-javascript.lintian-overrides @@ -0,0 +1,5 @@ +# if you don't upload to debian this is not a bug +hello-world-javascript: initial-upload-closes-no-bugs [usr/share/doc/hello-world-javascript/changelog.Debian.gz:1] +hello-world-javascript: maintainer-script-ignores-errors [postrm] +hello-world-javascript: no-manual-page [usr/bin/hello-world] +hello-world-javascript: script-not-executable [usr/lib/hello-world-javascript/src/hello.sh] \ No newline at end of file diff --git a/examples/jammy/javascript/hello-world/src/debian/hello-world.sh b/examples/trixie/javascript/hello-world/src/debian/hello-world.sh similarity index 100% rename from examples/jammy/javascript/hello-world/src/debian/hello-world.sh rename to examples/trixie/javascript/hello-world/src/debian/hello-world.sh diff --git a/examples/jammy/javascript/hello-world/src/debian/rules b/examples/trixie/javascript/hello-world/src/debian/rules similarity index 80% rename from examples/jammy/javascript/hello-world/src/debian/rules rename to examples/trixie/javascript/hello-world/src/debian/rules index ed395efc..8ece5fdf 100644 --- a/examples/jammy/javascript/hello-world/src/debian/rules +++ b/examples/trixie/javascript/hello-world/src/debian/rules @@ -14,5 +14,5 @@ override_dh_auto_build: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/jammy/javascript/hello-world/src/debian/source/lintian-overrides b/examples/trixie/javascript/hello-world/src/debian/source/lintian-overrides similarity index 81% rename from examples/jammy/javascript/hello-world/src/debian/source/lintian-overrides rename to examples/trixie/javascript/hello-world/src/debian/source/lintian-overrides index d121db3a..10f2ad8d 100644 --- a/examples/jammy/javascript/hello-world/src/debian/source/lintian-overrides +++ b/examples/trixie/javascript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-javascript source: debian-rules-ignores-make-clean-error (line 18) +hello-world-javascript source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/javascript/hello-world/src/debian/tests/control b/examples/trixie/javascript/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/javascript/hello-world/src/debian/tests/control rename to examples/trixie/javascript/hello-world/src/debian/tests/control diff --git a/examples/jammy/javascript/hello-world/src/debian/tests/tests b/examples/trixie/javascript/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/javascript/hello-world/src/debian/tests/tests rename to examples/trixie/javascript/hello-world/src/debian/tests/tests diff --git a/examples/jammy/javascript/hello-world/src/debian/tests/tests-with-node b/examples/trixie/javascript/hello-world/src/debian/tests/tests-with-node similarity index 100% rename from examples/jammy/javascript/hello-world/src/debian/tests/tests-with-node rename to examples/trixie/javascript/hello-world/src/debian/tests/tests-with-node diff --git a/examples/jammy/nim/hello-world/hello-world-nim-1.0.0.tar.gz b/examples/trixie/nim/hello-world/hello-world-nim-1.0.0.tar.gz similarity index 100% rename from examples/jammy/nim/hello-world/hello-world-nim-1.0.0.tar.gz rename to examples/trixie/nim/hello-world/hello-world-nim-1.0.0.tar.gz diff --git a/examples/jammy/nim/hello-world/hello-world-nim.changelog b/examples/trixie/nim/hello-world/hello-world-nim.changelog similarity index 65% rename from examples/jammy/nim/hello-world/hello-world-nim.changelog rename to examples/trixie/nim/hello-world/hello-world-nim.changelog index 8f935ab4..690f6ccd 100644 --- a/examples/jammy/nim/hello-world/hello-world-nim.changelog +++ b/examples/trixie/nim/hello-world/hello-world-nim.changelog @@ -1,4 +1,4 @@ -hello-world-nim (1.0.0-1) jammy; urgency=medium +hello-world-nim (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/nim/hello-world/hello-world-nim.sps b/examples/trixie/nim/hello-world/hello-world-nim.sps similarity index 100% rename from examples/jammy/nim/hello-world/hello-world-nim.sps rename to examples/trixie/nim/hello-world/hello-world-nim.sps diff --git a/examples/jammy/nim/hello-world/hello-world-nim.sss b/examples/trixie/nim/hello-world/hello-world-nim.sss similarity index 100% rename from examples/jammy/nim/hello-world/hello-world-nim.sss rename to examples/trixie/nim/hello-world/hello-world-nim.sss diff --git a/examples/trixie/nim/hello-world/pkg-builder.toml b/examples/trixie/nim/hello-world/pkg-builder.toml new file mode 100644 index 00000000..a33375f3 --- /dev/null +++ b/examples/trixie/nim/hello-world/pkg-builder.toml @@ -0,0 +1,33 @@ +[package] +name = "hello-world-nim" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-nim.sss" + +[source] +type = "tarball" +url = "hello-world-nim-1.0.0.tar.gz" +hash = "b24e4ff701d8cbccab0cc78f2de55518babcd05a861af8d5d140863637b0ec74ba3ed5255bafc7fbe596defcc227e8f788c1e540655725eeabb7144be573e8a7" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "nim" +binary_url = "https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz" +binary_checksum = "047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz" +nim_version = "2.0.2" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-nim_1.0.0-1.dsc", hash = "6645e6b5240a55a1e9807221a882b97f70515d6cfef1a8e141ca4eb6e6b11802" }, + { name = "hello-world-nim_1.0.0-1_amd64.deb", hash = "7631698ea1dd6b64719f26a366ef498344381fddf327c45cd546eb5b136257d2" }, +] diff --git a/examples/trixie/nim/hello-world/sbuild.conf b/examples/trixie/nim/hello-world/sbuild.conf new file mode 100644 index 00000000..10be184a --- /dev/null +++ b/examples/trixie/nim/hello-world/sbuild.conf @@ -0,0 +1,42 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: nim | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-nim-1.0.0-1"; + +# Runtime: Nim +# Note: binary_checksum includes the filename (e.g. "hash nim-VER-linux_x64.tar.xz") +my $binary_url = 'https://nim-lang.org/download/nim-2.0.2-linux_x64.tar.xz'; +my $binary_checksum = '047dde8ff40b18628ac1188baa9ca992d05f1f45c5121d1d07a76224f06e1551 nim-2.0.2-linux_x64.tar.xz'; +my $nim_version = '2.0.2'; + +my $nim_archive = "nim-${nim_version}-linux_x64.tar.xz"; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/$nim_archive $binary_url", + "cd /tmp && echo \"$binary_checksum\" > hash_file.txt && sha256sum -c hash_file.txt", + 'mkdir -p /opt/lib/nim', + "mkdir -p /tmp/nim-extract && tar xJf /tmp/$nim_archive -C /tmp/nim-extract --strip-components=1 && mv /tmp/nim-extract /opt/lib/nim/nim-${nim_version} && rm -f /tmp/$nim_archive /tmp/hash_file.txt", + "ln -s /opt/lib/nim/nim-${nim_version}/bin/nim /usr/bin/nim", + 'apt remove -y wget', + 'nim --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/javascript/hello-world/src/debian/copyright b/examples/trixie/nim/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/javascript/hello-world/src/debian/copyright rename to examples/trixie/nim/hello-world/src/debian/copyright diff --git a/examples/trixie/nim/hello-world/src/debian/hello-world-nim.lintian-overrides b/examples/trixie/nim/hello-world/src/debian/hello-world-nim.lintian-overrides new file mode 100644 index 00000000..25d3636a --- /dev/null +++ b/examples/trixie/nim/hello-world/src/debian/hello-world-nim.lintian-overrides @@ -0,0 +1,4 @@ +# if you don't upload to debian this is not a bug +hello-world-nim: initial-upload-closes-no-bugs [usr/share/doc/hello-world-nim/changelog.Debian.gz:1] +hello-world-nim: maintainer-script-ignores-errors [postrm] +hello-world-nim: no-manual-page [usr/bin/hello-world] \ No newline at end of file diff --git a/examples/jammy/nim/hello-world/src/debian/rules b/examples/trixie/nim/hello-world/src/debian/rules similarity index 72% rename from examples/jammy/nim/hello-world/src/debian/rules rename to examples/trixie/nim/hello-world/src/debian/rules index 6fe8db40..d253fd06 100644 --- a/examples/jammy/nim/hello-world/src/debian/rules +++ b/examples/trixie/nim/hello-world/src/debian/rules @@ -16,8 +16,5 @@ override_dh_auto_install: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean - -override_dh_strip: - dh_strip --no-automatic-dbgsym diff --git a/examples/trixie/nim/hello-world/src/debian/source/lintian-overrides b/examples/trixie/nim/hello-world/src/debian/source/lintian-overrides new file mode 100644 index 00000000..69356191 --- /dev/null +++ b/examples/trixie/nim/hello-world/src/debian/source/lintian-overrides @@ -0,0 +1 @@ +hello-world-nim source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/go/hello-world/src/debian/tests/control b/examples/trixie/nim/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/go/hello-world/src/debian/tests/control rename to examples/trixie/nim/hello-world/src/debian/tests/control diff --git a/examples/jammy/nim/hello-world/src/debian/tests/tests b/examples/trixie/nim/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/nim/hello-world/src/debian/tests/tests rename to examples/trixie/nim/hello-world/src/debian/tests/tests diff --git a/examples/jammy/rust/hello-world/hello-world-rust-1.0.0.tar.gz b/examples/trixie/rust/hello-world/hello-world-rust-1.0.0.tar.gz similarity index 100% rename from examples/jammy/rust/hello-world/hello-world-rust-1.0.0.tar.gz rename to examples/trixie/rust/hello-world/hello-world-rust-1.0.0.tar.gz diff --git a/examples/jammy/rust/hello-world/hello-world-rust.changelog b/examples/trixie/rust/hello-world/hello-world-rust.changelog similarity index 64% rename from examples/jammy/rust/hello-world/hello-world-rust.changelog rename to examples/trixie/rust/hello-world/hello-world-rust.changelog index a1fd1a73..8aaf5de8 100644 --- a/examples/jammy/rust/hello-world/hello-world-rust.changelog +++ b/examples/trixie/rust/hello-world/hello-world-rust.changelog @@ -1,4 +1,4 @@ -hello-world-rust (1.0.0-1) jammy; urgency=medium +hello-world-rust (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/rust/hello-world/hello-world-rust.sps b/examples/trixie/rust/hello-world/hello-world-rust.sps similarity index 100% rename from examples/jammy/rust/hello-world/hello-world-rust.sps rename to examples/trixie/rust/hello-world/hello-world-rust.sps diff --git a/examples/jammy/rust/hello-world/hello-world-rust.sss b/examples/trixie/rust/hello-world/hello-world-rust.sss similarity index 100% rename from examples/jammy/rust/hello-world/hello-world-rust.sss rename to examples/trixie/rust/hello-world/hello-world-rust.sss diff --git a/examples/trixie/rust/hello-world/pkg-builder.toml b/examples/trixie/rust/hello-world/pkg-builder.toml new file mode 100644 index 00000000..ccf3595c --- /dev/null +++ b/examples/trixie/rust/hello-world/pkg-builder.toml @@ -0,0 +1,48 @@ +[package] +name = "hello-world-rust" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-rust.sss" + +[source] +type = "tarball" +url = "hello-world-rust-1.0.0.tar.gz" +hash = "f5bab501028b666be71da81dcd675082d05ad4b8e1650350d27a89209a0e239a209a05b7cd3f89b1ec909260a6a2382f1c929b09ca61353594fe5836420b232d" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "rust" +binary_url = "https://static.rust-lang.org/dist/rust-1.94.0-x86_64-unknown-linux-gnu.tar.xz" +binary_gpg_asc = """-----BEGIN PGP SIGNATURE----- + +wsFcBAABCgAQBQJpqcrwCRCFq5bm+hvl/gAA9D0QANn8ev2hsore88LH1pYjT/em +fcer+TMQHazVsX5Ay4fLN79yyTXWXw/fO0E6JVKbZGuU2PpjrauXHahnrs8qTHkz +5nHMa6GcjbD5Ai1lzAeIo9Fl6qmszxf35uu6Fze71rqcW7slgOpRcGxUQaZFrHQo ++cEwAJ5XI9xiYjJDPRiZQu3hItcs2F3k+BUpl9E4N699818Iz/Nkxpd+B3OsU41x +TessON17oSSB8wNMq38SZW4bou1MWyWQASxS3ijzKipii2ABAY+71IUFxtDzWs/s ++kpvXD2UWVb/UMXQoXsWZ5mQj47Nj/AupWp/KX8v5Jamjivh6F+SG6Skq9cLgk3X +p1KhpJQefTDPx1rtz/MUWKMVeYEgd4oxy3yXQx5fcY+OD+31fntPkZKRBawrVwqd +Fx8AJ162fcp/3EIalVnBe+nnYb0/Tvk/CVvJRUqnJ3nc2t4qOOY9L0WC1LpBkEeD +tMm+q2TPYoMLA0LQSXcCFYj4BEThTHZI/ZvBKRGdopud7JTpSG7BczzjtC1z6nhQ +Pbads6M8GUHuIkfmSkVJron1EKqFISO8yTEd0HQlxSc8Pl2jioVkWnv9oM4os1zm +HHPLL77IzTAsDXtWSzvt3IuL+tmI2ZG9c3FvzTlC5Eji9+HOecCOR2QfrdJaqsRp +4yBHeEEQXm/cW4SVspKo +=Bvj8 +-----END PGP SIGNATURE----- +""" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-rust_1.0.0-1.dsc", hash = "9f20ca77a2ea162dbe5977e2343c287ab1891fe6f41989b31d5709e8039aae5f" }, + { name = "hello-world-rust_1.0.0-1_amd64.deb", hash = "5442cb0e10641f105cf1e27dd6a1f1917bd3216e3a9b9445e24e589d1501ce63" }, +] diff --git a/examples/trixie/rust/hello-world/sbuild.conf b/examples/trixie/rust/hello-world/sbuild.conf new file mode 100644 index 00000000..6661abb8 --- /dev/null +++ b/examples/trixie/rust/hello-world/sbuild.conf @@ -0,0 +1,57 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: rust | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-rust-1.0.0-1"; + +# Runtime: Rust (GPG-verified) +my $binary_url = 'https://static.rust-lang.org/dist/rust-1.94.0-x86_64-unknown-linux-gnu.tar.xz'; +my $binary_gpg_asc = '-----BEGIN PGP SIGNATURE----- + +wsFcBAABCgAQBQJpqcrwCRCFq5bm+hvl/gAA9D0QANn8ev2hsore88LH1pYjT/em +fcer+TMQHazVsX5Ay4fLN79yyTXWXw/fO0E6JVKbZGuU2PpjrauXHahnrs8qTHkz +5nHMa6GcjbD5Ai1lzAeIo9Fl6qmszxf35uu6Fze71rqcW7slgOpRcGxUQaZFrHQo ++cEwAJ5XI9xiYjJDPRiZQu3hItcs2F3k+BUpl9E4N699818Iz/Nkxpd+B3OsU41x +TessON17oSSB8wNMq38SZW4bou1MWyWQASxS3ijzKipii2ABAY+71IUFxtDzWs/s ++kpvXD2UWVb/UMXQoXsWZ5mQj47Nj/AupWp/KX8v5Jamjivh6F+SG6Skq9cLgk3X +p1KhpJQefTDPx1rtz/MUWKMVeYEgd4oxy3yXQx5fcY+OD+31fntPkZKRBawrVwqd +Fx8AJ162fcp/3EIalVnBe+nnYb0/Tvk/CVvJRUqnJ3nc2t4qOOY9L0WC1LpBkEeD +tMm+q2TPYoMLA0LQSXcCFYj4BEThTHZI/ZvBKRGdopud7JTpSG7BczzjtC1z6nhQ +Pbads6M8GUHuIkfmSkVJron1EKqFISO8yTEd0HQlxSc8Pl2jioVkWnv9oM4os1zm +HHPLL77IzTAsDXtWSzvt3IuL+tmI2ZG9c3FvzTlC5Eji9+HOecCOR2QfrdJaqsRp +4yBHeEEQXm/cW4SVspKo +=Bvj8 +-----END PGP SIGNATURE----- +'; + +my @runtime_commands = ( + 'apt install -y wget gpg gpg-agent', + "wget -q -O /tmp/rust.tar.xz $binary_url", + "echo \"$binary_gpg_asc\" > /tmp/rust.tar.xz.asc", + 'wget -qO- https://keybase.io/rust/pgp_keys.asc | gpg --import', + 'gpg --verify /tmp/rust.tar.xz.asc /tmp/rust.tar.xz', + 'mkdir -p /tmp/rust-install && tar xJf /tmp/rust.tar.xz -C /tmp/rust-install --strip-components=1 && rm -f /tmp/rust.tar.xz /tmp/rust.tar.xz.asc', + '/bin/bash /tmp/rust-install/install.sh --components=rustc,cargo,rust-std-x86_64-unknown-linux-gnu', + 'rm -rf /tmp/rust-install', + 'apt remove -y wget gpg gpg-agent', + 'rustc --version', + 'cargo --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/nim/hello-world/src/debian/copyright b/examples/trixie/rust/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/nim/hello-world/src/debian/copyright rename to examples/trixie/rust/hello-world/src/debian/copyright diff --git a/examples/trixie/rust/hello-world/src/debian/hello-world-rust.lintian-overrides b/examples/trixie/rust/hello-world/src/debian/hello-world-rust.lintian-overrides new file mode 100644 index 00000000..299a33a8 --- /dev/null +++ b/examples/trixie/rust/hello-world/src/debian/hello-world-rust.lintian-overrides @@ -0,0 +1,4 @@ +# if you don't upload to debian this is not a bug +hello-world-rust: initial-upload-closes-no-bugs [usr/share/doc/hello-world-rust/changelog.Debian.gz:1] +hello-world-rust: maintainer-script-ignores-errors [postrm] +hello-world-rust: no-manual-page [usr/bin/hello-world] diff --git a/examples/jammy/rust/hello-world/src/debian/rules b/examples/trixie/rust/hello-world/src/debian/rules similarity index 65% rename from examples/jammy/rust/hello-world/src/debian/rules rename to examples/trixie/rust/hello-world/src/debian/rules index e800b53c..b31e2efc 100644 --- a/examples/jammy/rust/hello-world/src/debian/rules +++ b/examples/trixie/rust/hello-world/src/debian/rules @@ -12,7 +12,5 @@ override_dh_auto_build: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean -override_dh_strip: - dh_strip --no-automatic-dbgsym diff --git a/examples/trixie/rust/hello-world/src/debian/source/lintian-overrides b/examples/trixie/rust/hello-world/src/debian/source/lintian-overrides new file mode 100644 index 00000000..8167aafb --- /dev/null +++ b/examples/trixie/rust/hello-world/src/debian/source/lintian-overrides @@ -0,0 +1 @@ +hello-world-rust source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/nim/hello-world/src/debian/tests/control b/examples/trixie/rust/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/nim/hello-world/src/debian/tests/control rename to examples/trixie/rust/hello-world/src/debian/tests/control diff --git a/examples/jammy/rust/hello-world/src/debian/tests/tests b/examples/trixie/rust/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/rust/hello-world/src/debian/tests/tests rename to examples/trixie/rust/hello-world/src/debian/tests/tests diff --git a/examples/jammy/typescript/hello-world/hello-world-typescript-1.0.0.tar.gz b/examples/trixie/typescript/hello-world/hello-world-typescript-1.0.0.tar.gz similarity index 100% rename from examples/jammy/typescript/hello-world/hello-world-typescript-1.0.0.tar.gz rename to examples/trixie/typescript/hello-world/hello-world-typescript-1.0.0.tar.gz diff --git a/examples/jammy/typescript/hello-world/hello-world-typescript.changelog b/examples/trixie/typescript/hello-world/hello-world-typescript.changelog similarity index 62% rename from examples/jammy/typescript/hello-world/hello-world-typescript.changelog rename to examples/trixie/typescript/hello-world/hello-world-typescript.changelog index a26c5d93..59b5ea94 100644 --- a/examples/jammy/typescript/hello-world/hello-world-typescript.changelog +++ b/examples/trixie/typescript/hello-world/hello-world-typescript.changelog @@ -1,4 +1,4 @@ -hello-world-typescript (1.0.0-1) jammy; urgency=medium +hello-world-typescript (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/typescript/hello-world/hello-world-typescript.sps b/examples/trixie/typescript/hello-world/hello-world-typescript.sps similarity index 100% rename from examples/jammy/typescript/hello-world/hello-world-typescript.sps rename to examples/trixie/typescript/hello-world/hello-world-typescript.sps diff --git a/examples/jammy/typescript/hello-world/hello-world-typescript.sss b/examples/trixie/typescript/hello-world/hello-world-typescript.sss similarity index 100% rename from examples/jammy/typescript/hello-world/hello-world-typescript.sss rename to examples/trixie/typescript/hello-world/hello-world-typescript.sss diff --git a/examples/trixie/typescript/hello-world/pkg-builder.toml b/examples/trixie/typescript/hello-world/pkg-builder.toml new file mode 100644 index 00000000..569c570d --- /dev/null +++ b/examples/trixie/typescript/hello-world/pkg-builder.toml @@ -0,0 +1,33 @@ +[package] +name = "hello-world-typescript" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "hello-world-typescript.sss" + +[source] +type = "tarball" +url = "hello-world-typescript-1.0.0.tar.gz" +hash = "e28af9271dd941888317597af77246c14671c83254a06c756d5fc56f0291a411e89fb730c1d19a848b3c3ac185c0ba20ed1accdd5feb6cc2a1c1c3a2febeba5c" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[runtime] +recipe = "node" +binary_url = "https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz" +binary_checksum = "f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d" +yarn_version = "1.22.19" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "hello-world-typescript_1.0.0-1.dsc", hash = "8ef3c56988911d197e3248deec17692879b42f3f8042300b1281ea467154e3f5" }, + { name = "hello-world-typescript_1.0.0-1_amd64.deb", hash = "1f81332b35c7d50e02d2efa05b06f759794866b0f5d597ad727625f4de303c02" }, +] diff --git a/examples/trixie/typescript/hello-world/sbuild.conf b/examples/trixie/typescript/hello-world/sbuild.conf new file mode 100644 index 00000000..28d9b8c6 --- /dev/null +++ b/examples/trixie/typescript/hello-world/sbuild.conf @@ -0,0 +1,41 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: node | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/hello-world-typescript-1.0.0-1"; + +# Runtime: Node.js +my $binary_url = 'https://nodejs.org/download/release/v20.12.2/node-v20.12.2-linux-x64.tar.gz'; +my $binary_checksum = 'f8f9b6877778ed2d5f920a5bd853f0f8a8be1c42f6d448c763a95625cbbb4b0d'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); + +$external_commands = { + 'chroot-setup-commands' => [ + @runtime_commands, + ], +}; + +1; diff --git a/examples/jammy/rust/hello-world/src/debian/copyright b/examples/trixie/typescript/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/rust/hello-world/src/debian/copyright rename to examples/trixie/typescript/hello-world/src/debian/copyright diff --git a/examples/jammy/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides b/examples/trixie/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides similarity index 57% rename from examples/jammy/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides rename to examples/trixie/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides index 032d89dd..602b9ffb 100644 --- a/examples/jammy/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides +++ b/examples/trixie/typescript/hello-world/src/debian/hello-world-typescript.lintian-overrides @@ -1,6 +1,8 @@ -hello-world-typescript: missing-dep-for-interpreter node (does not satisfy nodejs:any) [usr/lib/hello-world-typescript/node_modules/typescript/bin/tsc] -hello-world-typescript: missing-dep-for-interpreter node (does not satisfy nodejs:any) [usr/lib/hello-world-typescript/node_modules/typescript/bin/tsserver] -hello-world-typescript: initial-upload-closes-no-bugs +# if you don't upload to debian this is not a bug +hello-world-typescript: initial-upload-closes-no-bugs [usr/share/doc/hello-world-typescript/changelog.Debian.gz:1] hello-world-typescript: maintainer-script-ignores-errors [postrm] -hello-world-typescript: no-manual-page usr/bin/hello-world +hello-world-typescript: no-manual-page [usr/bin/hello-world] hello-world-typescript: script-not-executable [usr/lib/hello-world-typescript/src/hello.sh] +# you can add nodejs as dependency, this package does not adds it +hello-world-typescript: missing-dep-for-interpreter node (does not satisfy nodejs:any) [usr/lib/hello-world-typescript/node_modules/typescript/bin/tsc] +hello-world-typescript: missing-dep-for-interpreter node (does not satisfy nodejs:any) [usr/lib/hello-world-typescript/node_modules/typescript/bin/tsserver] \ No newline at end of file diff --git a/examples/jammy/typescript/hello-world/src/debian/hello-world.sh b/examples/trixie/typescript/hello-world/src/debian/hello-world.sh similarity index 100% rename from examples/jammy/typescript/hello-world/src/debian/hello-world.sh rename to examples/trixie/typescript/hello-world/src/debian/hello-world.sh diff --git a/examples/jammy/typescript/hello-world/src/debian/rules b/examples/trixie/typescript/hello-world/src/debian/rules similarity index 82% rename from examples/jammy/typescript/hello-world/src/debian/rules rename to examples/trixie/typescript/hello-world/src/debian/rules index 8696d14e..a3d16a24 100644 --- a/examples/jammy/typescript/hello-world/src/debian/rules +++ b/examples/trixie/typescript/hello-world/src/debian/rules @@ -16,5 +16,5 @@ override_dh_auto_build: override_dh_auto_clean: # on ubuntu clean fails, before dependency installation - # on bookworm clean succeeds, even if dependency is not installed + # on debian clean succeeds, even if dependency is not installed -make -j1 clean diff --git a/examples/jammy/typescript/hello-world/source/lintian-overrides b/examples/trixie/typescript/hello-world/src/debian/source/lintian-overrides similarity index 73% rename from examples/jammy/typescript/hello-world/source/lintian-overrides rename to examples/trixie/typescript/hello-world/src/debian/source/lintian-overrides index 616c696a..4209707c 100644 --- a/examples/jammy/typescript/hello-world/source/lintian-overrides +++ b/examples/trixie/typescript/hello-world/src/debian/source/lintian-overrides @@ -1 +1 @@ -hello-world-typescript source: debian-rules-ignores-make-clean-error [debian/rules:20] +hello-world-typescript source: debian-rules-ignores-make-clean-error diff --git a/examples/jammy/typescript/hello-world/src/debian/tests/control b/examples/trixie/typescript/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/typescript/hello-world/src/debian/tests/control rename to examples/trixie/typescript/hello-world/src/debian/tests/control diff --git a/examples/jammy/typescript/hello-world/src/debian/tests/tests b/examples/trixie/typescript/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/typescript/hello-world/src/debian/tests/tests rename to examples/trixie/typescript/hello-world/src/debian/tests/tests diff --git a/examples/jammy/typescript/hello-world/src/debian/tests/tests-with-node b/examples/trixie/typescript/hello-world/src/debian/tests/tests-with-node similarity index 100% rename from examples/jammy/typescript/hello-world/src/debian/tests/tests-with-node rename to examples/trixie/typescript/hello-world/src/debian/tests/tests-with-node diff --git a/examples/trixie/virtual/hello-world/pkg-builder.toml b/examples/trixie/virtual/hello-world/pkg-builder.toml new file mode 100644 index 00000000..8f35f57a --- /dev/null +++ b/examples/trixie/virtual/hello-world/pkg-builder.toml @@ -0,0 +1,25 @@ +[package] +name = "test-virtual-package" +version = "1.0.0" +revision = "1" +homepage = "https://github.com/eth-pkg/pkg-builder#examples" +spec = "test-virtual-package.sss" + +[source] +type = "virtual" + +[build] +distribution = "trixie" +arch = "amd64" +workdir = "~/.pkg-builder/packages/trixie" + +[tools] +pkg_builder = "0.3.1" +debcrafter = "8189263" +sbuild = "0.85.6" + +[verify] +package_hash = [ + { name = "test-virtual-package_1.0.0-1.dsc", hash = "61254d1e347b1156891460cc58cb1dc4261446b57bf9e3b9afed8cc10bd61963" }, + { name = "test-virtual-package_1.0.0-1_amd64.deb", hash = "fa896c9cd4ad158b57937da59a380bab38ff970b49a3de32e786b991e0c9f0b9" }, +] diff --git a/examples/trixie/virtual/hello-world/sbuild.conf b/examples/trixie/virtual/hello-world/sbuild.conf new file mode 100644 index 00000000..2effae2f --- /dev/null +++ b/examples/trixie/virtual/hello-world/sbuild.conf @@ -0,0 +1,18 @@ +# Auto-generated by pkg-builder — do not edit +# Runtime: none | Distribution: trixie + +$distribution = 'trixie'; +$build_arch_all = 1; +$build_source = 1; +$source_only_changes = 1; +$chroot_mode = 'unshare'; +$run_piuparts = 0; +$apt_upgrade = 0; +$apt_distupgrade = 0; +$run_autopkgtest = 0; +$verbose = 1; +$run_lintian = 0; +$build_dir = "$ENV{HOME}/.pkg-builder/packages/trixie/test-virtual-package-1.0.0-1"; + + +1; diff --git a/examples/jammy/typescript/hello-world/src/debian/copyright b/examples/trixie/virtual/hello-world/src/debian/copyright similarity index 100% rename from examples/jammy/typescript/hello-world/src/debian/copyright rename to examples/trixie/virtual/hello-world/src/debian/copyright diff --git a/examples/trixie/virtual/hello-world/src/debian/source/lintian-overrides b/examples/trixie/virtual/hello-world/src/debian/source/lintian-overrides new file mode 100644 index 00000000..c8db6d54 --- /dev/null +++ b/examples/trixie/virtual/hello-world/src/debian/source/lintian-overrides @@ -0,0 +1,2 @@ +# Not a bug, this is a virtual package to serve as umbrella installation for others package deps +test-virtual-package source: empty-upstream-sources \ No newline at end of file diff --git a/examples/trixie/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides b/examples/trixie/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides new file mode 100644 index 00000000..8c4e1c0f --- /dev/null +++ b/examples/trixie/virtual/hello-world/src/debian/test-virtual-package.lintian-overrides @@ -0,0 +1,2 @@ +test-virtual-package: initial-upload-closes-no-bugs [usr/share/doc/test-virtual-package/changelog.Debian.gz:1] +test-virtual-package: maintainer-script-ignores-errors [postrm] diff --git a/examples/jammy/virtual/hello-world/src/debian/tests/control b/examples/trixie/virtual/hello-world/src/debian/tests/control similarity index 100% rename from examples/jammy/virtual/hello-world/src/debian/tests/control rename to examples/trixie/virtual/hello-world/src/debian/tests/control diff --git a/examples/jammy/virtual/hello-world/src/debian/tests/tests b/examples/trixie/virtual/hello-world/src/debian/tests/tests similarity index 100% rename from examples/jammy/virtual/hello-world/src/debian/tests/tests rename to examples/trixie/virtual/hello-world/src/debian/tests/tests diff --git a/examples/jammy/virtual/hello-world/test-virtual-package.changelog b/examples/trixie/virtual/hello-world/test-virtual-package.changelog similarity index 63% rename from examples/jammy/virtual/hello-world/test-virtual-package.changelog rename to examples/trixie/virtual/hello-world/test-virtual-package.changelog index f07d4795..b417a5c4 100644 --- a/examples/jammy/virtual/hello-world/test-virtual-package.changelog +++ b/examples/trixie/virtual/hello-world/test-virtual-package.changelog @@ -1,4 +1,4 @@ -test-virtual-package (1.0.0-1) jammy; urgency=medium +test-virtual-package (1.0.0-1) trixie; urgency=medium * Initial packaging diff --git a/examples/jammy/virtual/hello-world/test-virtual-package.sps b/examples/trixie/virtual/hello-world/test-virtual-package.sps similarity index 100% rename from examples/jammy/virtual/hello-world/test-virtual-package.sps rename to examples/trixie/virtual/hello-world/test-virtual-package.sps diff --git a/examples/jammy/virtual/hello-world/test-virtual-package.sss b/examples/trixie/virtual/hello-world/test-virtual-package.sss similarity index 100% rename from examples/jammy/virtual/hello-world/test-virtual-package.sss rename to examples/trixie/virtual/hello-world/test-virtual-package.sss diff --git a/release-plz.toml b/release-plz.toml new file mode 100644 index 00000000..d7b6bc6f --- /dev/null +++ b/release-plz.toml @@ -0,0 +1,32 @@ +[workspace] +changelog_update = true +git_release_enable = true +git_release_type = "auto" +publish = false +release_commits = "^feat|^fix|^refactor|^perf|^docs" + +[[package]] +name = "pkg-builder-cli" +# CLI is the primary release artifact +changelog_path = "CHANGELOG.md" +version_group = "pkg-builder" + +[[package]] +name = "pkg-builder-config" +release = false +version_group = "pkg-builder" + +[[package]] +name = "pkg-builder-init" +release = false +version_group = "pkg-builder" + +[[package]] +name = "pkg-builder-executor" +release = false +version_group = "pkg-builder" + +[[package]] +name = "pkg-builder-update" +release = false +version_group = "pkg-builder" diff --git a/runtimes/c.perl b/runtimes/c.perl new file mode 100644 index 00000000..b6f9ca99 --- /dev/null +++ b/runtimes/c.perl @@ -0,0 +1,2 @@ +# Runtime: C (no special setup needed) +my @runtime_commands = (); diff --git a/runtimes/dotnet-backup.perl b/runtimes/dotnet-backup.perl new file mode 100644 index 00000000..84076fd0 --- /dev/null +++ b/runtimes/dotnet-backup.perl @@ -0,0 +1,19 @@ +# Runtime: .NET backup version (direct .deb install) +my @packages = ( +{{packages_perl}} +); + +my @runtime_commands = ( + 'apt install -y wget libicu-dev', + (map { + my $p = $_; + ( + "wget -q -O /tmp/$$p{name}.deb $$p{url}", + "dpkg -i /tmp/$$p{name}.deb", + "echo \"$$p{hash} /tmp/$$p{name}.deb\" > /tmp/hash_file.txt && sha1sum -c /tmp/hash_file.txt", + "rm -f /tmp/$$p{name}.deb /tmp/hash_file.txt", + ) + } @packages), + 'apt remove -y wget', + 'dotnet --version', +); diff --git a/runtimes/dotnet-debian.perl b/runtimes/dotnet-debian.perl new file mode 100644 index 00000000..0c08855a --- /dev/null +++ b/runtimes/dotnet-debian.perl @@ -0,0 +1,22 @@ +# Runtime: .NET on Debian (Microsoft repo) +my @packages = ( +{{packages_perl}} +); + +my @runtime_commands = ( + 'apt install -y wget', + 'wget -q -O /tmp/packages-microsoft-prod.deb https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb', + 'dpkg -i /tmp/packages-microsoft-prod.deb && rm -f /tmp/packages-microsoft-prod.deb', + 'apt update -y', + (map { + my $p = $_; + ( + "wget -q -O /tmp/$$p{name}.deb $$p{url}", + "apt install -y --allow-downgrades $$p{apt_name}", + "echo \"$$p{hash} /tmp/$$p{name}.deb\" > /tmp/hash_file.txt && sha1sum -c /tmp/hash_file.txt", + "rm -f /tmp/$$p{name}.deb /tmp/hash_file.txt", + ) + } @packages), + 'apt remove -y wget', + 'dotnet --version', +); diff --git a/runtimes/dotnet-noble.perl b/runtimes/dotnet-noble.perl new file mode 100644 index 00000000..52f181a0 --- /dev/null +++ b/runtimes/dotnet-noble.perl @@ -0,0 +1,22 @@ +# Runtime: .NET on Ubuntu Noble (PPA backports) +my @packages = ( +{{packages_perl}} +); + +my @runtime_commands = ( + 'apt-get install -y software-properties-common', + 'add-apt-repository ppa:dotnet/backports', + 'apt-get update -y', + 'apt install -y wget', + (map { + my $p = $_; + ( + "wget -q -O /tmp/$$p{name}.deb $$p{url}", + "apt install -y $$p{apt_name}", + "echo \"$$p{hash} /tmp/$$p{name}.deb\" > /tmp/hash_file.txt && sha1sum -c /tmp/hash_file.txt", + "rm -f /tmp/$$p{name}.deb /tmp/hash_file.txt", + ) + } @packages), + 'apt remove -y wget', + 'dotnet --version', +); diff --git a/runtimes/go.perl b/runtimes/go.perl new file mode 100644 index 00000000..e7d82be5 --- /dev/null +++ b/runtimes/go.perl @@ -0,0 +1,14 @@ +# Runtime: Go +my $binary_url = '{{binary_url}}'; +my $binary_checksum = '{{binary_checksum}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/go.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/go.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm -f /tmp/go.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/local/go/bin/go /usr/bin/go', + 'chmod -R a+rwx /usr/local/go/pkg', + 'apt remove -y wget', + 'go version', +); diff --git a/runtimes/java-gradle.perl b/runtimes/java-gradle.perl new file mode 100644 index 00000000..16e7a462 --- /dev/null +++ b/runtimes/java-gradle.perl @@ -0,0 +1,26 @@ +# Runtime: Java with Gradle +my $binary_url = '{{binary_url}}'; +my $binary_checksum = '{{binary_checksum}}'; +my $jdk_version = '{{jdk_version}}'; +my $gradle_binary_url = '{{gradle_binary_url}}'; +my $gradle_binary_checksum = '{{gradle_binary_checksum}}'; +my $gradle_version = '{{gradle_version}}'; + +my @runtime_commands = ( + 'apt install -y wget unzip', + # JDK + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + # Gradle + "wget -q -O /tmp/gradle.zip $gradle_binary_url", + "echo \"$gradle_binary_checksum /tmp/gradle.zip\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "cd /tmp && unzip -q gradle.zip && mv gradle-${gradle_version} /opt/lib/ && rm -f /tmp/gradle.zip /tmp/hash_file.txt", + "ln -s /opt/lib/gradle-${gradle_version}/bin/gradle /usr/bin/gradle", + 'apt remove -y wget unzip', + 'java -version', + 'gradle -version', +); diff --git a/runtimes/java.perl b/runtimes/java.perl new file mode 100644 index 00000000..64f4fdd5 --- /dev/null +++ b/runtimes/java.perl @@ -0,0 +1,16 @@ +# Runtime: Java (JDK only) +my $binary_url = '{{binary_url}}'; +my $binary_checksum = '{{binary_checksum}}'; +my $jdk_version = '{{jdk_version}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/jdk.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/jdk.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + "mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle", + "tar -zxf /tmp/jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 && rm -f /tmp/jdk.tar.gz /tmp/hash_file.txt", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java", + "ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac", + 'apt remove -y wget', + 'java -version', +); diff --git a/runtimes/nim.perl b/runtimes/nim.perl new file mode 100644 index 00000000..f007f4a1 --- /dev/null +++ b/runtimes/nim.perl @@ -0,0 +1,18 @@ +# Runtime: Nim +# Note: binary_checksum includes the filename (e.g. "hash nim-VER-linux_x64.tar.xz") +my $binary_url = '{{binary_url}}'; +my $binary_checksum = '{{binary_checksum}}'; +my $nim_version = '{{nim_version}}'; + +my $nim_archive = "nim-${nim_version}-linux_x64.tar.xz"; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/$nim_archive $binary_url", + "cd /tmp && echo \"$binary_checksum\" > hash_file.txt && sha256sum -c hash_file.txt", + 'mkdir -p /opt/lib/nim', + "mkdir -p /tmp/nim-extract && tar xJf /tmp/$nim_archive -C /tmp/nim-extract --strip-components=1 && mv /tmp/nim-extract /opt/lib/nim/nim-${nim_version} && rm -f /tmp/$nim_archive /tmp/hash_file.txt", + "ln -s /opt/lib/nim/nim-${nim_version}/bin/nim /usr/bin/nim", + 'apt remove -y wget', + 'nim --version', +); diff --git a/runtimes/node.perl b/runtimes/node.perl new file mode 100644 index 00000000..6a9a8b35 --- /dev/null +++ b/runtimes/node.perl @@ -0,0 +1,17 @@ +# Runtime: Node.js +my $binary_url = '{{binary_url}}'; +my $binary_checksum = '{{binary_checksum}}'; + +my @runtime_commands = ( + 'apt install -y wget', + "wget -q -O /tmp/node.tar.gz $binary_url", + "echo \"$binary_checksum /tmp/node.tar.gz\" > /tmp/hash_file.txt && sha256sum -c /tmp/hash_file.txt", + 'rm -rf /usr/share/node && mkdir -p /usr/share/node && tar -C /usr/share/node -xzf /tmp/node.tar.gz --strip-components=1 && rm -f /tmp/node.tar.gz /tmp/hash_file.txt', + 'ln -s /usr/share/node/bin/node /usr/bin/node', + 'ln -s /usr/share/node/bin/npm /usr/bin/npm', + 'ln -s /usr/share/node/bin/npx /usr/bin/npx', + 'ln -s /usr/share/node/bin/corepack /usr/bin/corepack', + 'apt remove -y wget', + 'node --version', + 'npm --version', +); diff --git a/runtimes/rust.perl b/runtimes/rust.perl new file mode 100644 index 00000000..e8242ec7 --- /dev/null +++ b/runtimes/rust.perl @@ -0,0 +1,17 @@ +# Runtime: Rust (GPG-verified) +my $binary_url = '{{binary_url}}'; +my $binary_gpg_asc = '{{binary_gpg_asc}}'; + +my @runtime_commands = ( + 'apt install -y wget gpg gpg-agent', + "wget -q -O /tmp/rust.tar.xz $binary_url", + "echo \"$binary_gpg_asc\" > /tmp/rust.tar.xz.asc", + 'wget -qO- https://keybase.io/rust/pgp_keys.asc | gpg --import', + 'gpg --verify /tmp/rust.tar.xz.asc /tmp/rust.tar.xz', + 'mkdir -p /tmp/rust-install && tar xJf /tmp/rust.tar.xz -C /tmp/rust-install --strip-components=1 && rm -f /tmp/rust.tar.xz /tmp/rust.tar.xz.asc', + '/bin/bash /tmp/rust-install/install.sh --components=rustc,cargo,rust-std-x86_64-unknown-linux-gnu', + 'rm -rf /tmp/rust-install', + 'apt remove -y wget gpg gpg-agent', + 'rustc --version', + 'cargo --version', +); diff --git a/scripts/bump-example-versions.sh b/scripts/bump-example-versions.sh new file mode 100755 index 00000000..17a4ac5c --- /dev/null +++ b/scripts/bump-example-versions.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# +# Updates the pkg_builder version in all example pkg-builder.toml files +# to match the current CLI crate version. +# +# Usage: ./scripts/bump-example-versions.sh [version] +# If no version is given, reads it from crates/cli/Cargo.toml + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +if [ $# -ge 1 ]; then + VERSION="$1" +else + VERSION=$(grep '^version' "$REPO_ROOT/crates/cli/Cargo.toml" | head -1 | sed 's/.*"\(.*\)"/\1/') +fi + +if [ -z "$VERSION" ]; then + echo "Error: could not determine version" >&2 + exit 1 +fi + +echo "Bumping pkg_builder version to $VERSION in example TOML files..." + +count=0 +while IFS= read -r -d '' f; do + sed -i "s/^pkg_builder = \".*\"/pkg_builder = \"$VERSION\"/" "$f" + count=$((count + 1)) +done < <(find "$REPO_ROOT/examples" -name "pkg-builder.toml" -print0) + +echo "Updated $count example files to pkg_builder = \"$VERSION\"" diff --git a/workspace/cli/Cargo.toml b/workspace/cli/Cargo.toml deleted file mode 100644 index 825b5a6d..00000000 --- a/workspace/cli/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "cli" -version = "0.3.1" -edition = "2024" - -[lib] -name = "cli" -path = "src/mod.rs" - -[dependencies] -types = { workspace = true} -packager_deb = { workspace = true} -clap = { workspace = true} -toml = { workspace = true} -serde = { workspace = true} -env_logger ={ workspace = true} -log = { workspace = true} -cargo_metadata = { workspace = true} -regex = { workspace = true} -thiserror = { workspace = true} -tempfile = { workspace = true } diff --git a/workspace/cli/src/args.rs b/workspace/cli/src/args.rs deleted file mode 100644 index f9d25b08..00000000 --- a/workspace/cli/src/args.rs +++ /dev/null @@ -1,101 +0,0 @@ -use clap::{Args, Parser, Subcommand}; - -#[derive(Debug, Parser)] -#[clap(author, version, about)] -pub struct PkgBuilderArgs { - #[clap(subcommand)] - pub action: ActionType, -} - -#[derive(Debug, Subcommand)] -pub enum ActionType { - /// create package - Package(PackageCommand), - /// clean, delete, create buildenv for package - Env(EnvCommand), - /// run package update, remove, install tests - Piuparts(DefaultCommand), - /// run tests against built deb package - Autopkgtest(DefaultCommand), - /// run linting against package - Lintian(DefaultCommand), - - /// Verify package against hashes, it also rebuilds the package - Verify(VerifyConfig), - // pkg-builder version - Version, -} - -#[derive(Debug, Args)] -pub struct VerifyConfig { - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder.toml is located - /// if not given current directory is searched for pkg-builder.toml - #[clap(long)] - pub config: Option, - - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder-verify.toml is located - /// if not given current directory is searched for pkg-builder-verify.toml - #[clap(long)] - pub verify_config: Option, - - /// if given it won't repackage it - #[clap(long)] - pub no_package: Option, -} - -#[derive(Debug, Args)] -pub struct DefaultCommand { - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder.toml is located - /// if not given current directory is searched for pkg-builder.toml - pub config: Option, -} - -#[derive(Debug, Args)] -pub struct PackageCommand { - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder.toml is located - /// if not given current directory is searched for pkg-builder.toml - pub config: Option, - /// overrides config value - /// runs piuparts or not based on supplied value - #[clap(long)] - pub run_piuparts: Option, - /// overrides config value - /// runs autopkgtest or not based on supplied value - #[clap(long)] - pub run_autopkgtest: Option, - #[clap(long)] - /// runs lintian or not, based on value, overrides config value - pub run_lintian: Option, -} - -#[derive(Debug, Args)] -pub struct EnvCommand { - #[clap(subcommand)] - pub build_env_sub_command: BuildEnvSubCommand, -} -#[derive(Debug, Subcommand)] -pub enum BuildEnvSubCommand { - /// creates build env used for packaging - Create(CreateBuildEnvCommand), - /// removes build env - Clean(CleanBuildEnvCommand), -} - -#[derive(Debug, Args)] -pub struct CreateBuildEnvCommand { - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder.toml is located - /// if not given current directory is searched for pkg-builder.toml - pub config: Option, -} -#[derive(Debug, Args)] -pub struct CleanBuildEnvCommand { - /// location of pkg-builder config_file, either full path - /// or directory to pkg-builder.toml is located - /// if not given current directory is searched for pkg-builder.toml - pub config: Option, -} diff --git a/workspace/cli/src/cli.rs b/workspace/cli/src/cli.rs deleted file mode 100644 index 7eb3c9ef..00000000 --- a/workspace/cli/src/cli.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::args::{ActionType, BuildEnvSubCommand, PkgBuilderArgs}; -use clap::Parser; -use env_logger::Env; -use log::error; -use packager_deb::handler::PackageError; -use packager_deb::handler::dispatch_package_operation; -use std::env; -use thiserror::Error; -use types::config::Config; -use types::config::ConfigError; -use types::config::ConfigFile; -use types::debian::DebCommandPayload; - -#[derive(Error, Debug)] -pub enum PkgBuilderError { - #[error(transparent)] - PackageError(#[from] PackageError), - - #[error(transparent)] - ConfigError(#[from] ConfigError), -} - -type Result = std::result::Result; - -pub fn run_cli() -> Result<()> { - env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); - - let args = PkgBuilderArgs::parse(); - let program_version: &str = env!("CARGO_PKG_VERSION"); - - if let ActionType::Version = &args.action { - let program_name: &str = env!("CARGO_PKG_NAME"); - - println!("{} version: {}", program_name, program_version); - return Ok(()); - } - - let config_path = match &args.action { - ActionType::Verify(command) => command.config.clone(), - ActionType::Package(command) => command.config.clone(), - ActionType::Env(command) => match &command.build_env_sub_command { - BuildEnvSubCommand::Create(sub_command) => sub_command.config.clone(), - BuildEnvSubCommand::Clean(sub_command) => sub_command.config.clone(), - }, - ActionType::Piuparts(command) => command.config.clone(), - ActionType::Autopkgtest(command) => command.config.clone(), - ActionType::Lintian(command) => command.config.clone(), - ActionType::Version => None, // Special case already handled above - }; - let config_file = ConfigFile::::load(config_path)?; - let build_env = config_file - .clone() - .parse()? - .build_env - .validate_and_apply_defaults(program_version)?; - - let cmd_payload = match args.action { - ActionType::Verify(command) => Ok(DebCommandPayload::Verify { - verify_config: command.verify_config, - no_package: command.no_package, - }), - ActionType::Lintian(_) => Ok(DebCommandPayload::Lintian), - ActionType::Piuparts(_) => Ok(DebCommandPayload::Piuparts), - ActionType::Autopkgtest(_) => Ok(DebCommandPayload::Autopkgtest), - ActionType::Package(cmd) => Ok(DebCommandPayload::Package { - run_autopkgtest: cmd.run_autopkgtest, - run_piuparts: cmd.run_piuparts, - run_lintian: cmd.run_lintian, - }), - ActionType::Env(build_env_action) => match build_env_action.build_env_sub_command { - BuildEnvSubCommand::Create(_) => Ok(DebCommandPayload::EnvCreate), - BuildEnvSubCommand::Clean(_) => Ok(DebCommandPayload::EnvClean), - }, - ActionType::Version => Err("Version has no payload."), - }; - - match build_env.codename { - types::distribution::Distribution::Debian(_) - | types::distribution::Distribution::Ubuntu(_) => { - dispatch_package_operation(config_file, cmd_payload.unwrap())? - } - }; - - Ok(()) -} diff --git a/workspace/cli/src/mod.rs b/workspace/cli/src/mod.rs deleted file mode 100644 index 1029203e..00000000 --- a/workspace/cli/src/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod args; -pub mod cli; diff --git a/workspace/debian/Cargo.lock b/workspace/debian/Cargo.lock deleted file mode 100644 index d9d9997c..00000000 --- a/workspace/debian/Cargo.lock +++ /dev/null @@ -1,253 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "debian" -version = "0.1.0" -dependencies = [ - "eyre", - "log", - "shellexpand", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags", - "libc", -] - -[[package]] -name = "log" -version = "0.4.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" - -[[package]] -name = "once_cell" -version = "1.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "shellexpand" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" -dependencies = [ - "dirs", -] - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/workspace/debian/Cargo.toml b/workspace/debian/Cargo.toml deleted file mode 100644 index f767728d..00000000 --- a/workspace/debian/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "debian" -version = "0.1.0" -edition = "2021" - -[lib] -name = "debian" -path = "src/mod.rs" - -[dependencies] -types = { workspace = true } -log = { workspace = true } -shellexpand = { workspace = true } -thiserror = { workspace = true } -tempfile = { workspace = true } -serde = { workspace = true } -toml = { workspace = true } diff --git a/workspace/debian/src/autopkgtest.rs b/workspace/debian/src/autopkgtest.rs deleted file mode 100644 index 18ee9829..00000000 --- a/workspace/debian/src/autopkgtest.rs +++ /dev/null @@ -1,359 +0,0 @@ -use log::info; -use std::path::PathBuf; -use thiserror::Error; - -use super::execute::{execute_command, Execute, ExecuteError}; - -/// `Autopkgtest` provides a builder interface for autopkgtest commands. -/// -/// This struct implements the builder pattern to configure and execute -/// autopkgtest commands, which are used for testing Debian packages. -/// It allows configuring various options such as changes files, test setup, -/// virtualization options, and more. -/// -/// # Examples -/// -/// ``` -/// use debian::autopkgtest::Autopkgtest; -/// use crate::debian::execute::Execute; -/// use std::path::PathBuf; -/// -/// let result = Autopkgtest::new() -/// .changes_file("package.changes") -/// .apt_upgrade() -/// .setup_commands("apt-get install dependency") -/// .qemu(PathBuf::from("/path/to/image.img")) -/// .working_dir(&PathBuf::from("/tmp/working_dir")) -/// .execute(); -/// ``` -#[derive(Debug, Clone, Default)] -pub struct Autopkgtest { - changes_file: Option, - no_built_binaries: bool, - apt_upgrade: bool, - setup_commands: Vec, - qemu_image: Option, - dir: Option, -} - -/// Custom error type for autopkgtest operations -#[derive(Error, Debug)] -pub enum AutopkgtestError { - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), -} - -type Result = std::result::Result; - -/// Builder for Autopkgtest commands -impl Autopkgtest { - /// Creates a new instance of `Autopkgtest` with default configuration. - /// - /// All options are initialized to their default values: - /// - No changes file - /// - No built binaries flag disabled - /// - Apt upgrade flag disabled - /// - No setup commands - /// - No QEMU image - /// - No working directory - /// - /// # Returns - /// - /// A new `Autopkgtest` instance with default configuration. - pub fn new() -> Self { - Self::default() - } - - /// Specifies a changes file to be processed by autopkgtest. - /// - /// This sets the path to a .changes file that will be used by autopkgtest. - /// The .changes file contains information about the package to be tested. - /// - /// # Arguments - /// - /// * `file` - Path to the .changes file - /// - /// # Returns - /// - /// The updated builder instance. - pub fn changes_file(mut self, file: &str) -> Self { - self.changes_file = Some(file.to_string()); - self - } - - /// Adds the `--no-built-binaries` flag to the command. - /// - /// When this flag is set, autopkgtest will ignore any built binaries - /// that might be available and build everything from source. - /// - /// # Returns - /// - /// The updated builder instance. - pub fn no_built_binaries(mut self) -> Self { - self.no_built_binaries = true; - self - } - - /// Adds the `--apt-upgrade` flag to the command. - /// - /// When this flag is set, autopkgtest will run apt-get upgrade - /// before starting the tests. - /// - /// # Returns - /// - /// The updated builder instance. - pub fn apt_upgrade(mut self) -> Self { - self.apt_upgrade = true; - self - } - - /// Adds a setup command to the autopkgtest. - /// - /// This method allows specifying shell commands that will be run - /// in the test environment before the tests are executed. - /// - /// # Arguments - /// - /// * `command` - A shell command to run in the test environment - /// - /// # Returns - /// - /// The updated builder instance. - pub fn setup_commands(mut self, command: &str) -> Self { - self.setup_commands.push(command.to_string()); - self - } - - /// Specifies test dependencies that are not in Debian repositories. - /// - /// This is a convenience method that adds each dependency as a separate setup command. - /// It can be used to install dependencies that are not available in standard repositories. - /// - /// # Arguments - /// - /// * `deps` - A slice of strings representing the dependencies - /// - /// # Returns - /// - /// The updated builder instance. - pub fn test_deps_not_in_debian(mut self, deps: &[String]) -> Self { - for dep in deps { - self.setup_commands.push(dep.clone()); - } - self - } - - /// Configures the command to use QEMU with the specified image. - /// - /// This adds the necessary arguments to run the tests in a QEMU virtual machine - /// using the specified disk image. - /// - /// # Arguments - /// - /// * `image_path` - Path to the QEMU disk image - /// - /// # Returns - /// - /// The updated builder instance. - pub fn qemu(mut self, image_path: PathBuf) -> Self { - self.qemu_image = Some(image_path); - self - } - - /// Sets the working directory for the command execution. - /// - /// This specifies the directory from which the autopkgtest command - /// will be executed. - /// - /// # Arguments - /// - /// * `dir` - Path to the working directory - /// - /// # Returns - /// - /// The updated builder instance. - pub fn working_dir(mut self, dir: &PathBuf) -> Self { - self.dir = Some(dir.clone()); - self - } - - /// Builds the command arguments based on the configured options. - /// - /// This method constructs a vector of strings representing the - /// command-line arguments that will be passed to the autopkgtest command. - /// - /// # Returns - /// - /// A vector of strings containing the command arguments. - fn build_args(&self) -> Vec { - let mut args = Vec::new(); - - // Add changes file if provided - if let Some(file) = &self.changes_file { - args.push(file.clone()); - } - - // Add flags based on boolean options - if self.no_built_binaries { - args.push("--no-built-binaries".to_string()); - } - - if self.apt_upgrade { - args.push("--apt-upgrade".to_string()); - } - - // Add setup commands - for cmd in &self.setup_commands { - args.push(format!("--setup-commands={}", cmd)); - } - - // Add QEMU configuration if provided - if let Some(image) = &self.qemu_image { - args.push("--".to_string()); - args.push("qemu".to_string()); - args.push(image.display().to_string()); - } - - args - } -} - -/// Implementation of the `Execute` trait for `Autopkgtest`. -/// -/// This allows an `Autopkgtest` instance to be executed using the `execute()` method. -impl Execute for Autopkgtest { - type Error = AutopkgtestError; - /// Executes the autopkgtest command with the configured options. - /// - /// This method builds the command arguments and runs the autopkgtest command. - /// It logs the command being executed and returns an error if the execution fails. - /// - /// # Returns - /// - /// A `Result` indicating success or failure. If successful, the result is `Ok(())`. - /// If there's an error, it will be wrapped with additional context information. - fn execute(&self) -> Result<()> { - let args = self.build_args(); - let args_str = args.join(" "); - info!("Running: autopkgtest {}", args_str); - - execute_command("autopkgtest", &args, self.dir.as_deref())?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - - #[test] - fn test_new() { - let autopkgtest = Autopkgtest::new(); - assert!(autopkgtest.changes_file.is_none()); - assert!(!autopkgtest.no_built_binaries); - assert!(!autopkgtest.apt_upgrade); - assert!(autopkgtest.setup_commands.is_empty()); - assert!(autopkgtest.qemu_image.is_none()); - assert!(autopkgtest.dir.is_none()); - } - - #[test] - fn test_changes_file() { - let autopkgtest = Autopkgtest::new().changes_file("test.changes"); - assert_eq!(autopkgtest.changes_file, Some("test.changes".to_string())); - } - - #[test] - fn test_no_built_binaries() { - let autopkgtest = Autopkgtest::new().no_built_binaries(); - assert!(autopkgtest.no_built_binaries); - } - - #[test] - fn test_apt_upgrade() { - let autopkgtest = Autopkgtest::new().apt_upgrade(); - assert!(autopkgtest.apt_upgrade); - } - - #[test] - fn test_setup_command() { - let autopkgtest = Autopkgtest::new() - .setup_commands("apt-get install foo") - .setup_commands("echo 'test'"); - - assert_eq!( - autopkgtest.setup_commands, - vec!["apt-get install foo".to_string(), "echo 'test'".to_string()] - ); - } - - #[test] - fn test_test_deps_not_in_debian() { - let deps = vec!["dep1".to_string(), "dep2".to_string()]; - let autopkgtest = Autopkgtest::new().test_deps_not_in_debian(&deps); - assert_eq!(autopkgtest.setup_commands, deps); - } - - #[test] - fn test_qemu() { - let autopkgtest = Autopkgtest::new().qemu(PathBuf::from("/path/to/image.img")); - assert_eq!( - autopkgtest.qemu_image, - Some(PathBuf::from("/path/to/image.img")) - ); - } - - #[test] - fn test_working_dir() { - let dir = PathBuf::from("/tmp/test"); - let autopkgtest = Autopkgtest::new().working_dir(&dir); - assert_eq!(autopkgtest.dir, Some(dir)); - } - - #[test] - fn test_build_args() { - let autopkgtest = Autopkgtest::new() - .changes_file("test.changes") - .no_built_binaries() - .apt_upgrade() - .setup_commands("apt-get install pkg1") - .setup_commands("apt-get install pkg2") - .qemu("/path/to/image.img".into()); - - let args = autopkgtest.build_args(); - - assert_eq!( - args, - vec![ - "test.changes", - "--no-built-binaries", - "--apt-upgrade", - "--setup-commands=apt-get install pkg1", - "--setup-commands=apt-get install pkg2", - "--", - "qemu", - "/path/to/image.img" - ] - ); - } - - #[test] - fn test_multiple_setup_commands() { - let autopkgtest = Autopkgtest::new() - .setup_commands("cmd1") - .setup_commands("cmd2") - .setup_commands("cmd3"); - - let args = autopkgtest.build_args(); - - assert_eq!( - args, - vec![ - "--setup-commands=cmd1", - "--setup-commands=cmd2", - "--setup-commands=cmd3" - ] - ); - } -} diff --git a/workspace/debian/src/autopkgtest_image.rs b/workspace/debian/src/autopkgtest_image.rs deleted file mode 100644 index 2c3f1fc1..00000000 --- a/workspace/debian/src/autopkgtest_image.rs +++ /dev/null @@ -1,285 +0,0 @@ -use crate::execute::ExecuteError; - -use super::execute::{execute_command_with_sudo, Execute}; -/// Provides functionality for building and managing Autopkgtest VM images -/// -/// This module contains structures and implementations for creating -/// virtual machine images compatible with autopkgtest for different -/// Linux distributions. -use log::info; -use std::path::{Path, PathBuf}; -use thiserror::Error; -use types::{config::Architecture, distribution::Distribution}; - -/// Custom error type for autopkgtest image building operations -#[derive(Error, Debug)] -pub enum AutopkgtestImageError { - #[error("Distribution not specified")] - MissingDistribution, - - #[error("Image path not specified")] - MissingImagePath, - - #[error("Unsupported or invalid distribution codename: {0}")] - UnsupportedDistribution(String), - - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), - - #[error("Work directory path error: {0}")] - PathError(String), -} - -// Type alias for Result with our custom error type -type Result = std::result::Result; - -trait BuildCommandProvider { - fn get_command(&self) -> &'static str; - fn get_formatted_codename(&self) -> String; -} -impl BuildCommandProvider for Distribution { - /// Returns the appropriate command for building an image for this distribution - /// - /// # Returns - /// * `&'static str` - The command to use for image creation - fn get_command(&self) -> &'static str { - match self { - Distribution::Debian(_) => "autopkgtest-build-qemu", - Distribution::Ubuntu(_) => "autopkgtest-buildvm-ubuntu-cloud", - } - } - - /// Returns the codename formatted as an argument for the build command - /// - /// # Returns - /// * `String` - The formatted codename argument - fn get_formatted_codename(&self) -> String { - match self { - Distribution::Debian(_) => self.as_short().to_string(), - Distribution::Ubuntu(_) => format!("--release={}", self.as_short()), - } - } -} - -/// Builder for creating Autopkgtest VM images -/// -/// Provides a fluent interface for configuring and building VM images -/// for different distributions, architectures, and repositories. -#[derive(Debug, Clone, Default)] -pub struct AutopkgtestImageBuilder { - /// The target Linux distribution - distribution: Option, - /// Path where the image will be created - image_path: Option, - /// Directory to use for temporary files during build - work_dir: Option, - /// Repository mirror URL to use for package installation - mirror: Option, - /// Target architecture for the VM image - arch: Option, -} - -impl AutopkgtestImageBuilder { - /// Creates a new empty builder instance - /// - /// # Returns - /// * `Self` - A new AutopkgtestImageBuilder - pub fn new() -> Self { - Self::default() - } - - /// Sets the distribution codename for the image - /// - /// # Arguments - /// * `codename` - The distribution codename (e.g., "bookworm", "noble") - /// - /// # Returns - /// * `Result` - Modified builder or error if codename is unsupported - pub fn codename(mut self, codename: &Distribution) -> Result { - // Assuming Distribution::from_codename has been modified to return our Result type - // or we're mapping the error here - self.distribution = Some(codename.clone()); - Ok(self) - } - - /// Sets the image output path based on cache directory, codename and architecture - /// - /// # Arguments - /// * `cache_dir` - Directory where the image will be stored - /// * `codename` - Distribution codename - /// * `arch` - Target architecture - /// - /// # Returns - /// * `Self` - Modified builder - pub fn image_path(mut self, cache_dir: &str, codename: &Distribution, arch: &Architecture) -> Self { - let image_name = format!("autopkgtest-{}-{}.img", codename.as_short(), arch); - let cache_dir = shellexpand::tilde(cache_dir).to_string(); - let image_path = Path::new(&cache_dir).join(&image_name); - self.image_path = Some(image_path.clone()); - self.work_dir = Some(image_path.parent().unwrap_or(Path::new("")).to_path_buf()); - self - } - - /// Sets the package repository mirror URL - /// - /// # Arguments - /// * `repo_url` - The URL of the package repository mirror - /// - /// # Returns - /// * `Self` - Modified builder - pub fn mirror(mut self, repo_url: &str) -> Self { - self.mirror = Some(repo_url.to_string()); - self - } - - /// Sets the target architecture for the VM image - /// - /// # Arguments - /// * `arch` - Architecture name (e.g., "amd64", "arm64") - /// - /// # Returns - /// * `Self` - Modified builder - pub fn arch(mut self, arch: &Architecture) -> Self { - self.arch = Some(arch.to_string()); - self - } - - /// Returns the configured image path if set - /// - /// # Returns - /// * `Option<&PathBuf>` - The image path or None if not set - pub fn get_image_path(&self) -> Option<&PathBuf> { - self.image_path.as_ref() - } - - /// Builds the command-line arguments for the image creation command - /// - /// # Returns - /// * `Result>` - The list of arguments or an error if configuration is incomplete - fn build_args(&self) -> Result> { - let mut args = Vec::new(); - - if let Some(dist) = &self.distribution { - args.push(dist.get_formatted_codename()); - } else { - return Err(AutopkgtestImageError::MissingDistribution); - } - - if let Some(mirror) = &self.mirror { - args.push(format!("--mirror={}", mirror)); - } - - if let Some(arch) = &self.arch { - args.push(format!("--arch={}", arch)); - } - - if let Some(Distribution::Ubuntu(_)) = &self.distribution { - args.push("-v".to_string()); - } - - if let Some(path) = &self.image_path { - if let Some(Distribution::Debian(_)) = &self.distribution { - args.push(path.to_string_lossy().to_string()); - } else { - args.push(format!("--timeout={}", 3600)); - args.push(format!("--ram-size={}", 2048)); - } - } else { - return Err(AutopkgtestImageError::MissingImagePath); - } - - Ok(args) - } -} - -/// Implementation of the Execute trait for AutopkgtestImageBuilder -/// -/// Allows the builder to be executed to create the VM image. -impl Execute for AutopkgtestImageBuilder { - type Error = AutopkgtestImageError; - /// Executes the VM image creation process - /// - /// # Returns - /// * `Result<()>` - Success or an error if the build fails - fn execute(&self) -> Result<()> { - let cmd = self - .distribution - .as_ref() - .ok_or(AutopkgtestImageError::MissingDistribution)? - .get_command(); - - let args = self.build_args()?; - - info!("Running: sudo -S {} {}", cmd, args.join(" ")); - - let result = execute_command_with_sudo(cmd, args.clone(), self.work_dir.as_deref()); - - // try again with sudo if the first attempt failed - // for some strange reason the first attempt fails, some of the times on ubuntu runners - if result.is_err(){ - execute_command_with_sudo(cmd, args, self.work_dir.as_deref())?; - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use types::{config::Architecture, distribution::Distribution}; - - /// Tests creation of Distribution from various codenames - #[test] - fn test_distribution_from_codename() { - assert!(matches!( - Distribution::from_codename("bookworm").unwrap(), - Distribution::Debian(_) - )); - - assert!(matches!( - Distribution::from_codename("noble").unwrap(), - Distribution::Ubuntu(_) - )); - - assert!(Distribution::from_codename("unsupported").is_err()); - } - - /// Tests generation of command-line arguments - #[test] - fn test_build_args() { - let builder = AutopkgtestImageBuilder::new() - .codename(&Distribution::bookworm()) - .unwrap() - .image_path("/tmp", &Distribution::bookworm(), &Architecture::Amd64) - .arch(&Architecture::Amd64) - .mirror("http://example.com/debian"); - - let args = builder.build_args().unwrap(); - assert!(args.contains(&"bookworm".to_string())); - assert!(args - .iter() - .any(|arg| arg.contains("/tmp/autopkgtest-bookworm-amd64.img"))); - assert!(args.contains(&"--arch=amd64".to_string())); - assert!(args.contains(&"--mirror=http://example.com/debian".to_string())); - } - - #[test] - fn test_noble_build_args() { - let builder = AutopkgtestImageBuilder::new() - .codename(&Distribution::noble()) - .unwrap() - .image_path("/tmp", &Distribution::noble(), &Architecture::Amd64) - .arch(&Architecture::Amd64) - .mirror("http://example.com/ubuntu"); - - let args = builder.build_args().unwrap(); - assert!(args.contains(&"--release=noble".to_string())); - assert!(!args.contains(&"--release=noble numbat".to_string())); - assert!(args - .iter() - .all(|arg| !arg.contains("/tmp/autopkgtest-noble-amd64.img"))); - assert!(args.contains(&"--arch=amd64".to_string())); - assert!(args.contains(&"--mirror=http://example.com/ubuntu".to_string())); - } -} diff --git a/workspace/debian/src/debcrafter.rs b/workspace/debian/src/debcrafter.rs deleted file mode 100644 index c24c8240..00000000 --- a/workspace/debian/src/debcrafter.rs +++ /dev/null @@ -1,314 +0,0 @@ -use log::info; -use std::fs; -use std::io; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; -use tempfile::tempdir; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum DebcrafterCmdError { - #[error("Command not found: {0}")] - CommandNotFound(#[from] io::Error), - - #[error("Failed to execute command: {0}")] - CommandFailed(CommandError), - - #[error("File not found: {0}")] - FileNotFound(String), -} - -#[derive(Debug, Error)] -pub enum CommandError { - #[error("{0}")] - StringError(String), - #[error("{0}")] - IOError(#[from] io::Error), -} - -impl PartialEq for CommandError { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::StringError(a), Self::StringError(b)) => a == b, - (Self::IOError(_), Self::IOError(_)) => false, // IO errors aren't comparable - _ => false, - } - } -} - -impl From for CommandError { - fn from(err: String) -> Self { - CommandError::StringError(err) - } -} - -pub struct DebcrafterCmd { - version: String, -} - -impl DebcrafterCmd { - /// Creates a new DebcrafterCmd with the specified version - pub fn new(version: &str) -> Self { - Self { - version: version.to_string(), - } - } - - /// Checks if dpkg-parsechangelog is installed on the system - pub fn check_if_dpkg_parsechangelog_installed(&self) -> Result<(), DebcrafterCmdError> { - let mut cmd = Command::new("which"); - cmd.arg("dpkg-parsechangelog"); - - self.handle_command_execution( - &mut cmd, - "dpkg-parsechangelog is not installed, please install it.".to_string(), - ) - } - - /// Checks if the specified version of debcrafter is installed - pub fn check_if_installed(&self) -> Result<(), DebcrafterCmdError> { - let mut cmd = Command::new("which"); - cmd.arg(format!("debcrafter_{}", self.version)); - - self.handle_command_execution( - &mut cmd, - format!("debcrafter_{} is not installed", self.version), - ) - } - - /// Creates a debian directory using the specified specification file - pub fn create_debian_dir( - &self, - specification_file: &PathBuf, - target_dir: &PathBuf, - ) -> Result<(), DebcrafterCmdError> { - let debcrafter_dir = - tempdir().map_err(|e| DebcrafterCmdError::CommandFailed(e.to_string().into()))?; - - let spec_file_path = fs::canonicalize(specification_file).map_err(|_| { - DebcrafterCmdError::FileNotFound(format!( - "{:?} spec_file doesn't exist", - specification_file - )) - })?; - - if !spec_file_path.exists() { - return Err(DebcrafterCmdError::FileNotFound(format!( - "{:?} spec_file doesn't exist", - specification_file - ))); - } - - let spec_dir = spec_file_path.parent().ok_or_else(|| { - DebcrafterCmdError::CommandFailed("Invalid specification file path".to_string().into()) - })?; - - let spec_file_name = spec_file_path.file_name().ok_or_else(|| { - DebcrafterCmdError::CommandFailed("Invalid specification file name".to_string().into()) - })?; - - info!( - "Spec directory: {:?}", - spec_dir.to_str().unwrap_or_default() - ); - info!("Spec file: {:?}", spec_file_name); - info!("Debcrafter directory: {:?}", debcrafter_dir.path()); - - let mut cmd = Command::new(format!("debcrafter_{}", self.version)); - cmd.arg(spec_file_name) - .current_dir(spec_dir) - .arg(debcrafter_dir.path()); - - self.handle_command_execution(&mut cmd, "Debcrafter execution failed".to_string())?; - - if let Some(first_directory) = self.get_first_directory(debcrafter_dir.path()) { - let tmp_debian_dir = first_directory.join("debian"); - let dest_dir = Path::new(target_dir).join("debian"); - self.copy_dir_contents_recursive(&tmp_debian_dir, &dest_dir) - .map_err(|err| DebcrafterCmdError::CommandFailed(err.to_string().into()))?; - } else { - return Err(DebcrafterCmdError::CommandFailed( - "Unable to create debian dir: no output directory found" - .to_string() - .into(), - )); - } - - Ok(()) - } - - /// Recursively copies the contents of a directory to another location - fn copy_dir_contents_recursive(&self, src_dir: &Path, dest_dir: &Path) -> io::Result<()> { - info!( - "Copying directory: {:?} to {:?}", - src_dir.display(), - dest_dir.display() - ); - - if !src_dir.is_dir() { - return Err(io::Error::new( - io::ErrorKind::NotFound, - format!("Source path is not a directory: {}", src_dir.display()), - )); - } - - if !dest_dir.exists() { - fs::create_dir_all(dest_dir)?; - } - - for entry in fs::read_dir(src_dir)? { - let entry = entry?; - let src_path = entry.path(); - let dest_path = dest_dir.join(entry.file_name()); - - if src_path.is_dir() { - self.copy_dir_contents_recursive(&src_path, &dest_path)?; - } else { - fs::copy(&src_path, &dest_path)?; - } - } - - Ok(()) - } - - /// Handles command execution and processes errors - fn handle_command_execution( - &self, - cmd: &mut Command, - error_message: String, - ) -> Result<(), DebcrafterCmdError> { - let output = cmd - .output() - .map_err(|e| DebcrafterCmdError::CommandNotFound(e))?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr).to_string(); - let detailed_error = if stderr.is_empty() { - error_message - } else { - format!("{}: {}", error_message, stderr) - }; - - return Err(DebcrafterCmdError::CommandFailed(detailed_error.into())); - } - - Ok(()) - } - - /// Gets the first directory in a given path - fn get_first_directory(&self, dir: &Path) -> Option { - if !dir.is_dir() { - return None; - } - - fs::read_dir(dir) - .ok()? - .filter_map(Result::ok) - .find(|entry| entry.path().is_dir()) - .map(|entry| entry.path()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::{NamedTempFile, TempDir}; - - #[test] - fn test_command_error_from_string() { - let error = CommandError::from("test error".to_string()); - assert_eq!(error, CommandError::StringError("test error".to_string())); - } - - #[test] - fn test_command_error_from_io_error() { - let io_error = io::Error::new(io::ErrorKind::NotFound, "io error"); - let error_kind = io_error.kind(); - let error = CommandError::from(io::Error::new(error_kind, "io error")); - assert!(matches!(error, CommandError::IOError(_))); - } - - #[test] - fn test_get_first_directory_none() { - // Create a temp file (not a directory) - let temp_file = NamedTempFile::new().unwrap(); - let path = temp_file.path(); - let cmd = DebcrafterCmd::new("test"); - - assert_eq!(cmd.get_first_directory(path), None); - } - - #[test] - fn test_get_first_directory_empty() { - // Create an empty temp directory - let temp_dir = TempDir::new().unwrap(); - let path = temp_dir.path(); - let cmd = DebcrafterCmd::new("test"); - - assert_eq!(cmd.get_first_directory(path), None); - } - - #[test] - fn test_get_first_directory_with_subdirectory() { - // Create a temp directory with a subdirectory - let temp_dir = TempDir::new().unwrap(); - let sub_dir_path = temp_dir.path().join("subdir"); - fs::create_dir(&sub_dir_path).unwrap(); - let cmd = DebcrafterCmd::new("test"); - - let result = cmd.get_first_directory(temp_dir.path()); - assert!(result.is_some()); - assert_eq!(result.unwrap(), sub_dir_path); - } - - #[test] - fn test_copy_dir_contents_recursive() { - // Create source directory structure - let src_dir = TempDir::new().unwrap(); - let src_file1_path = src_dir.path().join("file1.txt"); - let src_subdir_path = src_dir.path().join("subdir"); - let src_file2_path = src_subdir_path.join("file2.txt"); - - fs::create_dir(&src_subdir_path).unwrap(); - fs::write(&src_file1_path, b"test content 1").unwrap(); - fs::write(&src_file2_path, b"test content 2").unwrap(); - - // Create destination directory - let dest_dir = TempDir::new().unwrap(); - let cmd = DebcrafterCmd::new("test"); - - // Copy the directory contents - let result = cmd.copy_dir_contents_recursive(src_dir.path(), dest_dir.path()); - assert!(result.is_ok()); - - // Verify the destination has the same structure and content - let dest_file1_path = dest_dir.path().join("file1.txt"); - let dest_subdir_path = dest_dir.path().join("subdir"); - let dest_file2_path = dest_subdir_path.join("file2.txt"); - - assert!(dest_file1_path.exists()); - assert!(dest_subdir_path.exists()); - assert!(dest_file2_path.exists()); - - assert_eq!( - fs::read_to_string(&dest_file1_path).unwrap(), - "test content 1" - ); - assert_eq!( - fs::read_to_string(&dest_file2_path).unwrap(), - "test content 2" - ); - } - - #[test] - fn test_copy_dir_contents_recursive_source_not_dir() { - // Create a temp file (not a directory) - let temp_file = NamedTempFile::new().unwrap(); - let dest_dir = TempDir::new().unwrap(); - let cmd = DebcrafterCmd::new("test"); - - let result = cmd.copy_dir_contents_recursive(temp_file.path(), dest_dir.path()); - assert!(result.is_err()); - } -} diff --git a/workspace/debian/src/execute.rs b/workspace/debian/src/execute.rs deleted file mode 100644 index c153bbb1..00000000 --- a/workspace/debian/src/execute.rs +++ /dev/null @@ -1,87 +0,0 @@ -use log::info; -use std::{ - ffi::OsStr, - io::{BufRead, BufReader}, - path::Path, - process::{Command, Stdio}, -}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum ExecuteError { - #[error("Command execution failed: {0}")] - CommandFailed(#[from] std::io::Error), - - #[error("Failed to change working directory: {0}")] - WorkingDirectoryError(String), - - #[error("Command '{0}' failed with status: {1}")] - CommandStatusError(String, i32), -} - -pub trait Execute { - type Error; - fn execute(&self) -> Result<(), Self::Error>; -} - -pub fn execute_command(cmd: &str, args: I, dir: Option<&Path>) -> Result<(), ExecuteError> -where - I: IntoIterator, - S: AsRef, -{ - let mut command = Command::new(cmd); - command - .args(args) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()); - - if let Some(dir) = dir { - command.current_dir(dir); - } - - run_command(&mut command, cmd) -} - -pub fn execute_command_with_sudo( - cmd: &str, - args: I, - dir: Option<&Path>, -) -> Result<(), ExecuteError> -where - I: IntoIterator, - S: AsRef, -{ - let mut command = Command::new("sudo"); - command - .arg("-S") - .arg(cmd) - .args(args) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()); - - if let Some(dir) = dir { - command.current_dir(dir); - } - - run_command(&mut command, &format!("sudo -S {}", cmd)) -} - -fn run_command(command: &mut Command, cmd_name: &str) -> Result<(), ExecuteError> { - let mut child = command.spawn()?; - - if let Some(stdout) = child.stdout.take() { - let reader = BufReader::new(stdout); - for line in reader.lines() { - info!("{}", line?); - } - } - - let status = child.wait()?; - - if status.success() { - Ok(()) - } else { - let code = status.code().unwrap_or(-1); - Err(ExecuteError::CommandStatusError(cmd_name.to_string(), code)) - } -} diff --git a/workspace/debian/src/lintian.rs b/workspace/debian/src/lintian.rs deleted file mode 100644 index b478bbb6..00000000 --- a/workspace/debian/src/lintian.rs +++ /dev/null @@ -1,395 +0,0 @@ -use super::execute::{execute_command, Execute, ExecuteError}; -use log::info; -use std::path::Path; -use thiserror::Error; -use types::distribution::Distribution; - -/// Represents a wrapper for the Lintian Debian package checker tool. -/// -/// Lintian is used to check Debian packages for compliance with the Debian policy -/// and other quality assurance checks. This struct provides a builder pattern -/// interface to configure and execute Lintian commands. -/// -/// # Examples -/// -/// ``` -/// use debian::lintian::Lintian; -/// use debian::execute::Execute; -/// let result = Lintian::new() -/// .info() -/// .suppress_tag("malformed-deb-archive") -/// .changes_file("package.changes") -/// .execute(); -/// ``` -#[derive(Debug, Clone, Default)] -pub struct Lintian { - /// Tags to suppress during linting - suppress_tags: Vec, - /// Whether to show informational tags - show_info: bool, - /// Whether to show extended information - extended_info: bool, - /// Path to the changes file to check - changes_file_path: Option, - /// Maximum number of tags to display - tag_display_limit: Option, - /// Severity levels to fail on (warning, error) - fail_on: Vec, - /// Ubuntu/Debian codename for version-specific checks - codename: Option, -} - -/// Custom error type for lintian operations -#[derive(Error, Debug)] -pub enum LintianError { - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), -} - -type Result = std::result::Result; - -impl Lintian { - /// Creates a new Lintian instance with default configuration. - /// - /// This method initializes a Lintian object with empty or default values, - /// ready to be configured using the builder pattern. - /// - /// # Returns - /// - /// A new instance of `Lintian`. - pub fn new() -> Self { - Self::default() - } - - /// Suppresses the specified lintian tag. - /// - /// This will add the given tag to the list of tags that Lintian - /// should not report. - /// - /// # Arguments - /// - /// * `tag` - The tag to suppress. - /// - /// # Returns - /// - /// Self with the tag added to the suppress list. - pub fn suppress_tag>(mut self, tag: S) -> Self { - self.suppress_tags.push(tag.as_ref().to_string()); - self - } - - /// Enables display of informational tags. - /// - /// Corresponds to the `-i` flag in the Lintian command. - /// - /// # Returns - /// - /// Self with the info flag enabled. - pub fn info(mut self) -> Self { - self.show_info = true; - self - } - - /// Enables display of extended information. - /// - /// Corresponds to the `-I` flag in the Lintian command. - /// - /// # Returns - /// - /// Self with the extended info flag enabled. - pub fn extended_info(mut self) -> Self { - self.extended_info = true; - self - } - - /// Specifies a changes file to check. - /// - /// # Arguments - /// - /// * `file` - Path to the changes file. - /// - /// # Returns - /// - /// Self with the changes file path set. - pub fn changes_file>(mut self, file: P) -> Self { - self.changes_file_path = Some(format!("{:?}", file.as_ref())); - self - } - - /// Sets the maximum number of tags to display. - /// - /// # Arguments - /// - /// * `limit` - Maximum number of tags to display. - /// - /// # Returns - /// - /// Self with the tag display limit set. - pub fn tag_display_limit(mut self, limit: u32) -> Self { - self.tag_display_limit = Some(limit); - self - } - - /// Configures Lintian to fail on warnings. - /// - /// Can be combined with `fail_on_error()`. - /// - /// # Returns - /// - /// Self with fail-on-warning configured. - pub fn fail_on_warning(mut self) -> Self { - self.fail_on.push("warning".to_string()); - self - } - - /// Configures Lintian to fail on errors. - /// - /// Can be combined with `fail_on_warning()`. - /// - /// # Returns - /// - /// Self with fail-on-error configured. - pub fn fail_on_error(mut self) -> Self { - self.fail_on.push("error".to_string()); - self - } - - /// Configures Lintian for a specific Ubuntu/Debian codename. - /// - /// For certain codenames (jammy, noble), this automatically - /// suppresses the "malformed-deb-archive" tag. - /// - /// # Arguments - /// - /// * `codename` - Ubuntu/Debian codename (e.g., "jammy", "noble"). - /// - /// # Returns - /// - /// Self with codename-specific configuration. - pub fn with_codename(mut self, codename: &Distribution) -> Self { - self.codename = Some(codename.clone()); - - match codename { - Distribution::Debian(_) => {} - Distribution::Ubuntu(_) => self.suppress_tags.push("malformed-deb-archive".to_string()), - } - self - } - - /// Builds the command arguments from struct fields. - /// - /// This method constructs a vector of command-line arguments - /// based on the current configuration of the Lintian object. - /// - /// # Returns - /// - /// A vector of strings representing the command-line arguments. - fn build_args(&self) -> Vec { - let mut args = Vec::new(); - - // Add suppress tags - for tag in &self.suppress_tags { - args.push("--suppress-tags".to_string()); - args.push(tag.clone()); - } - - // Add info flag - if self.show_info { - args.push("-i".to_string()); - } - - // Add extended info flag - if self.extended_info { - args.push("-I".to_string()); - } - - // Add changes file - if let Some(file) = &self.changes_file_path { - args.push(file.clone()); - } - - // Add tag display limit - if let Some(limit) = self.tag_display_limit { - args.push(format!("--tag-display-limit={}", limit)); - } - - // Add fail-on options - for level in &self.fail_on { - args.push(format!("--fail-on={}", level)); - } - - args - } -} - -impl Execute for Lintian { - type Error = LintianError; - /// Executes the lintian command with the configured options. - /// - /// This method builds the arguments based on the current configuration - /// and executes the lintian command. - /// - /// # Returns - /// - /// A result indicating success or an error. - fn execute(&self) -> Result<()> { - let args = self.build_args(); - info!("Running: lintian {}", args.join(" ")); - execute_command("lintian", &args, None)?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - - #[test] - fn test_new() { - let lintian = Lintian::new(); - assert!(lintian.suppress_tags.is_empty()); - assert!(!lintian.show_info); - assert!(!lintian.extended_info); - assert!(lintian.changes_file_path.is_none()); - assert!(lintian.tag_display_limit.is_none()); - assert!(lintian.fail_on.is_empty()); - assert!(lintian.codename.is_none()); - } - - #[test] - fn test_suppress_tag() { - let lintian = Lintian::new().suppress_tag("test-tag"); - assert_eq!(lintian.suppress_tags, vec!["test-tag"]); - } - - #[test] - fn test_info() { - let lintian = Lintian::new().info(); - assert!(lintian.show_info); - } - - #[test] - fn test_extended_info() { - let lintian = Lintian::new().extended_info(); - assert!(lintian.extended_info); - } - - #[test] - fn test_changes_file() { - let path = PathBuf::from("/path/to/file.changes"); - let lintian = Lintian::new().changes_file(&path); - assert_eq!(lintian.changes_file_path, Some(format!("{:?}", path))); - } - - #[test] - fn test_tag_display_limit() { - let lintian = Lintian::new().tag_display_limit(10); - assert_eq!(lintian.tag_display_limit, Some(10)); - } - - #[test] - fn test_fail_on_warning() { - let lintian = Lintian::new().fail_on_warning(); - assert_eq!(lintian.fail_on, vec!["warning".to_string()]); - } - - #[test] - fn test_fail_on_error() { - let lintian = Lintian::new().fail_on_error(); - assert_eq!(lintian.fail_on, vec!["error".to_string()]); - } - - #[test] - fn test_fail_on_both() { - let lintian = Lintian::new().fail_on_warning().fail_on_error(); - assert_eq!( - lintian.fail_on, - vec!["warning".to_string(), "error".to_string()] - ); - } - - #[test] - fn test_with_codename_jammy() { - let lintian = Lintian::new().with_codename(&Distribution::jammy()); - assert_eq!(lintian.codename, Some(Distribution::jammy())); - assert!(lintian - .suppress_tags - .contains(&"malformed-deb-archive".to_string())); - } - - #[test] - fn test_with_codename_other() { - let lintian = Lintian::new().with_codename(&Distribution::bookworm()); - assert_eq!(lintian.codename, Some(Distribution::bookworm())); - assert!(!lintian - .suppress_tags - .contains(&"malformed-deb-archive".to_string())); - } - - #[test] - fn test_build_args() { - let lintian = Lintian::new() - .suppress_tag("tag1") - .suppress_tag("tag2") - .info() - .extended_info() - .changes_file("/path/to/file.changes") - .tag_display_limit(5) - .fail_on_warning(); - - let args = lintian.build_args(); - - assert!(args.contains(&"--suppress-tags".to_string())); - assert!(args.contains(&"tag1".to_string())); - assert!(args.contains(&"tag2".to_string())); - assert!(args.contains(&"-i".to_string())); - assert!(args.contains(&"-I".to_string())); - assert!(args.contains(&format!("{:?}", PathBuf::from("/path/to/file.changes")))); - assert!(args.contains(&"--tag-display-limit=5".to_string())); - assert!(args.contains(&"--fail-on=warning".to_string())); - } - - // #[test] - // fn test_execute() { - // // Setup mock - // let mut mock = MockExecuteCommand::new(); - // mock.expect_call() - // .with( - // eq("lintian"), - // eq(vec!["-i".to_string()]), - // eq(None) - // ) - // .times(1) - // .returning(|_, _, _| Ok(())); - - // // We'd normally replace the actual execute_command with our mock - // // For this test, we're just verifying the arguments - - // let lintian = Lintian::new().info(); - // let args = lintian.build_args(); - - // assert_eq!(args, vec!["-i".to_string()]); - // } - - #[test] - fn test_chaining() { - let lintian = Lintian::new() - .info() - .extended_info() - .suppress_tag("tag1") - .changes_file("file.changes") - .fail_on_error() - .with_codename(&Distribution::noble()); - - assert!(lintian.show_info); - assert!(lintian.extended_info); - assert_eq!(lintian.suppress_tags, vec!["tag1", "malformed-deb-archive"]); - assert_eq!( - lintian.changes_file_path, - Some(format!("{:?}", PathBuf::from("file.changes"))) - ); - assert_eq!(lintian.fail_on, vec!["error".to_string()]); - assert_eq!(lintian.codename, Some(Distribution::noble())); - } -} diff --git a/workspace/debian/src/mod.rs b/workspace/debian/src/mod.rs deleted file mode 100644 index ec7fc526..00000000 --- a/workspace/debian/src/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod autopkgtest; -pub mod autopkgtest_image; -pub mod debcrafter; -pub mod execute; -pub mod lintian; -pub mod piuparts; -pub mod sbuild; -pub mod sbuild_create_chroot; diff --git a/workspace/debian/src/piuparts.rs b/workspace/debian/src/piuparts.rs deleted file mode 100644 index 7bef8295..00000000 --- a/workspace/debian/src/piuparts.rs +++ /dev/null @@ -1,393 +0,0 @@ -use super::execute::{execute_command_with_sudo, Execute, ExecuteError}; -use log::info; -use std::path::Path; -use thiserror::Error; -use types::distribution::{Distribution, UbuntuCodename}; - -/// A builder for the piuparts command, which tests Debian package installation, -/// upgrading, and removal processes. -/// -/// Piuparts (Package Installation, UPgrading And Removal Testing Suite) helps validate -/// Debian packages by testing their installation, upgrade paths, and purging in a clean -/// chroot environment. This struct implements a builder pattern to configure and execute -/// piuparts with various options. -/// -/// # Examples -/// -/// ```rust -/// use std::path::Path; -/// use debian::piuparts::Piuparts; -/// use crate::debian::execute::Execute; -/// use types::distribution::Distribution; -/// -/// // Basic usage -/// let deb_file = Path::new("/path/to/package.deb"); -/// let result = Piuparts::new() -/// .distribution(&Distribution::bookworm()) -/// .mirror("http://deb.debian.org/debian") -/// .verbose() -/// .deb_file(deb_file) -/// .execute(); -/// -/// // With .NET environment setup -/// let result = Piuparts::new() -/// .distribution(&Distribution::bookworm()) -/// .with_dotnet_env(true, &Distribution::bookworm()) -/// .deb_file(deb_file) -/// .execute(); -/// ``` -/// -/// # Note -/// -/// This command requires sudo privileges to run piuparts, as it operates -/// on system package management and creates isolated environments. -pub struct Piuparts<'a> { - /// Distribution codename (e.g., "bookworm", "jammy") - distribution: Option, - /// Mirror URL for package repository - mirror: Option, - /// Paths to bind mount into the chroot - bindmounts: Vec, - /// Path to keyring file for package verification - keyring: Option, - /// Whether to enable verbose output - verbose: bool, - /// Additional repositories to use - extra_repos: Vec, - /// Whether to verify package signatures - verify_signatures: bool, - /// Path to the .deb file to test - deb_file: Option<&'a Path>, - /// Directory containing the .deb file - deb_path: Option<&'a Path>, -} -/// Custom error type for piuparts operations -#[derive(Error, Debug)] -pub enum PiupartsError { - #[error("Deb file not specified")] - MissingDebFile, - - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), -} - -type Result = std::result::Result; - -impl<'a> Piuparts<'a> { - /// Creates a new Piuparts builder with default settings. - /// - /// Default values: - /// - No distribution specified - /// - No mirror specified - /// - No bind mounts - /// - No keyring specified - /// - Verbose mode disabled - /// - No extra repositories - /// - Package signature verification enabled - /// - No .deb file or path specified - pub fn new() -> Self { - Self { - distribution: None, - mirror: None, - bindmounts: Vec::new(), - keyring: None, - verbose: false, - extra_repos: Vec::new(), - verify_signatures: true, - deb_file: None, - deb_path: None, - } - } - - /// Sets the distribution codename (e.g., "bookworm", "jammy"). - /// - /// This corresponds to the `-d` option in piuparts and specifies the - /// Debian/Ubuntu distribution to use for testing. The distribution must - /// be available in the specified mirror. - /// - /// # Arguments - /// - /// * `codename` - The distribution codename (e.g., "bookworm", "jammy", "bullseye") - pub fn distribution(mut self, codename: &Distribution) -> Self { - self.distribution = Some(codename.clone()); - self - } - - /// Sets the mirror URL for the package repository. - /// - /// This corresponds to the `-m` option in piuparts and specifies the - /// package repository mirror to use for downloading packages. - /// - /// # Arguments - /// - /// * `url` - The URL of the repository mirror (e.g., "http://deb.debian.org/debian") - pub fn mirror(mut self, url: &str) -> Self { - self.mirror = Some(url.to_string()); - self - } - - /// Adds /dev to the list of directories to bind mount into the chroot. - /// - /// This corresponds to the `--bindmount=/dev` option in piuparts and allows - /// the chroot environment to access the host's /dev directory. This can be - /// necessary for certain packages that need access to device files. - /// - /// # Note - /// - /// Binding /dev can introduce security risks by giving the chroot - /// environment access to the host's devices. - pub fn bindmount_dev(mut self) -> Self { - self.bindmounts.push("/dev".to_string()); - self - } - - /// Sets the keyring file to use for package verification. - /// - /// This corresponds to the `--keyring` option in piuparts and specifies the - /// GPG keyring file to use for package signature verification. - /// - /// # Arguments - /// - /// * `keyring` - The path to the keyring file - pub fn keyring(mut self, keyring: &str) -> Self { - self.keyring = Some(keyring.to_string()); - self - } - - /// Enables verbose output. - /// - /// This corresponds to the `--verbose` option in piuparts and causes - /// piuparts to output more detailed information during testing, which - /// can be helpful for debugging. - pub fn verbose(mut self) -> Self { - self.verbose = true; - self - } - - /// Adds an additional repository to use. - /// - /// This corresponds to the `--extra-repo` option in piuparts and allows - /// specifying additional package repositories beyond the main mirror. - /// - /// # Arguments - /// - /// * `repo` - The repository definition in sources.list format - /// (e.g., "deb http://security.debian.org/debian-security bookworm-security main") - pub fn extra_repo(mut self, repo: &str) -> Self { - self.extra_repos.push(repo.to_string()); - self - } - - /// Disables package signature verification. - /// - /// This corresponds to the `--do-not-verify-signatures` option in piuparts - /// and disables GPG signature verification for packages. This can be necessary - /// when using unofficial repositories that don't provide properly signed packages. - /// - /// # Security Note - /// - /// Disabling signature verification reduces security by allowing potentially - /// tampered packages to be installed. - pub fn no_verify_signatures(mut self) -> Self { - self.verify_signatures = false; - self - } - - /// Configures the environment for .NET packages if needed. - /// - /// If `is_dotnet` is true and the distribution is either "bookworm" or "jammy jellyfish", - /// adds the Microsoft repository and disables signature verification. - pub fn with_dotnet_env(self, is_dotnet: bool, codename: &Distribution) -> Self { - if !is_dotnet { - return self; - } - - match codename { - Distribution::Debian(debian) => { - let repo = format!( - "deb https://packages.microsoft.com/debian/12/prod {} main", - debian - ); - return self.extra_repo(&repo).no_verify_signatures(); - } - Distribution::Ubuntu(ubuntu_distro) => { - if let UbuntuCodename::Jammy = ubuntu_distro { - let repo = format!( - "deb https://packages.microsoft.com/debian/12/prod {} main", - "jammy" - ); - return self.extra_repo(&repo).no_verify_signatures(); - } - } - } - - self - } - - /// Sets the .deb file to test. - /// - /// This specifies the Debian package file that piuparts will test. - /// This is a required parameter for executing piuparts. - /// - /// # Arguments - /// - /// * `deb_file` - Path to the .deb file to test - pub fn deb_file(mut self, deb_file: &'a Path) -> Self { - self.deb_file = Some(deb_file); - self - } - - /// Sets the directory containing the .deb file. - /// - /// This specifies the directory where the .deb file is located. - /// It can be useful when the execution needs to know the context directory. - /// - /// # Arguments - /// - /// * `deb_path` - Path to the directory containing the .deb file - pub fn deb_path(mut self, deb_path: &'a Path) -> Self { - self.deb_path = Some(deb_path); - self - } - - /// Builds the command-line arguments for piuparts based on the configured options. - /// - /// This method converts the builder's state into a vector of string arguments - /// that can be passed to the piuparts command. It's called internally by the - /// `execute()` method. - /// - /// # Returns - /// - /// A vector of strings representing the command-line arguments - fn build_args(&self) -> Vec { - let mut args = Vec::new(); - - if let Some(dist) = &self.distribution { - args.push("-d".to_string()); - args.push(dist.as_short().into()); - } - - if let Some(mirror_url) = &self.mirror { - args.push("-m".to_string()); - args.push(mirror_url.clone()); - } - - for bindmount in &self.bindmounts { - args.push(format!("--bindmount={}", bindmount)); - } - - if let Some(keyring_path) = &self.keyring { - args.push(format!("--keyring={}", keyring_path)); - } - - if self.verbose { - args.push("--verbose".to_string()); - } - - for repo in &self.extra_repos { - args.push(format!("--extra-repo={}", repo)); - } - - if !self.verify_signatures { - args.push("--do-not-verify-signatures".to_string()); - } - - if let Some(deb_file) = &self.deb_file { - args.push(deb_file.display().to_string()); - } - - args - } -} - -impl<'a> Execute for Piuparts<'a> { - type Error = PiupartsError; - /// Executes the piuparts command with the configured options. - /// - /// Returns an error if the .deb file is not set or if the command fails. - fn execute(&self) -> Result<()> { - let args = self.build_args(); - - - info!( - "Running: sudo -S piuparts {} {:?}", - args.join(" "), - self.deb_file.unwrap() - ); - - execute_command_with_sudo("piuparts", args, self.deb_path)?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_default_piuparts() { - let piuparts = Piuparts::new(); - assert_eq!(piuparts.build_args(), Vec::::new()); - } - - #[test] - fn test_distribution_option() { - let piuparts = Piuparts::new().distribution(&Distribution::bookworm()); - assert_eq!(piuparts.build_args(), vec!["-d", "bookworm"]); - } - - #[test] - fn test_mirror_option() { - let piuparts = Piuparts::new().mirror("http://deb.debian.org/debian"); - assert_eq!( - piuparts.build_args(), - vec!["-m", "http://deb.debian.org/debian"] - ); - } - - #[test] - fn test_multiple_options() { - let piuparts = Piuparts::new() - .distribution(&Distribution::jammy()) - .mirror("http://archive.ubuntu.com/ubuntu") - .verbose() - .bindmount_dev(); - - let args = piuparts.build_args(); - assert!(args.contains(&"-d".to_string())); - assert!(args.contains(&"jammy".to_string())); - assert!(args.contains(&"-m".to_string())); - assert!(args.contains(&"http://archive.ubuntu.com/ubuntu".to_string())); - assert!(args.contains(&"--verbose".to_string())); - assert!(args.contains(&"--bindmount=/dev".to_string())); - } - - #[test] - fn test_dotnet_env_bookworm() { - let piuparts = Piuparts::new().with_dotnet_env(true, &Distribution::bookworm()); - let args = piuparts.build_args(); - - assert!(args.contains( - &"--extra-repo=deb https://packages.microsoft.com/debian/12/prod bookworm main" - .to_string() - )); - assert!(args.contains(&"--do-not-verify-signatures".to_string())); - } - - #[test] - fn test_dotnet_env_no_effect() { - let piuparts = Piuparts::new().with_dotnet_env(true, &Distribution::noble()); - assert_eq!(piuparts.build_args(), Vec::::new()); - - let piuparts = Piuparts::new().with_dotnet_env(false, &Distribution::bookworm()); - assert_eq!(piuparts.build_args(), Vec::::new()); - } - - - #[test] - fn test_deb_file_path() { - let deb_path = Path::new("/tmp/package.deb"); - let piuparts = Piuparts::new().deb_file(&deb_path); - assert_eq!(piuparts.deb_file, Some(deb_path)); - } -} diff --git a/workspace/debian/src/sbuild.rs b/workspace/debian/src/sbuild.rs deleted file mode 100644 index 6ccbd32a..00000000 --- a/workspace/debian/src/sbuild.rs +++ /dev/null @@ -1,401 +0,0 @@ -use super::execute::{execute_command, Execute, ExecuteError}; -use log::info; -use std::path::{Path, PathBuf}; -use thiserror::Error; -use types::distribution::Distribution; - -/// A builder for configuring and executing the sbuild command. -/// -/// This struct allows for fluid configuration of sbuild parameters using -/// the builder pattern. Once configured, the command can be executed -/// via the `Execute` trait implementation. -/// -/// # Example -/// -/// ``` -/// use debian::sbuild::SbuildBuilder; -/// use debian::execute::Execute; -/// use types::distribution::Distribution; -/// -/// let result = SbuildBuilder::new() -/// .distribution(&Distribution::bookworm()) -/// .build_arch_all() -/// .verbose() -/// .execute(); -/// ``` - -#[derive(Default, Debug, Clone)] -pub struct SbuildBuilder { - /// Debian distribution codename (e.g., "bullseye", "bookworm") - distribution: Option, - /// Whether to build architecture-independent packages - build_arch_all: bool, - /// Whether to build source packages only - build_source: bool, - /// Path to the sbuild cache file - cache_file: Option, - /// Whether to enable verbose output - verbose: bool, - /// Whether to use unshare chroot mode - chroot_mode_unshare: bool, - /// Additional setup commands to pass to sbuild - setup_commands: Vec, - /// Whether to run piuparts after building - run_piuparts: bool, - /// Whether to perform apt upgrades before building - apt_upgrades: bool, - /// Whether to run lintian after building (None = use sbuild default) - run_lintian: Option, - /// Whether to run autopkgtest after building - run_autopkgtest: bool, - /// Working directory for the sbuild command - dir: Option, -} - -#[derive(Error, Debug)] -pub enum SbuildCmdError { - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), -} - -type Result = std::result::Result; - -impl SbuildBuilder { - /// Creates a new SbuildBuilder with default settings. - /// - /// Default settings: - /// - No distribution specified - /// - Architecture-independent packages not built - /// - Source packages not built - /// - No cache file specified - /// - Normal (non-verbose) output - /// - Default chroot mode - /// - No additional setup commands - /// - piuparts enabled - /// - apt upgrades enabled - /// - lintian uses sbuild default - /// - autopkgtest enabled - /// - No working directory specified - pub fn new() -> Self { - Self { - distribution: None, - build_arch_all: false, - build_source: false, - cache_file: None, - verbose: false, - chroot_mode_unshare: false, - setup_commands: Vec::new(), - run_piuparts: true, - apt_upgrades: true, - run_lintian: None, - run_autopkgtest: true, - dir: None, - } - } - - /// Sets the target distribution for the build. - /// - /// This corresponds to the `-d` flag in sbuild. - /// - /// # Arguments - /// - /// * `codename` - The Debian distribution codename (e.g., "bullseye", "bookworm") - pub fn distribution(mut self, codename: &Distribution) -> Self { - self.distribution = Some(codename.clone()); - self - } - - /// Enables building of architecture-independent packages. - /// - /// This corresponds to the `-A` flag in sbuild. - pub fn build_arch_all(mut self) -> Self { - self.build_arch_all = true; - self - } - - /// Enables building of source packages only. - /// - /// This corresponds to the `-s` and `--source-only-changes` flags in sbuild. - pub fn build_source(mut self) -> Self { - self.build_source = true; - self - } - - /// Sets the cache file to use for the build. - /// - /// This corresponds to the `-c` flag in sbuild. - /// - /// # Arguments - /// - /// * `cache_file` - Path to the cache file - pub fn cache_file(mut self, cache_file: PathBuf) -> Self { - self.cache_file = Some(cache_file); - self - } - - /// Enables verbose output. - /// - /// This corresponds to the `-v` flag in sbuild. - pub fn verbose(mut self) -> Self { - self.verbose = true; - self - } - - /// Sets the chroot mode to unshare. - /// - /// This corresponds to the `--chroot-mode=unshare` flag in sbuild. - pub fn chroot_mode_unshare(mut self) -> Self { - self.chroot_mode_unshare = true; - self - } - - /// Adds custom setup commands to pass to sbuild. - /// - /// # Arguments - /// - /// * `commands` - List of additional commands to pass to sbuild - pub fn setup_commands(mut self, commands: &[String]) -> Self { - self.setup_commands - .extend(commands.iter().map(|s| s.to_string())); - self - } - - /// Disables running piuparts after building. - /// - /// This corresponds to the `--no-run-piuparts` flag in sbuild. - pub fn no_run_piuparts(mut self) -> Self { - self.run_piuparts = false; - self - } - - /// Disables apt upgrades before building. - /// - /// This corresponds to the `--no-apt-upgrade` and `--no-apt-distupgrade` flags in sbuild. - pub fn no_apt_upgrades(mut self) -> Self { - self.apt_upgrades = false; - self - } - - /// Sets whether to run lintian after building. - /// - /// When enabled, adds several lintian-related flags with common options. - /// When disabled, adds the `--no-run-lintian` flag. - /// - /// # Arguments - /// - /// * `enabled` - Whether to enable or disable lintian - pub fn run_lintian(mut self, enabled: bool) -> Self { - self.run_lintian = Some(enabled); - self - } - - /// Disables running autopkgtest after building. - /// - /// This corresponds to the `--no-run-autopkgtest` flag in sbuild. - pub fn no_run_autopkgtest(mut self) -> Self { - self.run_autopkgtest = false; - self - } - - /// Sets the working directory for the sbuild command. - /// - /// # Arguments - /// - /// * `dir` - Path to the working directory - pub fn working_dir(mut self, dir: &Path) -> Self { - self.dir = Some(dir.to_path_buf()); - self - } - - /// Converts the builder configuration into command-line arguments. - /// - /// This method translates the builder's state into a vector of strings - /// that can be passed to the sbuild command. - /// - /// # Returns - /// - /// A vector of strings representing the sbuild command-line arguments. - fn build_args(&self) -> Vec { - let mut args = Vec::new(); - - if let Some(dist) = &self.distribution { - args.push("-d".to_string()); - args.push(dist.as_short().into()); - } - - if self.build_arch_all { - args.push("-A".to_string()); - } - - if self.build_source { - args.push("-s".to_string()); - args.push("--source-only-changes".to_string()); - } - - if let Some(cache) = &self.cache_file { - args.push("-c".to_string()); - args.push(cache.display().to_string()); - } - - if self.verbose { - args.push("-v".to_string()); - } - - if self.chroot_mode_unshare { - args.push("--chroot-mode=unshare".to_string()); - } - - args.extend(self.setup_commands.clone()); - - if !self.run_piuparts { - args.push("--no-run-piuparts".to_string()); - } - - if !self.apt_upgrades { - args.push("--no-apt-upgrade".to_string()); - args.push("--no-apt-distupgrade".to_string()); - } - - if let Some(enabled) = self.run_lintian { - if enabled { - args.extend([ - "--run-lintian".to_string(), - "--lintian-opt=-i".to_string(), - "--lintian-opt=--I".to_string(), - "--lintian-opt=--suppress-tags".to_string(), - "--lintian-opt=bad-distribution-in-changes-file".to_string(), - "--lintian-opt=--suppress-tags".to_string(), - "--lintian-opt=debug-file-with-no-debug-symbols".to_string(), - "--lintian-opt=--tag-display-limit=0".to_string(), - "--lintian-opts=--fail-on=error".to_string(), - "--lintian-opts=--fail-on=warning".to_string(), - ]); - } else { - args.push("--no-run-lintian".to_string()); - } - } - - if !self.run_autopkgtest { - args.push("--no-run-autopkgtest".to_string()); - } - - args - } -} - -/// Implementation of the Execute trait for SbuildBuilder. -/// -/// This allows the builder to be executed directly after configuration. -impl Execute for SbuildBuilder { - type Error = SbuildCmdError; - /// Executes the sbuild command with the configured options. - /// - /// # Returns - /// - /// Ok(()) if the command executed successfully, or an error if it failed. - /// - /// # Errors - /// - /// Returns an error if the sbuild command fails to execute or returns a non-zero exit code. - fn execute(&self) -> Result<()> { - let args = self.build_args(); - info!("Running: sbuild {}", &args.join(" ")); - execute_command("sbuild", &args, self.dir.as_deref())?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - - #[test] - fn test_new_builder() { - let builder = SbuildBuilder::new(); - assert!(builder.distribution.is_none()); - assert!(!builder.build_arch_all); - assert!(!builder.build_source); - assert!(builder.cache_file.is_none()); - assert!(!builder.verbose); - assert!(!builder.chroot_mode_unshare); - assert!(builder.setup_commands.is_empty()); - assert!(builder.run_piuparts); - assert!(builder.apt_upgrades); - assert!(builder.run_lintian.is_none()); - assert!(builder.run_autopkgtest); - assert!(builder.dir.is_none()); - } - - #[test] - fn test_builder_methods() { - let path = PathBuf::from("/tmp/test"); - let builder = SbuildBuilder::new() - .distribution(&Distribution::bookworm()) - .build_arch_all() - .build_source() - .cache_file("cache.txt".into()) - .verbose() - .chroot_mode_unshare() - .setup_commands(&["--foo".to_string(), "--bar".to_string()]) - .no_run_piuparts() - .no_apt_upgrades() - .run_lintian(true) - .no_run_autopkgtest() - .working_dir(&path); - - assert_eq!(builder.distribution, Some(Distribution::bookworm())); - assert!(builder.build_arch_all); - assert!(builder.build_source); - assert_eq!(builder.cache_file, Some("cache.txt".into())); - assert!(builder.verbose); - assert!(builder.chroot_mode_unshare); - assert_eq!( - builder.setup_commands, - vec!["--foo".to_string(), "--bar".to_string()] - ); - assert!(!builder.run_piuparts); - assert!(!builder.apt_upgrades); - assert_eq!(builder.run_lintian, Some(true)); - assert!(!builder.run_autopkgtest); - assert_eq!(builder.dir, Some(path)); - } - - #[test] - fn test_build_args() { - let builder = SbuildBuilder::new() - .distribution(&Distribution::bookworm()) - .build_arch_all() - .verbose() - .run_lintian(false); - - let args = builder.build_args(); - assert!(args.contains(&"-d".to_string())); - assert!(args.contains(&"bookworm".to_string())); - assert!(args.contains(&"-A".to_string())); - assert!(args.contains(&"-v".to_string())); - assert!(args.contains(&"--no-run-lintian".to_string())); - - // Test with lintian enabled - let builder = SbuildBuilder::new().run_lintian(true); - let args = builder.build_args(); - assert!(args.contains(&"--run-lintian".to_string())); - assert!(args.contains(&"--lintian-opt=-i".to_string())); - } - - #[test] - fn test_custom_commands() { - let commands = vec![ - "--foo=bar".to_string(), - "--baz".to_string(), - "--qux=quux".to_string(), - ]; - - let builder = SbuildBuilder::new().setup_commands(&commands); - let args = builder.build_args(); - - for cmd in commands { - assert!(args.contains(&cmd)); - } - } -} diff --git a/workspace/debian/src/sbuild_create_chroot.rs b/workspace/debian/src/sbuild_create_chroot.rs deleted file mode 100644 index d1e2e17e..00000000 --- a/workspace/debian/src/sbuild_create_chroot.rs +++ /dev/null @@ -1,294 +0,0 @@ -use super::execute::{execute_command, Execute, ExecuteError}; -use log::info; -use std::path::{Path, PathBuf}; -use thiserror::Error; -use types::distribution::Distribution; - -/// Represents options for creating an sbuild chroot environment -/// -/// This struct provides a builder pattern to configure and execute -/// the `sbuild-createchroot` command with various options. -#[derive(Debug, Default)] -pub struct SbuildCreateChroot { - /// The chroot mode (e.g., "schroot", "unshare") - chroot_mode: Option, - /// Whether to create a tarball - make_tarball: bool, - /// Path to the cache file - cache_file: Option, - /// Codename of the distribution (e.g., "bullseye") - codename: Option, - /// Directory to use for temporary files - temp_dir: Option, - /// URL of the repository to use - repo_url: Option, -} - -/// Custom error type for sbuild-createchroot operations -#[derive(Error, Debug)] -pub enum SbuildCreateChrootError { - #[error("Failed to execute command: {0}")] - CommandExecutionError(#[from] ExecuteError), -} - -type Result = std::result::Result; - -impl SbuildCreateChroot { - /// Creates a new instance with default options - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let chroot = SbuildCreateChroot::new(); - /// ``` - pub fn new() -> Self { - Self::default() - } - - /// Sets the chroot mode - /// - /// # Arguments - /// - /// * `mode` - The chroot mode to use (e.g., "schroot", "unshare") - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let chroot = SbuildCreateChroot::new().chroot_mode("unshare"); - /// ``` - pub fn chroot_mode(mut self, mode: &str) -> Self { - self.chroot_mode = Some(mode.to_string()); - self - } - - /// Enables creation of a tarball - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let chroot = SbuildCreateChroot::new().make_tarball(); - /// ``` - pub fn make_tarball(mut self) -> Self { - self.make_tarball = true; - self - } - - /// Sets the cache file path - /// - /// # Arguments - /// - /// * `path` - Path to the cache file - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let chroot = SbuildCreateChroot::new().cache_file(&"/path/to/cache".into()); - /// ``` - pub fn cache_file(mut self, path: &PathBuf) -> Self { - self.cache_file = Some(path.clone()); - self - } - - /// Sets the distribution codename - /// - /// # Arguments - /// - /// * `name` - Codename of the distribution (e.g., "bullseye") - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// use types::distribution::Distribution; - /// let chroot = SbuildCreateChroot::new().codename(&Distribution::bookworm()); - /// ``` - pub fn codename(mut self, name: &Distribution) -> Self { - self.codename = Some(name.clone()); - self - } - - /// Sets the temporary directory - /// - /// # Arguments - /// - /// * `dir` - Path to the temporary directory - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let temp = PathBuf::from("/tmp/sbuild"); - /// let chroot = SbuildCreateChroot::new().temp_dir(&temp); - /// ``` - pub fn temp_dir(mut self, dir: &Path) -> Self { - self.temp_dir = Some(dir.to_string_lossy().to_string()); - self - } - - /// Sets the repository URL - /// - /// # Arguments - /// - /// * `url` - URL of the repository to use - /// - /// # Examples - /// - /// ``` - /// use debian::sbuild_create_chroot::SbuildCreateChroot; - /// let chroot = SbuildCreateChroot::new().repo_url("http://deb.debian.org/debian"); - /// ``` - pub fn repo_url(mut self, url: &str) -> Self { - self.repo_url = Some(url.to_string()); - self - } - - /// Builds the command arguments based on the configured options - fn build_args(&self) -> Vec { - let mut args = Vec::new(); - - if let Some(mode) = &self.chroot_mode { - args.push(format!("--chroot-mode={}", mode)); - } - - if self.make_tarball { - args.push("--make-sbuild-tarball".to_string()); - } - - if let Some(cache) = &self.cache_file { - args.push(cache.display().to_string()); - } - - if let Some(name) = &self.codename { - args.push(name.as_short().into()); - } - - if let Some(dir) = &self.temp_dir { - args.push(dir.clone()); - } - - if let Some(url) = &self.repo_url { - args.push(url.clone()); - } - - args - } -} - -impl Execute for SbuildCreateChroot { - type Error = SbuildCreateChrootError; - /// Executes the sbuild-createchroot command with the configured options - /// - /// # Returns - /// - /// A `Result` indicating success or containing an error - /// - /// # Examples - /// - /// ``` - /// - /// # use debian::sbuild_create_chroot::SbuildCreateChroot; - /// # use debian::sbuild_create_chroot::SbuildCreateChrootError; - /// # use debian::execute::Execute; - /// # use types::distribution::Distribution; - /// # fn run() -> Result<(), SbuildCreateChrootError> { - /// let chroot = SbuildCreateChroot::new() - /// .chroot_mode("unshare") - /// .make_tarball() - /// .codename(&Distribution::bookworm()); - /// - /// chroot.execute()?; - /// # Ok(()) - /// # } - /// ``` - fn execute(&self) -> Result<()> { - let args = self.build_args(); - info!("Running: sbuild-createchroot {}", args.join(" ")); - execute_command("sbuild-createchroot", &args, None)?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::path::PathBuf; - // use mockall::predicate::*; - // use mockall::mock; - - // // Mock the execute_command function - // mock! { - // pub fn ExecuteCommand {} - // impl ExecuteCommand { - // pub fn execute_command(cmd: &str, args: &[String], env: Option<&[(String, String)]>) -> Result<()>; - // } - // } - - #[test] - fn test_default_new() { - let chroot = SbuildCreateChroot::new(); - assert!(chroot.chroot_mode.is_none()); - assert!(!chroot.make_tarball); - assert!(chroot.cache_file.is_none()); - assert!(chroot.codename.is_none()); - assert!(chroot.temp_dir.is_none()); - assert!(chroot.repo_url.is_none()); - } - - #[test] - fn test_build_args_empty() { - let chroot = SbuildCreateChroot::new(); - let args = chroot.build_args(); - assert!(args.is_empty()); - } - - #[test] - fn test_build_args_with_options() { - let temp_path = PathBuf::from("/tmp/sbuild"); - let chroot = SbuildCreateChroot::new() - .chroot_mode("unshare") - .make_tarball() - .cache_file(&"/var/cache/sbuild.tar.gz".into()) - .codename(&Distribution::bookworm()) - .temp_dir(&temp_path) - .repo_url("http://deb.debian.org/debian"); - - let args = chroot.build_args(); - - assert_eq!(args.len(), 6); - assert_eq!(args[0], "--chroot-mode=unshare"); - assert_eq!(args[1], "--make-sbuild-tarball"); - assert_eq!(args[2], "/var/cache/sbuild.tar.gz"); - assert_eq!(args[3], "bookworm"); - assert_eq!(args[4], "/tmp/sbuild"); - assert_eq!(args[5], "http://deb.debian.org/debian"); - } - - // #[test] - // fn test_execute() { - // let mut mock = MockExecuteCommand::new(); - - // // Set up expectations - // mock.expect_execute_command() - // .with( - // eq("sbuild-createchroot"), - // eq(vec!["--chroot-mode=unshare".to_string(), "bullseye".to_string()]), - // eq(None) - // ) - // .times(1) - // .returning(|_, _, _| Ok(())); - - // // Create and execute the command - // let chroot = SbuildCreateChroot::new() - // .chroot_mode("unshare") - // .codename("bullseye"); - - // // This would fail without mocking the actual command execution - // // Here we'd need a way to inject our mock into the execution - // // For a real test, you might use dependency injection or function pointers - // } -} diff --git a/workspace/packager_deb/Cargo.toml b/workspace/packager_deb/Cargo.toml deleted file mode 100644 index 1597f373..00000000 --- a/workspace/packager_deb/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "packager_deb" -version = "0.1.0" -edition = "2021" - -[lib] -name = "packager_deb" -path = "src/mod.rs" - - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -debian = { workspace = true } -types = { workspace = true } -serde = { workspace = true } -thiserror = { workspace = true } -tempfile = { workspace = true } -log = { workspace = true } -dirs = { workspace = true } -rand = { workspace = true } -shellexpand = { workspace = true } -sha2 = { workspace = true } -sha1 = { workspace = true } -filetime = { workspace = true } -cargo_metadata = { workspace = true } -toml = { workspace = true } - - -[dev-dependencies] -toml = { workspace = true } -httpmock = { workspace = true } -env_logger = { workspace = true } diff --git a/workspace/packager_deb/src/.sbuildrc b/workspace/packager_deb/src/.sbuildrc deleted file mode 100644 index c5e57888..00000000 --- a/workspace/packager_deb/src/.sbuildrc +++ /dev/null @@ -1,16 +0,0 @@ -############################################################################## -# PACKAGE BUILD RELATED (source-only-upload as default) -############################################################################## - -$build_environment = { -'HOME' => '' -}; - -$lintian_require_success = 1; -$piuparts_require_success = 1; -$autopkgtest_require_success = 1; - -############################################################################## -# PERL MAGIC -############################################################################## -1; \ No newline at end of file diff --git a/workspace/packager_deb/src/configs/autopkgtest_version.rs b/workspace/packager_deb/src/configs/autopkgtest_version.rs deleted file mode 100644 index 903ca841..00000000 --- a/workspace/packager_deb/src/configs/autopkgtest_version.rs +++ /dev/null @@ -1,121 +0,0 @@ -use cargo_metadata::semver::Version as OriginalVersion; -use serde::{de, Deserialize, Deserializer, Serialize}; -use std::borrow::Cow; -use std::fmt; -use std::ops::{Deref, DerefMut}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct AutopkgtestVersion { - inner: OriginalVersion, - original_string: Cow<'static, str>, -} - -impl fmt::Display for AutopkgtestVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.original_string) - } -} - -impl AutopkgtestVersion { - pub fn as_str(&self) -> &str { - &self.original_string - } - - // Helper to normalize version strings like "2.5" to "0.2.5" - fn normalize_version(s: &str) -> String { - if s.matches('.').count() == 1 { - format!("0.{}", s) - } else { - s.to_string() - } - } - - // Helper to denormalize version strings like "0.2.5" back to "2.5" - fn denormalize_version(s: &str) -> String { - if s.starts_with("0.") { - s[2..].to_string() - } else { - s.to_string() - } - } -} - -impl Serialize for AutopkgtestVersion { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - // Remove the leading "0." if it was added during deserialization - let output = AutopkgtestVersion::denormalize_version(&self.original_string); - serializer.serialize_str(&output) - } -} - -impl Deref for AutopkgtestVersion { - type Target = OriginalVersion; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for AutopkgtestVersion { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl From for AutopkgtestVersion { - fn from(version: OriginalVersion) -> Self { - let original_string = Cow::Owned(version.to_string()); - AutopkgtestVersion { - inner: version, - original_string, - } - } -} - -impl<'a> TryFrom<&'a str> for AutopkgtestVersion { - type Error = cargo_metadata::semver::Error; - fn try_from(s: &'a str) -> Result { - let normalized = AutopkgtestVersion::normalize_version(s); - let inner = OriginalVersion::parse(&normalized)?; - Ok(AutopkgtestVersion { - inner, - original_string: Cow::Owned(s.to_string()), // Keep the original format - }) - } -} - -impl TryFrom for AutopkgtestVersion { - type Error = cargo_metadata::semver::Error; - fn try_from(s: String) -> Result { - >::try_from(&s) - } -} - -impl<'de> Deserialize<'de> for AutopkgtestVersion { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct AutopkgVersionVisitor; - impl<'de> de::Visitor<'de> for AutopkgVersionVisitor { - type Value = AutopkgtestVersion; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a string containing a valid version (e.g., 2.5 or 1.2.3)") - } - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let normalized = AutopkgtestVersion::normalize_version(value); - let inner = OriginalVersion::parse(&normalized).map_err(de::Error::custom)?; - Ok(AutopkgtestVersion { - inner, - original_string: Cow::Owned(value.to_string()), // Keep original format - }) - } - } - deserializer.deserialize_string(AutopkgVersionVisitor) - } -} diff --git a/workspace/packager_deb/src/configs/mod.rs b/workspace/packager_deb/src/configs/mod.rs deleted file mode 100644 index 7477dd78..00000000 --- a/workspace/packager_deb/src/configs/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod autopkgtest_version; -pub mod pkg_config; -pub mod pkg_config_verify; -pub mod sbuild_version; diff --git a/workspace/packager_deb/src/configs/pkg_config.rs b/workspace/packager_deb/src/configs/pkg_config.rs deleted file mode 100644 index 5feb8875..00000000 --- a/workspace/packager_deb/src/configs/pkg_config.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::path::PathBuf; - -use serde::Deserialize; -use types::{config::Architecture, defaults::WORKDIR_ROOT, distribution::Distribution, url::Url, version::Version}; - - -use crate::misc::utils::expand_path; - -use super::{autopkgtest_version::AutopkgtestVersion, sbuild_version::SbuildVersion}; - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct RustConfig { - pub rust_version: Version, - pub rust_binary_url: Url, - pub rust_binary_gpg_asc: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct GoConfig { - pub go_version: Version, - pub go_binary_url: Url, - pub go_binary_checksum: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct JavascriptConfig { - pub node_version: Version, - pub node_binary_url: Url, - pub node_binary_checksum: String, - pub yarn_version: Option, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct GradleConfig { - pub gradle_version: String, - pub gradle_binary_url: Url, - pub gradle_binary_checksum: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct JavaConfig { - pub is_oracle: bool, - pub jdk_version: String, - pub jdk_binary_url: Url, - pub jdk_binary_checksum: String, - pub gradle: Option, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct DotnetPackage { - pub name: String, - pub hash: String, - pub url: Url, -} - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -pub struct DotnetConfig { - pub use_backup_version: bool, - pub dotnet_packages: Vec, - pub deps: Option>, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct NimConfig { - pub nim_version: Version, - pub nim_binary_url: String, - pub nim_version_checksum: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -#[serde(tag = "language_env", rename_all = "lowercase")] -pub enum LanguageEnv { - Rust(RustConfig), - Go(GoConfig), - JavaScript(JavascriptConfig), - Java(JavaConfig), - Dotnet(DotnetConfig), - TypeScript(JavascriptConfig), - Nim(NimConfig), - #[default] - C, - Python, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct DefaultPackageTypeConfig { - pub tarball_url: String, - pub tarball_hash: Option, - pub language_env: LanguageEnv, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct SubModule { - pub commit: String, - pub path: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct GitPackageTypeConfig { - pub git_tag: String, - pub git_url: Url, - pub submodules: Vec, - pub language_env: LanguageEnv, -} - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -#[serde(tag = "package_type", rename_all = "lowercase")] -pub enum PackageType { - Default(DefaultPackageTypeConfig), - Git(GitPackageTypeConfig), - #[default] - Virtual, -} - -impl PackageType { - pub fn get_language_env(&self) -> Option<&LanguageEnv> { - match self { - PackageType::Default(config) => Some(&config.language_env), - PackageType::Git(config) => Some(&config.language_env), - PackageType::Virtual => None, - } - } -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct PackageFields { - pub spec_file: PathBuf, - pub package_name: String, - pub version_number: Version, - pub revision_number: String, - pub homepage: String, -} - - - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct BuildEnv { - pub codename: Distribution, - pub arch: Architecture, - pub pkg_builder_version: Version, - pub debcrafter_version: String, - pub sbuild_cache_dir: Option, - pub docker: Option, - pub run_lintian: Option, - pub run_piuparts: Option, - pub run_autopkgtest: Option, - pub lintian_version: Version, - pub piuparts_version: Version, - pub autopkgtest_version: AutopkgtestVersion, - pub sbuild_version: SbuildVersion, - pub workdir: PathBuf, -} - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub struct PkgConfig { - pub package_fields: PackageFields, - pub package_type: PackageType, - pub build_env: BuildEnv, - pub _config_root: Option, -} - -impl PkgConfig { - pub fn resolve_paths(mut self, config_root: PathBuf) -> Self { - self._config_root = Some(config_root.clone()); - // Set workdir to default if empty - let mut default_work_dir = PathBuf::from(WORKDIR_ROOT); - default_work_dir.push(self.build_env.codename.as_ref()); - - if self.build_env.workdir.as_os_str().is_empty() { - self.build_env.workdir = default_work_dir; - } - - // Expand workdir path - self.build_env.workdir = expand_path(&self.build_env.workdir, None); - - // Update spec file path to canonical form - self.package_fields.spec_file = config_root.join(&self.package_fields.spec_file); - - self - } -} diff --git a/workspace/packager_deb/src/configs/pkg_config_verify.rs b/workspace/packager_deb/src/configs/pkg_config_verify.rs deleted file mode 100644 index 8bc570af..00000000 --- a/workspace/packager_deb/src/configs/pkg_config_verify.rs +++ /dev/null @@ -1,17 +0,0 @@ -use serde::Deserialize; - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -pub struct PackageHash { - pub name: String, - pub hash: String, -} - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -pub struct VerifyConfig { - pub package_hash: Vec, -} - -#[derive(Debug, Deserialize, PartialEq, Clone, Default)] -pub struct PkgVerifyConfig { - pub verify: VerifyConfig, -} diff --git a/workspace/packager_deb/src/configs/sbuild_version.rs b/workspace/packager_deb/src/configs/sbuild_version.rs deleted file mode 100644 index 10aac60a..00000000 --- a/workspace/packager_deb/src/configs/sbuild_version.rs +++ /dev/null @@ -1,134 +0,0 @@ -use cargo_metadata::semver::Version as OriginalVersion; -use serde::{de, Deserialize, Deserializer, Serialize}; -use std::borrow::Cow; -use std::fmt; -use std::ops::{Deref, DerefMut}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SbuildVersion { - inner: OriginalVersion, - original_string: Cow<'static, str>, -} - -impl fmt::Display for SbuildVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.original_string) - } -} - -impl SbuildVersion { - pub fn as_str(&self) -> &str { - &self.original_string - } - - // Extract version from the first line of a string - fn extract_version(s: &str) -> Option { - let first_line = s.lines().next()?; - - if let Some(start_idx) = first_line.find("sbuild (Debian sbuild) ") { - let start_pos = start_idx + "sbuild (Debian sbuild) ".len(); - if let Some(end_idx) = first_line[start_pos..].find(' ') { - return Some(first_line[start_pos..(start_pos + end_idx)].to_string()); - } else { - return Some(first_line[start_pos..].trim().to_string()); - } - } - None - } -} - -impl Serialize for SbuildVersion { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.original_string) - } -} - -impl Deref for SbuildVersion { - type Target = OriginalVersion; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for SbuildVersion { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl From for SbuildVersion { - fn from(version: OriginalVersion) -> Self { - let original_string = Cow::Owned(version.to_string()); - SbuildVersion { - inner: version, - original_string, - } - } -} - -impl<'a> TryFrom<&'a str> for SbuildVersion { - type Error = cargo_metadata::semver::Error; - fn try_from(s: &'a str) -> Result { - let version_str = if s.contains("sbuild") { - SbuildVersion::extract_version(s) - .unwrap_or_else(|| s.lines().next().unwrap_or(s).to_string()) - } else { - s.to_string() - }; - - let inner = OriginalVersion::parse(&version_str)?; - Ok(SbuildVersion { - inner, - original_string: Cow::Owned(version_str), - }) - } -} - -impl TryFrom for SbuildVersion { - type Error = cargo_metadata::semver::Error; - fn try_from(s: String) -> Result { - >::try_from(&s) - } -} - -impl<'de> Deserialize<'de> for SbuildVersion { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct SbuildVersionVisitor; - impl<'de> de::Visitor<'de> for SbuildVersionVisitor { - type Value = SbuildVersion; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str( - "a string containing a valid version, possibly in a multiline string", - ) - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let version_str = if value.contains("sbuild") { - SbuildVersion::extract_version(value).ok_or_else(|| { - de::Error::custom("Could not extract version from the first line") - })? - } else { - value.to_string() - }; - - let inner = OriginalVersion::parse(&version_str).map_err(de::Error::custom)?; - Ok(SbuildVersion { - inner, - original_string: Cow::Owned(version_str), - }) - } - } - - deserializer.deserialize_string(SbuildVersionVisitor) - } -} diff --git a/workspace/packager_deb/src/handler.rs b/workspace/packager_deb/src/handler.rs deleted file mode 100644 index 90ee2d9c..00000000 --- a/workspace/packager_deb/src/handler.rs +++ /dev/null @@ -1,90 +0,0 @@ -use thiserror::Error; - -use types::{ - config::{Config, ConfigError, ConfigFile, ConfigType}, - debian::DebCommandPayload, - defaults::{CONFIG_FILE_NAME, VERIFY_CONFIG_FILE_NAME}, -}; - -use crate::{ - configs::{pkg_config::PkgConfig, pkg_config_verify::PkgVerifyConfig}, - misc::{build_pipeline::BuildError, validation::ValidationError}, - sbuild::{Sbuild, SbuildError}, -}; - -impl ConfigType for PkgVerifyConfig { - fn default_config_path() -> &'static str { - VERIFY_CONFIG_FILE_NAME - } -} - -impl ConfigType for PkgConfig { - fn default_config_path() -> &'static str { - CONFIG_FILE_NAME - } -} - -#[derive(Debug, Error)] -pub enum PackageError { - #[error(transparent)] - BuildError(#[from] BuildError), - #[error(transparent)] - SbuildError(#[from] SbuildError), - #[error(transparent)] - ConfigError(#[from] ConfigError), - #[error(transparent)] - ValidationError(#[from] ValidationError), -} - -pub fn dispatch_package_operation( - config: ConfigFile, - cmd_payload: DebCommandPayload, -) -> Result<(), PackageError> { - // ReParse config first - let mut pkg_config = - ConfigFile::::load_and_parse(Some(config.path.display().to_string()))? - .resolve_paths(config.path.parent().unwrap().to_path_buf()); - - // Apply CLI overrides if needed - if let DebCommandPayload::Package { - run_autopkgtest, - run_lintian, - run_piuparts, - } = &cmd_payload - { - if let Some(run_piuparts_value) = run_piuparts { - pkg_config.build_env.run_piuparts = Some(*run_piuparts_value); - } - if let Some(run_autopkgtest_value) = run_autopkgtest { - pkg_config.build_env.run_autopkgtest = Some(*run_autopkgtest_value); - } - if let Some(run_lintian_value) = run_lintian { - pkg_config.build_env.run_lintian = Some(*run_lintian_value); - } - } - - // do not run piuparts or autopkgtest on verify - if let DebCommandPayload::Verify { .. } = &cmd_payload { - pkg_config.build_env.run_piuparts = Some(false); - pkg_config.build_env.run_autopkgtest = Some(false); - } - - let packager: Sbuild = pkg_config.try_into()?; - match cmd_payload { - DebCommandPayload::Verify { - verify_config, - no_package, - } => { - let pkg_verify_config_file = - ConfigFile::::load_and_parse(verify_config)?; - packager.run_verify(pkg_verify_config_file, no_package.unwrap_or_default()) - } - DebCommandPayload::Lintian => packager.run_lintian(), - DebCommandPayload::Piuparts => packager.run_piuparts(), - DebCommandPayload::Autopkgtest => packager.run_autopkgtests(), - DebCommandPayload::Package { .. } => packager.run_package(), - DebCommandPayload::EnvCreate => packager.run_env_create(), - DebCommandPayload::EnvClean => packager.run_env_clean(), - }?; - Ok(()) -} diff --git a/workspace/packager_deb/src/installers/command_builder.rs b/workspace/packager_deb/src/installers/command_builder.rs deleted file mode 100644 index 92c7fb5d..00000000 --- a/workspace/packager_deb/src/installers/command_builder.rs +++ /dev/null @@ -1,39 +0,0 @@ -pub struct CommandBuilder { - commands: Vec, -} - -impl CommandBuilder { - pub fn new() -> Self { - Self { - commands: Vec::new(), - } - } - - pub fn add(&mut self, cmd: impl Into) -> &mut Self { - self.commands.push(cmd.into()); - self - } - - pub fn add_with(&mut self, template: &str, replacement: &str) -> &mut Self { - let cmd = template.replace("{}", replacement); - self.commands.push(cmd); - self - } - - pub fn add_with_args(&mut self, template: &str, args: &[&str]) -> &mut Self { - // Format the string with positional arguments - let mut result = template.to_string(); - for arg in args { - // Replace the first occurrence of {} with the argument - if let Some(pos) = result.find("{}") { - result.replace_range(pos..pos + 2, arg); - } - } - self.commands.push(result); - self - } - - pub fn build(self) -> Vec { - self.commands - } -} diff --git a/workspace/packager_deb/src/installers/dotnet_installer.rs b/workspace/packager_deb/src/installers/dotnet_installer.rs deleted file mode 100644 index 1f4e1777..00000000 --- a/workspace/packager_deb/src/installers/dotnet_installer.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::{config::Architecture, distribution::{Distribution, UbuntuCodename}}; - -use crate::configs::pkg_config::DotnetConfig; - -use super::{command_builder::CommandBuilder, language_installer::LanguageInstaller}; - -pub struct DotnetInstaller(pub(crate) DotnetConfig); - -impl LanguageInstaller for DotnetInstaller { - fn recipe(&self) -> Cow<'static, str> { - let recipe = include_str!("../recipes/dotnet_installer.sh"); - Cow::Borrowed(&recipe) - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let subs = HashMap::new(); - subs - } - fn get_build_deps(&self, arch: &Architecture, codename: &Distribution) -> Vec { - let dotnet_packages = &self.0.dotnet_packages; - let deps = self.0.deps.clone().unwrap_or_default(); - let mut builder = CommandBuilder::new(); - - if self.0.use_backup_version { - builder - .add("apt install -y wget") - .add("apt install -y libicu-dev"); - - for package in deps { - builder.add_with("apt install -y {}", &package); - } - - for package in dotnet_packages { - builder - .add_with("cd /tmp && wget -q {}", &package.url.as_ref()) - .add_with("cd /tmp && ls && dpkg -i {}.deb", &package.name) - .add_with("cd /tmp && ls && sha1sum {}.deb", &package.name) - .add_with_args( - "cd /tmp && echo {} {}.deb > hash_file.txt && cat hash_file.txt", - &[&package.hash, &package.name], - ) - .add("cd /tmp && sha1sum -c hash_file.txt"); - } - - builder.add("dotnet --version").add("apt remove -y wget"); - } else { - match codename { - Distribution::Debian(_) | Distribution::Ubuntu(UbuntuCodename::Jammy) => { - builder - .add("apt install -y wget") - .add("cd /tmp && wget -q https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb") - .add("cd /tmp && dpkg -i packages-microsoft-prod.deb") - .add("apt update -y"); - - for package in dotnet_packages { - let pkg = transform_name(&package.name, arch); - builder - .add_with("cd /tmp && wget -q {}", &package.url.as_ref()) - .add_with("cd /tmp && apt install -y --allow-downgrades {}", &pkg) - .add_with("cd /tmp && apt download -y {}", &pkg) - .add_with("cd /tmp && ls && sha1sum {}.deb", &package.name) - .add_with_args( - "cd /tmp && echo {} {}.deb >> hash_file.txt && cat hash_file.txt", - &[&package.hash, &package.name], - ) - .add("cd /tmp && sha1sum -c hash_file.txt"); - } - - builder.add("dotnet --version").add("apt remove -y wget"); - } - Distribution::Ubuntu(UbuntuCodename::Noble) => { - builder - .add("apt-get install software-properties-common -y") - .add("add-apt-repository ppa:dotnet/backports") - .add("apt-get update -y") - .add("apt install -y wget"); - - for package in dotnet_packages { - let pkg = transform_name(&package.name, arch); - builder - .add_with("cd /tmp && wget -q {}", &package.url.as_ref()) - .add_with("cd /tmp && apt install -y {}", &pkg) - .add_with("cd /tmp && apt download -y {}", &pkg) - .add_with("cd /tmp && ls && sha1sum {}.deb", &package.name) - .add_with_args( - "cd /tmp && echo {} {}.deb >> hash_file.txt && cat hash_file.txt", - &[&package.hash, &package.name], - ) - .add("cd /tmp && sha1sum -c hash_file.txt"); - } - - builder.add("dotnet --version").add("apt remove -y wget"); - } - } - } - - builder.build() - } - fn get_test_deps(&self, codename: &Distribution) -> Vec { - let mut builder = CommandBuilder::new(); - - match codename { - Distribution::Debian(_) | Distribution::Ubuntu(UbuntuCodename::Jammy) => { - builder - .add("apt install -y wget") - .add("cd /tmp && wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb") - .add("cd /tmp && dpkg -i packages-microsoft-prod.deb") - .add("apt-get update -y") - .add("apt remove -y wget"); - - builder.build() - } - Distribution::Ubuntu(UbuntuCodename::Noble) => { - vec![] - } - } - } -} - -fn transform_name(input: &str, arch: &Architecture) -> String { - if let Some(pos) = input.find(format!("_{}", arch).as_str()) { - let trimmed = &input[..pos]; - trimmed.replace('_', "=") - } else { - input.replace('_', "=") - } -} diff --git a/workspace/packager_deb/src/installers/empty_installer.rs b/workspace/packager_deb/src/installers/empty_installer.rs deleted file mode 100644 index 6552bc6d..00000000 --- a/workspace/packager_deb/src/installers/empty_installer.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use super::language_installer::LanguageInstaller; - -pub struct EmptyInstaller; - -impl LanguageInstaller for EmptyInstaller { - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] - } - - fn recipe(&self) -> Cow<'static, str> { - Cow::Borrowed("") - } - - fn substitutions(&self) -> HashMap<&str, &str> { - HashMap::new() - } -} diff --git a/workspace/packager_deb/src/installers/go_installer.rs b/workspace/packager_deb/src/installers/go_installer.rs deleted file mode 100644 index 1eaaf108..00000000 --- a/workspace/packager_deb/src/installers/go_installer.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use crate::configs::pkg_config::GoConfig; - -use super::language_installer::LanguageInstaller; - -pub struct GoInstaller(pub(crate) GoConfig); - -impl LanguageInstaller for GoInstaller { - fn recipe(&self) -> Cow<'static, str> { - let recipe = include_str!("../recipes/go_installer.sh"); - Cow::Borrowed(recipe) - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let mut subs = HashMap::new(); - subs.insert("${go_binary_url}", self.0.go_binary_url.as_str()); - subs.insert("${go_binary_checksum}", self.0.go_binary_checksum.as_str()); - subs - } - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] - } -} diff --git a/workspace/packager_deb/src/installers/java_installer.rs b/workspace/packager_deb/src/installers/java_installer.rs deleted file mode 100644 index b74875f4..00000000 --- a/workspace/packager_deb/src/installers/java_installer.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use crate::configs::pkg_config::JavaConfig; - -use super::language_installer::LanguageInstaller; - -pub struct JavaInstaller(pub(crate) JavaConfig); - -impl LanguageInstaller for JavaInstaller { - fn recipe(&self) -> Cow<'static, str> { - let java_installer = include_str!("../recipes/java_installer.sh"); - if let Some(_) = &self.0.gradle { - let java_gradle_installer = include_str!("../recipes/java_gradle_installer.sh"); - let installer = java_installer.to_string() + java_gradle_installer; - Cow::Owned(installer) - } else { - Cow::Borrowed(java_installer) - } - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let mut subs = HashMap::new(); - subs.insert("${jdk_version}", self.0.jdk_version.as_str()); - subs.insert("${jdk_binary_url}", &self.0.jdk_binary_url.as_str()); - subs.insert( - "${jdk_binary_checksum}", - &self.0.jdk_binary_checksum.as_str(), - ); - if let Some(gradle_config) = &self.0.gradle { - let gradle_version = &gradle_config.gradle_version; - let gradle_binary_url = &gradle_config.gradle_binary_url; - let gradle_binary_checksum = &gradle_config.gradle_binary_checksum; - subs.insert("${gradle_version}", &gradle_version.as_str()); - subs.insert("${gradle_binary_url}", &gradle_binary_url.as_str()); - subs.insert( - "${gradle_binary_checksum}", - &gradle_binary_checksum.as_str(), - ); - } - subs - } - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] - } -} diff --git a/workspace/packager_deb/src/installers/language_installer.rs b/workspace/packager_deb/src/installers/language_installer.rs deleted file mode 100644 index 67c43885..00000000 --- a/workspace/packager_deb/src/installers/language_installer.rs +++ /dev/null @@ -1,50 +0,0 @@ -use types::{config::Architecture, distribution::Distribution}; - -use super::{ - command_builder::CommandBuilder, dotnet_installer::DotnetInstaller, - empty_installer::EmptyInstaller, go_installer::GoInstaller, java_installer::JavaInstaller, - nim_installer::NimInstaller, node_installer::NodeInstaller, rust_installer::RustInstaller, -}; -use crate::configs::pkg_config::LanguageEnv; -use std::{borrow::Cow, collections::HashMap}; - -pub trait LanguageInstaller { - fn recipe(&self) -> Cow<'static, str>; - fn substitutions(&self) -> HashMap<&str, &str>; - - fn get_build_deps(&self, _arch: &Architecture, _codename: &Distribution) -> Vec { - let mut builder = CommandBuilder::new(); - let recipe = self.recipe(); - let substitutions = self.substitutions(); - - for line in recipe.lines() { - let command = line.trim(); - let mut processed_command = String::from(command); - - for (placeholder, value) in &substitutions { - processed_command = processed_command.replace(placeholder, value); - } - - builder.add(&processed_command); - } - - builder.build() - } - fn get_test_deps(&self, codename: &Distribution) -> Vec; -} - -impl From for Box { - fn from(lang_env: LanguageEnv) -> Self { - match lang_env { - LanguageEnv::Rust(config) => Box::new(RustInstaller(config.clone())), - LanguageEnv::Go(config) => Box::new(GoInstaller(config.clone())), - LanguageEnv::JavaScript(config) | LanguageEnv::TypeScript(config) => { - Box::new(NodeInstaller(config.clone())) - } - LanguageEnv::Java(config) => Box::new(JavaInstaller(config.clone())), - LanguageEnv::Dotnet(config) => Box::new(DotnetInstaller(config.clone())), - LanguageEnv::Nim(config) => Box::new(NimInstaller(config.clone())), - _ => Box::new(EmptyInstaller), - } - } -} diff --git a/workspace/packager_deb/src/installers/mod.rs b/workspace/packager_deb/src/installers/mod.rs deleted file mode 100644 index f80b6153..00000000 --- a/workspace/packager_deb/src/installers/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod command_builder; -mod dotnet_installer; -mod empty_installer; -mod go_installer; -mod java_installer; -pub mod language_installer; -mod nim_installer; -mod node_installer; -mod rust_installer; diff --git a/workspace/packager_deb/src/installers/nim_installer.rs b/workspace/packager_deb/src/installers/nim_installer.rs deleted file mode 100644 index 1ea102d4..00000000 --- a/workspace/packager_deb/src/installers/nim_installer.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use crate::configs::pkg_config::NimConfig; - -use super::language_installer::LanguageInstaller; - -pub struct NimInstaller(pub(crate) NimConfig); - -impl LanguageInstaller for NimInstaller { - fn recipe(&self) -> Cow<'static, str> { - let recipe = include_str!("../recipes/nim_installer.sh"); - Cow::Borrowed(recipe) - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let mut subs = HashMap::new(); - subs.insert("${nim_binary_url}", self.0.nim_binary_url.as_str()); - subs.insert("${nim_version}", &self.0.nim_version.as_str()); - subs.insert( - "${nim_version_checksum}", - &self.0.nim_version_checksum.as_str(), - ); - subs - } - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] - } -} diff --git a/workspace/packager_deb/src/installers/node_installer.rs b/workspace/packager_deb/src/installers/node_installer.rs deleted file mode 100644 index 3f2b52f7..00000000 --- a/workspace/packager_deb/src/installers/node_installer.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use crate::configs::pkg_config::JavascriptConfig; - -use super::language_installer::LanguageInstaller; - -pub struct NodeInstaller(pub(crate) JavascriptConfig); -impl LanguageInstaller for NodeInstaller { - fn recipe(&self) -> Cow<'static, str> { - let recipe = include_str!("../recipes/node_installer.sh"); - if let Some(_) = &self.0.yarn_version { - let yarn_installer = include_str!("../recipes/yarn_installer.sh"); - let installer = recipe.to_string() + yarn_installer; - Cow::Owned(installer) - } else { - Cow::Borrowed(recipe) - } - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let mut subs = HashMap::new(); - subs.insert( - "${node_binary_checksum}", - self.0.node_binary_checksum.as_str(), - ); - subs.insert("${node_binary_url}", &self.0.node_binary_url.as_str()); - subs.insert("${node_version}", &&self.0.node_version.as_str()); - if let Some(yarn_version) = &self.0.yarn_version { - subs.insert("${yarn_version}", &yarn_version.as_str()); - } - subs - } - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] - } -} diff --git a/workspace/packager_deb/src/installers/rust_installer.rs b/workspace/packager_deb/src/installers/rust_installer.rs deleted file mode 100644 index ce8f3886..00000000 --- a/workspace/packager_deb/src/installers/rust_installer.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use types::distribution::Distribution; - -use crate::configs::pkg_config::RustConfig; - -use super::language_installer::LanguageInstaller; - -pub struct RustInstaller(pub(crate) RustConfig); - -impl LanguageInstaller for RustInstaller { - fn recipe(&self) -> Cow<'static, str> { - let recipe = include_str!("../recipes/rust_installer.sh"); - Cow::Borrowed(recipe) - } - - fn substitutions(&self) -> HashMap<&str, &str> { - let mut subs = HashMap::new(); - subs.insert("${rust_binary_url}", self.0.rust_binary_url.as_str()); - subs.insert( - "${rust_binary_gpg_asc}", - self.0.rust_binary_gpg_asc.as_str(), - ); - subs - } - - fn get_test_deps(&self, _codename: &Distribution) -> Vec { - vec![] // Rust compiles to binary, no test deps needed - } -} diff --git a/workspace/packager_deb/src/misc/build_pipeline.rs b/workspace/packager_deb/src/misc/build_pipeline.rs deleted file mode 100644 index 3360e201..00000000 --- a/workspace/packager_deb/src/misc/build_pipeline.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::path::PathBuf; - -use debian::debcrafter::DebcrafterCmdError; -use thiserror::Error; - -use crate::{ - configs::pkg_config::SubModule, - steps::{create_empty_tar::CreateEmptyTarError, dowload_git::DownloadGitError}, -}; - -#[derive(Debug, Default, Clone)] -pub struct BuildContext { - pub tarball_url: String, - pub tarball_hash: String, - pub tarball_path: PathBuf, - pub build_files_dir: PathBuf, - pub debcrafter_version: String, - pub homepage: String, - pub build_artifacts_dir: PathBuf, - pub spec_file: PathBuf, - pub src_dir: PathBuf, - // only for git package - pub package_name: String, - pub git_tag: String, - pub git_url: String, - pub submodules: Vec, -} - -#[derive(Error, Debug)] -pub enum BuildError { - #[error("Command execution failed: {0}")] - CommandFailed(String), - - #[error("Download failed")] - DownloadFailed, - - #[error("File copy failed: {0}")] - FileCopyFailed(String), - - #[error(transparent)] - IoError(#[from] std::io::Error), - - #[error("Failed to open tarball: {0}")] - TarballOpenError(String), - - #[error("Failed to read tarball: {0}")] - TarballReadError(String), - - #[error("Checksum verification failed: hashes do not match")] - HashMismatchError, - - #[error("Extraction error: {0}")] - ExtractionError(String), - - #[error(transparent)] - DebcrafterError(#[from] DebcrafterCmdError), - - #[error("Failed to copy src directory: {0}")] - CopyDirectory(String), - - #[error("Failed to get debian/rules permission")] - RulesPermissionGet, - - #[error("Failed to set debian/rules permission")] - RulesPermissionSet, - - #[error("Home directory not found")] - HomeDirNotFound, - - #[error("Failed to create ~/.sbuildrc: {0}")] - FileCreationError(String), - - #[error("Failed to write to ~/.sbuildrc: {0}")] - FileWriteError(String), - - #[error(transparent)] - DownloadGitStepError(#[from] DownloadGitError), - - #[error(transparent)] - CreateEmptyTarStepError(#[from] CreateEmptyTarError), -} - -pub trait BuildStep { - fn step(&self) -> Result<(), BuildError>; -} - -#[derive(Default)] -pub struct BuildPipeline { - handlers: Vec>, -} - -impl BuildPipeline { - pub fn new() -> Self { - Self::default() - } - - pub fn add_step(&mut self, handler: T) -> &mut Self { - self.handlers.push(Box::new(handler)); - self - } - - pub fn execute(&self) -> Result<(), BuildError> { - for handler in &self.handlers { - handler.step()?; - } - Ok(()) - } -} diff --git a/workspace/packager_deb/src/misc/distribution.rs b/workspace/packager_deb/src/misc/distribution.rs deleted file mode 100644 index c57f3db3..00000000 --- a/workspace/packager_deb/src/misc/distribution.rs +++ /dev/null @@ -1,22 +0,0 @@ -use types::distribution::Distribution; - -pub trait DistributionTrait { - fn get_keyring(&self) -> &str; - fn get_repo_url(&self) -> &str; -} - -impl DistributionTrait for Distribution { - fn get_keyring(&self) -> &str { - match &self { - Distribution::Debian(_) => "/usr/share/keyrings/debian-archive-keyring.gpg", - Distribution::Ubuntu(_) => "/usr/share/keyrings/ubuntu-archive-keyring.gpg", - } - } - - fn get_repo_url(&self) -> &str { - match &self { - Distribution::Debian(_) => "http://deb.debian.org/debian", - Distribution::Ubuntu(_) => "http://archive.ubuntu.com/ubuntu", - } - } -} diff --git a/workspace/packager_deb/src/misc/mod.rs b/workspace/packager_deb/src/misc/mod.rs deleted file mode 100644 index db9c9197..00000000 --- a/workspace/packager_deb/src/misc/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod build_pipeline; -pub mod distribution; -pub mod sbuild_pipelines; -pub mod utils; -pub mod validation; diff --git a/workspace/packager_deb/src/misc/sbuild_pipelines.rs b/workspace/packager_deb/src/misc/sbuild_pipelines.rs deleted file mode 100644 index 19d379f9..00000000 --- a/workspace/packager_deb/src/misc/sbuild_pipelines.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::{ - misc::build_pipeline::{BuildContext, BuildError, BuildPipeline}, - steps::{ - create_debian_dir::CreateDebianDir, create_empty_tar::CreateEmptyTar, - dowload_git::DownloadGit, download_source::DownloadSource, extract_source::ExtractSource, - package_dir_setup::PackageDirSetup, patch_source::PatchSource, setup_sbuild::SetupSbuild, - verify_hash::VerifyHash, - }, -}; - -#[derive(Default)] -pub struct SbuildSourcePipeline { - context: BuildContext, -} - -impl SbuildSourcePipeline { - pub fn new(context: BuildContext) -> Self { - SbuildSourcePipeline { context } - } - - pub fn execute(self) -> Result<(), BuildError> { - let mut pipeline = BuildPipeline::new(); - let package_dir_handle = PackageDirSetup::from(self.context.clone()); - let download_source_handle = DownloadSource::from(self.context.clone()); - let verify_hash_handle = VerifyHash::from(self.context.clone()); - let extract_source_handle = ExtractSource::from(self.context.clone()); - let create_deb_dir: CreateDebianDir = CreateDebianDir::from(self.context.clone()); - let patch_source_handle = PatchSource::from(self.context.clone()); - let setup_sbuild_handle = SetupSbuild::from(self.context.clone()); - - pipeline - .add_step(package_dir_handle) - .add_step(download_source_handle) - .add_step(verify_hash_handle) - .add_step(extract_source_handle) - .add_step(create_deb_dir) - .add_step(patch_source_handle) - .add_step(setup_sbuild_handle); - - pipeline.execute()?; - Ok(()) - } -} - -#[derive(Default)] -pub struct SbuildGitPipeline { - context: BuildContext, -} - -impl SbuildGitPipeline { - pub fn new(context: BuildContext) -> Self { - SbuildGitPipeline { context } - } - - pub fn execute(self) -> Result<(), BuildError> { - let mut pipeline = BuildPipeline::new(); - let package_dir_handle = PackageDirSetup::from(self.context.clone()); - let download_git_step = DownloadGit::from(self.context.clone()); - let extract_source_handle = ExtractSource::from(self.context.clone()); - let create_deb_dir: CreateDebianDir = CreateDebianDir::from(self.context.clone()); - let patch_source_handle = PatchSource::from(self.context.clone()); - let setup_sbuild_handle = SetupSbuild::from(self.context.clone()); - - pipeline - .add_step(package_dir_handle) - .add_step(download_git_step) - .add_step(extract_source_handle) - .add_step(create_deb_dir) - .add_step(patch_source_handle) - .add_step(setup_sbuild_handle); - - pipeline.execute()?; - Ok(()) - } -} - -#[derive(Default)] -pub struct SbuildVirtualPipeline { - context: BuildContext, -} - -impl SbuildVirtualPipeline { - pub fn new(context: BuildContext) -> Self { - SbuildVirtualPipeline { context } - } - - pub fn execute(self) -> Result<(), BuildError> { - let mut pipeline = BuildPipeline::new(); - let package_dir_handle = PackageDirSetup::from(self.context.clone()); - let empty_tar_handle = CreateEmptyTar::from(self.context.clone()); - let extract_source_handle = ExtractSource::from(self.context.clone()); - let create_deb_dir: CreateDebianDir = CreateDebianDir::from(self.context.clone()); - let patch_source_handle = PatchSource::from(self.context.clone()); - let setup_sbuild_handle = SetupSbuild::from(self.context.clone()); - - pipeline - .add_step(package_dir_handle) - .add_step(empty_tar_handle) - .add_step(extract_source_handle) - .add_step(create_deb_dir) - .add_step(patch_source_handle) - .add_step(setup_sbuild_handle); - - pipeline.execute()?; - Ok(()) - } -} diff --git a/workspace/packager_deb/src/misc/utils.rs b/workspace/packager_deb/src/misc/utils.rs deleted file mode 100644 index 0ac3892c..00000000 --- a/workspace/packager_deb/src/misc/utils.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::{ - env, fs::{self, create_dir_all, remove_dir_all, remove_file}, path::{Path, PathBuf} -}; - -use crate::sbuild::SbuildError; -use sha1::{Digest, Sha1}; - -pub fn calculate_sha1(data: &[u8]) -> Result { - let mut hasher = Sha1::new(); - hasher.update(data); - Ok(hasher - .finalize() - .iter() - .map(|b| format!("{:02x}", b)) - .collect()) -} - -pub fn ensure_parent_dir>(path: T) -> Result<(), SbuildError> { - let parent = Path::new(path.as_ref()) - .parent() - .ok_or(SbuildError::GenericError(format!( - "Invalid path: {:?}", - path.as_ref() - )))?; - create_dir_all(parent)?; - Ok(()) -} -pub fn remove_file_or_directory(path: &PathBuf, is_dir: bool) -> Result<(), SbuildError> { - if Path::new(path).exists() { - if is_dir { - remove_dir_all(path)?; - } else { - remove_file(path)?; - } - } - Ok(()) -} - -pub fn expand_path(dir: &PathBuf, dir_to_expand: Option<&PathBuf>) -> PathBuf { - if dir.to_string_lossy().starts_with('~') { - let dir_str = dir.to_string_lossy(); - PathBuf::from(shellexpand::tilde(&dir_str).to_string()) - } else if dir.is_absolute() { - dir.clone() - } else { - let parent_dir = match dir_to_expand { - None => env::current_dir().unwrap(), - Some(path) => path.clone(), - }; - - let path = parent_dir.join(dir); - fs::canonicalize(path.clone()).unwrap_or(path) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn expand_path_expands_tilde_correctly() { - let tilde = PathBuf::from("~"); - let result = expand_path(&tilde, None); - assert_ne!(result, tilde); - assert!(!result.display().to_string().contains('~')); - } - - #[test] - fn expand_path_handles_absolute_paths() { - let absolute_path = PathBuf::from("/absolute/path"); - let result = expand_path(&absolute_path, None); - assert_eq!(result, absolute_path); - } - - #[test] - fn expand_path_expands_relative_paths_with_parent() { - let file = PathBuf::from("somefile"); - let mut tmp = PathBuf::from("/tmp"); - let result = expand_path(&file, Some(&tmp)); - tmp.push(file); - assert_eq!(result, tmp); - } - - #[test] - fn expand_path_expands_relative_paths_without_parent() { - let file = PathBuf::from("somefile"); - - let result = expand_path(&file, None); - assert!(result.display().to_string().starts_with('/')); - } -} \ No newline at end of file diff --git a/workspace/packager_deb/src/misc/validation.rs b/workspace/packager_deb/src/misc/validation.rs deleted file mode 100644 index 26bc18e5..00000000 --- a/workspace/packager_deb/src/misc/validation.rs +++ /dev/null @@ -1,19 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum ValidationError { - #[error("Field: '{0}' cannot be empty")] - EmptyField(String), - - #[error("Validation failed: {0}")] - Multiple(String), - - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("TOML parsing error: {0}")] - TomlParse(#[from] toml::de::Error), - - #[error("Package hash cannot be empty")] - EmptyPackageHash, -} diff --git a/workspace/packager_deb/src/mod.rs b/workspace/packager_deb/src/mod.rs deleted file mode 100644 index aa588967..00000000 --- a/workspace/packager_deb/src/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod configs; -pub mod handler; -mod installers; -mod misc; -pub mod sbuild; -mod sbuild_args; -mod steps; -mod tools; diff --git a/workspace/packager_deb/src/recipes/dotnet_installer.sh b/workspace/packager_deb/src/recipes/dotnet_installer.sh deleted file mode 100644 index e69de29b..00000000 diff --git a/workspace/packager_deb/src/recipes/go_installer.sh b/workspace/packager_deb/src/recipes/go_installer.sh deleted file mode 100644 index 6df320fb..00000000 --- a/workspace/packager_deb/src/recipes/go_installer.sh +++ /dev/null @@ -1,9 +0,0 @@ -apt install -y wget -cd /tmp && wget -q -O go.tar.gz ${go_binary_url} -cd /tmp && echo "${go_binary_checksum} go.tar.gz" >> hash_file.txt && cat hash_file.txt -cd /tmp && sha256sum -c hash_file.txt -cd /tmp && rm -rf /usr/local/go && mkdir /usr/local/go && tar -C /usr/local -xzf go.tar.gz -ln -s /usr/local/go/bin/go /usr/bin/go -go version -chmod -R a+rwx /usr/local/go/pkg -apt remove -y wget diff --git a/workspace/packager_deb/src/recipes/java_gradle_installer.sh b/workspace/packager_deb/src/recipes/java_gradle_installer.sh deleted file mode 100644 index 35a84f06..00000000 --- a/workspace/packager_deb/src/recipes/java_gradle_installer.sh +++ /dev/null @@ -1,9 +0,0 @@ -apt install -y wget unzip -mkdir -p /opt/lib/gradle-${gradle_version} -cd /tmp && wget -q --output-document gradle.tar.gz ${gradle_binary_url} -cd /tmp && echo "${gradle_binary_checksum} gradle.tar.gz" > hash_file.txt && cat hash_file.txt -cd /tmp && sha256sum -c hash_file.txt -cd /tmp && unzip gradle.tar.gz && mv gradle-${gradle_version} /opt/lib -ln -s /opt/lib/gradle-${gradle_version}/bin/gradle /usr/bin/gradle -gradle -version -apt remove -y wget \ No newline at end of file diff --git a/workspace/packager_deb/src/recipes/java_installer.sh b/workspace/packager_deb/src/recipes/java_installer.sh deleted file mode 100644 index 6404d4e3..00000000 --- a/workspace/packager_deb/src/recipes/java_installer.sh +++ /dev/null @@ -1,10 +0,0 @@ -apt install -y wget -mkdir -p /opt/lib/jvm/jdk-${jdk_version}-oracle && mkdir -p /usr/lib/jvm -cd /tmp && wget -q --output-document jdk.tar.gz ${jdk_binary_url} -cd /tmp && echo "${jdk_binary_checksum} jdk.tar.gz" >>hash_file.txt && cat hash_file.txt -cd /tmp && sha256sum -c hash_file.txt -cd /tmp && tar -zxf jdk.tar.gz -C /opt/lib/jvm/jdk-${jdk_version}-oracle --strip-components=1 -ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/java /usr/bin/java -ln -s /opt/lib/jvm/jdk-${jdk_version}-oracle/bin/javac /usr/bin/javac -java -version -apt remove -y wget diff --git a/workspace/packager_deb/src/recipes/nim_installer.sh b/workspace/packager_deb/src/recipes/nim_installer.sh deleted file mode 100644 index 60821ac0..00000000 --- a/workspace/packager_deb/src/recipes/nim_installer.sh +++ /dev/null @@ -1,11 +0,0 @@ -apt install -y wget -rm -rf /tmp/nim-${nim_version} && rm -rf /usr/lib/nim/nim-${nim_version} && rm -rf /opt/lib/nim/nim-${nim_version} && mkdir /tmp/nim-${nim_version} -mkdir -p /opt/lib/nim && mkdir -p /usr/lib/nim -cd /tmp && wget -q ${nim_binary_url} -cd /tmp && echo ${nim_version_checksum} >> hash_file.txt && cat hash_file.txt -cd /tmp && sha256sum -c hash_file.txt -cd /tmp && tar xJf nim-${nim_version}-linux_x64.tar.xz -C nim-${nim_version} --strip-components=1 -cd /tmp && mv nim-${nim_version} /opt/lib/nim -ln -s /opt/lib/nim/nim-${nim_version}/bin/nim /usr/bin/nim -nim --version -apt remove -y wget diff --git a/workspace/packager_deb/src/recipes/node_installer.sh b/workspace/packager_deb/src/recipes/node_installer.sh deleted file mode 100644 index 8932bd56..00000000 --- a/workspace/packager_deb/src/recipes/node_installer.sh +++ /dev/null @@ -1,13 +0,0 @@ -apt install -y wget -cd /tmp && wget -q -O node.tar.gz ${node_binary_url} -cd /tmp && echo "${node_binary_checksum} node.tar.gz" >> hash_file.txt && cat hash_file.txt -cd /tmp && sha256sum -c hash_file.txt -cd /tmp && rm -rf /usr/share/node && mkdir /usr/share/node && tar -C /usr/share/node -xzf node.tar.gz --strip-components=1 -ls -l /usr/share/node/bin -ln -s /usr/share/node/bin/node /usr/bin/node -ln -s /usr/share/node/bin/npm /usr/bin/npm -ln -s /usr/share/node/bin/npx /usr/bin/npx -ln -s /usr/share/node/bin/corepack /usr/bin/corepack -apt remove -y wget -node --version -npm --version diff --git a/workspace/packager_deb/src/recipes/rust_installer.sh b/workspace/packager_deb/src/recipes/rust_installer.sh deleted file mode 100644 index ba3b65e1..00000000 --- a/workspace/packager_deb/src/recipes/rust_installer.sh +++ /dev/null @@ -1,8 +0,0 @@ -apt install -y wget gpg gpg-agent -cd /tmp && wget -q -O package.tar.xz ${rust_binary_url} -cd /tmp && echo "${rust_binary_gpg_asc}" >> package.tar.xz.asc -wget -qO- https://keybase.io/rust/pgp_keys.asc | gpg --import -cd /tmp && gpg --verify package.tar.xz.asc package.tar.xz -cd /tmp && tar xvJf package.tar.xz -C . --strip-components=1 -cd /tmp && /bin/bash install.sh -apt remove -y wget gpg gpg-agent \ No newline at end of file diff --git a/workspace/packager_deb/src/recipes/yarn_installer.sh b/workspace/packager_deb/src/recipes/yarn_installer.sh deleted file mode 100644 index 53fedf01..00000000 --- a/workspace/packager_deb/src/recipes/yarn_installer.sh +++ /dev/null @@ -1,3 +0,0 @@ -npm install --global yarn@${yarn_version} -ln -s /usr/share/node/bin/yarn /usr/bin/yarn -yarn --version \ No newline at end of file diff --git a/workspace/packager_deb/src/sbuild.rs b/workspace/packager_deb/src/sbuild.rs deleted file mode 100644 index 896eeaa9..00000000 --- a/workspace/packager_deb/src/sbuild.rs +++ /dev/null @@ -1,310 +0,0 @@ -use crate::configs::pkg_config::PkgConfig; -use crate::configs::pkg_config_verify::PkgVerifyConfig; -use crate::misc::build_pipeline::BuildError; -use crate::misc::distribution::DistributionTrait; -use crate::misc::utils::{calculate_sha1, ensure_parent_dir, remove_file_or_directory}; -use crate::sbuild_args::SbuildArgs; -use crate::tools::autopkgtest_tool::AutopkgtestTool; -use crate::tools::lintian_tool::LintianTool; -use crate::tools::piuparts_tool::PiupartsTool; -use crate::tools::sbuild_tool::SbuildTool; -use crate::tools::tool_runner::ToolRunner; -use debian::autopkgtest::AutopkgtestError; -use debian::autopkgtest_image::AutopkgtestImageError; -use debian::execute::Execute; -use debian::lintian::LintianError; -use debian::piuparts::PiupartsError; -use debian::sbuild::SbuildCmdError; -use debian::sbuild_create_chroot::{SbuildCreateChroot, SbuildCreateChrootError}; -use log::info; -use rand::random; -use std::path::Path; -use std::{env, fs}; -use thiserror::Error; - -pub struct Sbuild { - args: SbuildArgs, -} - -impl TryFrom for Sbuild { - type Error = SbuildError; - - fn try_from(config: PkgConfig) -> Result { - let args: SbuildArgs = SbuildArgs::try_from(config)?; - Ok(Sbuild { args }) - } -} - -#[derive(Debug, Error)] -pub enum SbuildError { - #[error(transparent)] - IoError(#[from] std::io::Error), - #[error(transparent)] - SbuildCreateChrootError(#[from] SbuildCreateChrootError), - - #[error(transparent)] - AutopkgtestImageError(#[from] AutopkgtestImageError), - - #[error(transparent)] - PiupartsError(#[from] PiupartsError), - - #[error(transparent)] - LintianError(#[from] LintianError), - - #[error(transparent)] - AutopkgtestError(#[from] AutopkgtestError), - - #[error(transparent)] - SbuildCmdError(#[from] SbuildCmdError), - - #[error("Verification error: {0}")] - VerificationError(String), - - #[error("{0}")] - GenericError(String), - - #[error(transparent)] - SemverError(#[from] cargo_metadata::semver::Error), - - #[error(transparent)] - BuildError(#[from] BuildError), -} - -impl Sbuild { - pub fn run_env_clean(&self) -> Result<(), SbuildError> { - let cache_file = self.args.get_cache_file(); - info!("Cleaning cached build: {:?}", cache_file); - remove_file_or_directory(&cache_file, false)?; - Ok(()) - } - - pub fn run_env_create(&self) -> Result<(), SbuildError> { - let temp_dir = env::temp_dir().join(format!("temp_{}", random::())); - fs::create_dir(&temp_dir)?; - - let cache_file = self.args.get_cache_file(); - ensure_parent_dir(&cache_file)?; - - let codename = &self.args.codename(); - - SbuildCreateChroot::new() - .chroot_mode("unshare") - .make_tarball() - .cache_file(&cache_file) - .codename(codename) - .temp_dir(&temp_dir) - .repo_url(codename.get_repo_url()) - .execute()?; - - Ok(()) - } - - pub fn run_package(&self) -> Result<(), SbuildError> { - let args = self.args.get_sbuild_tool_args(); - - let tool = SbuildTool::new(args); - ToolRunner::new().run_tool(tool)?; - if self.args.run_piuparts() { - self.run_piuparts()?; - } - if self.args.run_autopkgtests() { - self.run_autopkgtests()?; - } - Ok(()) - } - - pub fn run_verify( - &self, - verify_config: PkgVerifyConfig, - no_package: bool, - ) -> Result<(), SbuildError> { - if !no_package { - self.run_package()?; - } - let output_dir = - Path::new(self.args.build_files_dir()) - .parent() - .ok_or(SbuildError::GenericError( - "Invalid build files dir".to_string(), - ))?; - - let errors: Vec<_> = verify_config - .verify - .package_hash - .iter() - .filter_map(|output| { - let file_path = output_dir.join(&output.name); - if !file_path.exists() { - return Some(format!("Verification file missing: {}", output.name)); - } - - let buffer = match std::fs::read(&file_path) { - Ok(buf) => buf, - Err(_) => return Some(format!("Failed to read file: {}", output.name)), - }; - - let actual_sha1 = match calculate_sha1(&buffer) { - Ok(hash) => hash, - Err(_) => { - return Some(format!("Failed to calculate hash for: {}", output.name)) - } - }; - - (actual_sha1 != output.hash).then(|| { - format!( - "SHA1 mismatch for {}: expected {}, got {}", - output.name, output.hash, actual_sha1 - ) - }) - }) - .collect(); - - if errors.is_empty() { - info!("Verification successful!"); - Ok(()) - } else { - // Convert the error collection to a proper error - Err(SbuildError::VerificationError(errors.join("; "))) - } - } - - pub fn run_lintian(&self) -> Result<(), SbuildError> { - let args = self.args.get_lintian_tool_args(); - let tool = LintianTool::new(args); - ToolRunner::new().run_tool(tool) - } - - pub fn run_piuparts(&self) -> Result<(), SbuildError> { - let args = self.args.get_piuparts_tool_args(); - let tool = PiupartsTool::new(args); - ToolRunner::new().run_tool(tool) - } - - pub fn run_autopkgtests(&self) -> Result<(), SbuildError> { - let args = self.args.get_autopkg_tool_args(); - let tool = AutopkgtestTool::new(args); - ToolRunner::new().run_tool(tool) - } -} - -#[cfg(test)] -mod tests { - - use crate::configs::autopkgtest_version::AutopkgtestVersion; - use crate::configs::pkg_config::{ - BuildEnv, DefaultPackageTypeConfig, LanguageEnv, PackageFields, PackageType, - }; - use crate::configs::sbuild_version::SbuildVersion; - - use super::*; - use env_logger::Env; - use types::config::Architecture; - use std::fs::{create_dir_all, File}; - use std::path::{Path, PathBuf}; - use std::sync::Once; - use tempfile::tempdir; - use types::distribution::Distribution; - use types::version::Version; - - static INIT: Once = Once::new(); - - // Initialize logger once for all tests - fn setup() { - INIT.call_once(|| { - env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); - }); - } - - fn create_base_config() -> PkgConfig { - let sbuild_cache_dir = tempdir().unwrap().path().to_path_buf(); - let config = PkgConfig { - package_fields: PackageFields { - spec_file: "".into(), - package_name: "".into(), - version_number: Version::try_from("1.0.0").unwrap(), - revision_number: "".into(), - homepage: "".into(), - }, - package_type: PackageType::Default(DefaultPackageTypeConfig { - tarball_url: "test.tar.gz".into(), - tarball_hash: Some("".into()), - language_env: LanguageEnv::C, - }), - build_env: BuildEnv { - codename: Distribution::bookworm(), - arch: Architecture::Amd64, - pkg_builder_version: Version::try_from("1.0.0").unwrap(), - debcrafter_version: "1.0.0".into(), - sbuild_cache_dir: Some(sbuild_cache_dir.clone()), - docker: None, - run_lintian: None, - run_piuparts: None, - run_autopkgtest: None, - lintian_version: Version::try_from("1.0.0").unwrap(), - piuparts_version: Version::try_from("1.0.0").unwrap(), - autopkgtest_version: AutopkgtestVersion::try_from("2.5").unwrap(), - sbuild_version: SbuildVersion::try_from( - "sbuild (Debian sbuild) 0.85.6 (26 February 2024)", - ) - .unwrap(), - workdir: PathBuf::from(""), - }, - _config_root: Some(tempdir().unwrap().path().to_path_buf()), - }; - - config - } - - #[test] - fn test_clean_when_file_missing() { - setup(); - let config = create_base_config(); - let args = SbuildArgs::try_from(config).unwrap(); - let build_env = Sbuild { args: args.clone() }; - - let result = build_env.run_env_clean(); - let cache_file = args.get_cache_file(); - - assert!(result.is_ok()); - assert!(!Path::new(&cache_file).exists()); - } - - #[test] - fn test_clean_with_existing_file() { - setup(); - let config = create_base_config(); - let cache_dir = config.build_env.sbuild_cache_dir.clone().unwrap(); - - let args = SbuildArgs::try_from(config).unwrap(); - - let build_env = Sbuild { args: args.clone() }; - let cache_file = args.get_cache_file(); - - create_dir_all(cache_dir).unwrap(); - File::create(&cache_file).unwrap(); - assert!(Path::new(&cache_file).exists()); - - let result = build_env.run_env_clean(); - assert!(result.is_ok()); - assert!(!Path::new(&cache_file).exists()); - } - - #[test] - #[ignore = "Only run on CI"] - fn test_create_environment() { - setup(); - let config = create_base_config(); - - let args = SbuildArgs::try_from(config).unwrap(); - - let build_env = Sbuild { args: args.clone() }; - let cache_file = args.get_cache_file(); - - build_env.run_env_clean().unwrap(); - assert!(!Path::new(&cache_file).exists()); - - let result = build_env.run_env_create(); - assert!(result.is_ok()); - assert!(Path::new(&cache_file).exists()); - } -} diff --git a/workspace/packager_deb/src/sbuild_args.rs b/workspace/packager_deb/src/sbuild_args.rs deleted file mode 100644 index d5f2ffa9..00000000 --- a/workspace/packager_deb/src/sbuild_args.rs +++ /dev/null @@ -1,522 +0,0 @@ -use std::{ - convert::TryFrom, - path::{Path, PathBuf}, -}; - -use types::{config::Architecture, defaults::WORKDIR_ROOT, distribution::Distribution, version::Version}; - -use crate::{ - configs::{ - autopkgtest_version::AutopkgtestVersion, - pkg_config::{LanguageEnv, PackageType, PkgConfig}, - sbuild_version::SbuildVersion, - }, - installers::language_installer::LanguageInstaller, - misc::{build_pipeline::BuildContext, utils::expand_path}, - tools::{ - autopkgtest_tool::AutopkgtestToolArgs, lintian_tool::LintianToolArgs, - piuparts_tool::PiupartsToolArgs, sbuild_tool::SbuildToolArgs, - }, -}; - -#[derive(Debug, Clone)] -pub struct SbuildArgs { - cache_dir: PathBuf, - build_files_dir: PathBuf, - codename: Distribution, - run_lintian: bool, - run_autopkgtests: bool, - run_piuparts: bool, - lintian_version: Version, - piuparts_version: Version, - autopkgtest_version: AutopkgtestVersion, - sbuild_version: SbuildVersion, - package_type: PackageType, - arch: Architecture, - context: BuildContext, - deb_dir: PathBuf, - deb_name: PathBuf, - changes_file: PathBuf, - cache_file: PathBuf, - language_env: Option, - test_deps_not_in_debian: Vec, - chroot_setup_commands: Vec, -} - -impl TryFrom for SbuildArgs { - type Error = std::io::Error; - - fn try_from(config: PkgConfig) -> Result { - let config_root = config._config_root.unwrap(); - // Cache directory - let cache_dir = config - .build_env - .sbuild_cache_dir - .clone() - .unwrap_or_else(|| PathBuf::from("~/.cache/sbuild")); - - let cache_dir = expand_path(&cache_dir, None); - - // Build context - let package_fields = &config.package_fields; - let config_root_path = PathBuf::from(config_root.clone()); - let source_to_patch_from_path = config_root_path.join("src").to_str().unwrap().to_string(); - - let mut workdir = config.build_env.workdir.clone(); - let mut default_work_dir = PathBuf::from(WORKDIR_ROOT); - default_work_dir.push(config.build_env.codename.as_ref()); - if workdir.as_os_str().is_empty() { - workdir = default_work_dir; - } - let workdir = expand_path(&workdir, None); - - let build_artifacts_dir = { - let build_artifacts_dir = format!( - "{}/{}-{}-{}", - workdir.display().to_string(), - &package_fields.package_name, - package_fields.version_number.as_str(), - &package_fields.revision_number - ); - PathBuf::from(build_artifacts_dir) - }; - - let debian_orig_tarball_path = { - let tarball_path = format!( - "{}/{}_{}.orig.tar.gz", - &build_artifacts_dir.display().to_string(), - &package_fields.package_name, - &package_fields.version_number - ); - PathBuf::from(tarball_path) - }; - - let build_files_dir = { - let build_files_dir = format!( - "{}/{}-{}", - build_artifacts_dir.display().to_string(), - &package_fields.package_name, - &package_fields.version_number - ); - PathBuf::from(build_files_dir) - }; - - let mut context = BuildContext { - build_artifacts_dir, - build_files_dir: build_files_dir.clone(), - debcrafter_version: config.build_env.debcrafter_version.as_str().to_string(), - homepage: package_fields.homepage.clone(), - spec_file: package_fields.spec_file.clone(), - tarball_hash: String::new(), - tarball_url: String::new(), - src_dir: source_to_patch_from_path.into(), - tarball_path: debian_orig_tarball_path, - package_name: package_fields.package_name.clone(), - git_tag: String::new(), - git_url: String::new(), - submodules: vec![], - }; - - match &config.package_type { - PackageType::Default(default_config) => { - context.tarball_url = { - let tarball_url = default_config.tarball_url.as_str(); - if tarball_url.starts_with("http") { - tarball_url.to_string() - } else { - expand_path( - &PathBuf::from(tarball_url), - Some(&PathBuf::from(&config_root.clone())), - ) - .display() - .to_string() - } - }; - - if let Some(hash) = &default_config.tarball_hash { - context.tarball_hash = hash.clone(); - } - } - PackageType::Git(git_config) => { - context.git_tag = git_config.git_tag.clone(); - context.git_url = git_config.git_url.as_str().to_string(); - context.submodules = git_config.submodules.clone(); - } - PackageType::Virtual => { - // Virtual packages already have the correct default values - } - } - - // Extract other fields from config - let run_lintian = config.build_env.run_lintian.unwrap_or(false); - let run_autopkgtests = config.build_env.run_piuparts.unwrap_or(false); - let run_piuparts = config.build_env.run_piuparts.unwrap_or(false); - let lintian_version = config.build_env.lintian_version.clone(); - let piuparts_version = config.build_env.piuparts_version.clone(); - let autopkgtest_version = config.build_env.autopkgtest_version.clone(); - let sbuild_version = config.build_env.sbuild_version.clone(); - let package_type = config.package_type.clone(); - let arch = config.build_env.arch.clone(); - let package_name = package_fields.package_name.clone(); - let package_version_number = package_fields.version_number.clone(); - let revision_number = package_fields.revision_number.clone(); - - // Generate derived paths - let deb_dir = PathBuf::from(&build_files_dir) - .parent() - .unwrap() - .to_path_buf(); - - let deb_name = { - let filename = format!( - "{}_{}-{}_{}.{}", - &package_name, &package_version_number, &revision_number, &arch, "deb" - ); - deb_dir.join(filename) - }; - - let changes_file = { - let filename = format!( - "{}_{}-{}_{}.{}", - &package_name, &package_version_number, &revision_number, &arch, "changes" - ); - deb_dir.join(filename) - }; - - let cache_file = { - let dir = shellexpand::tilde(&cache_dir.display().to_string()).to_string(); - let codename = &config.build_env.codename.as_short(); - let cache_file_name = format!("{}-{}.tar.gz", codename, &arch); - Path::new(&dir).join(cache_file_name) - }; - - // Get language environment - let language_env = match &package_type { - PackageType::Default(config) => Some(config.language_env.clone()), - PackageType::Git(config) => Some(config.language_env.clone()), - PackageType::Virtual => None, - }; - - // Build deps - let build_deps_not_in_debian = match &language_env { - Some(env) => { - let installer: Box = env.clone().into(); - installer.get_build_deps(&arch, &config.build_env.codename) - } - None => vec![], - }; - - // Test deps - let test_deps_not_in_debian = match &language_env { - Some(env) => { - let installer: Box = env.clone().into(); - installer.get_test_deps(&config.build_env.codename) - } - None => vec![], - }; - - // Chroot setup commands - let mut chroot_setup_commands = build_deps_not_in_debian.clone(); - if config.build_env.codename == Distribution::noble() { - chroot_setup_commands.extend(vec![ - "apt install -y software-properties-common".to_string(), - "add-apt-repository universe".to_string(), - "add-apt-repository restricted".to_string(), - "add-apt-repository multiverse".to_string(), - "apt update".to_string(), - ]); - } - let chroot_setup_commands = chroot_setup_commands - .into_iter() - .map(|dep| format!("--chroot-setup-commands={}", dep)) - .collect(); - - Ok(SbuildArgs { - cache_dir, - build_files_dir, - codename: config.build_env.codename, - run_lintian, - run_autopkgtests, - run_piuparts, - lintian_version, - piuparts_version, - autopkgtest_version, - sbuild_version, - package_type, - arch, - context, - deb_dir, - deb_name, - changes_file, - cache_file, - language_env, - test_deps_not_in_debian, - chroot_setup_commands, - }) - } -} - -impl SbuildArgs { - pub fn get_sbuild_tool_args(&self) -> SbuildToolArgs { - let version = self.sbuild_version.clone(); - let codename = self.codename.clone(); - let cache_file = self.cache_file.clone(); - let build_chroot_setup_commands = self.chroot_setup_commands.clone(); - let build_files_dir = self.build_files_dir.clone(); - let package_type = self.package_type.clone(); - let context = self.context.clone(); - SbuildToolArgs { - version, - codename, - cache_file, - build_chroot_setup_commands, - build_files_dir, - package_type, - context, - run_lintian: self.run_lintian, - } - } - - pub fn get_autopkg_tool_args(&self) -> AutopkgtestToolArgs { - let version = self.autopkgtest_version.clone(); - let changes_file = self.changes_file.clone(); - let codename = self.codename.clone(); - let deb_dir = self.deb_dir.clone(); - let test_deps = self.test_deps_not_in_debian.clone(); - let cache_dir = self.cache_dir.clone(); - let arch = self.arch.clone(); - - AutopkgtestToolArgs { - version, - changes_file, - codename, - deb_dir, - test_deps, - image_path: None, - cache_dir, - arch, - } - } - pub fn get_lintian_tool_args(&self) -> LintianToolArgs { - let version = self.lintian_version.clone(); - let changes_file = self.changes_file.clone(); - let codename = self.codename.clone(); - - LintianToolArgs { - version, - changes_file, - codename, - } - } - pub fn get_piuparts_tool_args(&self) -> PiupartsToolArgs { - let version = self.piuparts_version.clone(); - let codename = self.codename.clone(); - let deb_dir = self.deb_dir.clone(); - let deb_name = self.deb_name.clone(); - let language_env = self.language_env.clone(); - PiupartsToolArgs { - version, - codename, - deb_dir, - language_env, - deb_name, - } - } - - pub fn build_files_dir(&self) -> &PathBuf { - &self.build_files_dir - } - pub fn codename(&self) -> &Distribution { - &self.codename - } - - pub fn run_autopkgtests(&self) -> bool { - self.run_autopkgtests - } - pub fn run_piuparts(&self) -> bool { - self.run_piuparts - } - - pub fn get_cache_file(&self) -> PathBuf { - self.cache_file.clone() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::configs::autopkgtest_version::AutopkgtestVersion; - use crate::configs::pkg_config::{ - BuildEnv, DefaultPackageTypeConfig, DotnetConfig, LanguageEnv, PackageFields, PackageType, - }; - use crate::configs::sbuild_version::SbuildVersion; - use std::convert::TryFrom; - use std::path::PathBuf; - use types::distribution::Distribution; - use types::version::Version; - - fn create_test_pkg_config() -> PkgConfig { - let config = PkgConfig { - package_fields: PackageFields { - spec_file: "hello-world-dotnet.sss".into(), - package_name: "hello-world".into(), - version_number: Version::try_from("1.0.0").unwrap(), - revision_number: "1".into(), - homepage: "http://example.com".into(), - }, - package_type: PackageType::Default(DefaultPackageTypeConfig { - tarball_url: "test.tar.gz".into(), - tarball_hash: Some("".into()), - language_env: LanguageEnv::Dotnet(DotnetConfig { - dotnet_packages: vec![], - use_backup_version: false, - deps: None, - }), - }), - build_env: BuildEnv { - codename: Distribution::bookworm(), - arch: Architecture::Amd64, - pkg_builder_version: Version::try_from("1.0.0").unwrap(), - debcrafter_version: "1.0.0".into(), - sbuild_cache_dir: None, - docker: None, - run_lintian: None, - run_piuparts: None, - run_autopkgtest: None, - lintian_version: Version::try_from("1.0.0").unwrap(), - piuparts_version: Version::try_from("1.0.0").unwrap(), - autopkgtest_version: AutopkgtestVersion::try_from("2.5").unwrap(), - sbuild_version: SbuildVersion::try_from( - "sbuild (Debian sbuild) 0.85.6 (26 February 2024)", - ) - .unwrap(), - workdir: PathBuf::from("/tmp/workdir/packages"), - }, - _config_root: Some("/test/config/root".into()), - }; - - config - } - - #[test] - fn test_cache_dir_set_to_default() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - // Test all fields - assert_eq!( - args.cache_dir.display().to_string(), - shellexpand::tilde("~/.cache/sbuild").to_string() - ); - } - - #[test] - fn test_cache_dir_overriden() { - let mut config = create_test_pkg_config(); - config.build_env.sbuild_cache_dir = Some(PathBuf::from("/test/cache/dir")); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - // Test all fields - assert_eq!( - args.cache_dir.display().to_string(), - shellexpand::tilde("/test/cache/dir").to_string() - ); - } - - #[test] - fn test_deb_name_construction() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_deb_name = PathBuf::from( - "/tmp/workdir/packages/hello-world-1.0.0-1/hello-world_1.0.0-1_amd64.deb", - ); - assert_eq!( - args.deb_name, - expected_deb_name, - "deb_name should be correctly constructed from package name, version, revision, and arch" - ); - } - - #[test] - fn test_changes_file_construction() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_changes_file = PathBuf::from( - "/tmp/workdir/packages/hello-world-1.0.0-1/hello-world_1.0.0-1_amd64.changes", - ); - assert_eq!( - args.changes_file, - expected_changes_file, - "changes_file should be correctly constructed from package name, version, revision, and arch" - ); - } - - #[test] - fn test_cache_file_construction() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_cache_file = - PathBuf::from(shellexpand::tilde("~/.cache/sbuild/bookworm-amd64.tar.gz").to_string()); - assert_eq!( - args.get_cache_file(), - expected_cache_file, - "cache_file should be constructed from cache_dir, codename, and arch" - ); - } - - #[test] - fn test_deb_dir_construction() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_deb_dir = PathBuf::from("/tmp/workdir/packages/hello-world-1.0.0-1"); - assert_eq!( - args.deb_dir, expected_deb_dir, - "deb_dir should be the parent directory of build_files_dir" - ); - } - - #[test] - fn test_build_files_dir_construction() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_build_files_dir = - PathBuf::from("/tmp/workdir/packages/hello-world-1.0.0-1/hello-world-1.0.0"); - assert_eq!( - args.build_files_dir(), - &expected_build_files_dir, - "build_files_dir should be constructed from workdir, package name, and version" - ); - } - - #[test] - fn test_context_tarball_url_local_path() { - let config = create_test_pkg_config(); - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_tarball_url = "/test/config/root/test.tar.gz".to_string(); - assert_eq!( - args.context.tarball_url, expected_tarball_url, - "tarball_url should be expanded relative to config_root for local paths" - ); - } - - #[test] - fn test_context_tarball_url_http() { - let mut config = create_test_pkg_config(); - if let PackageType::Default(ref mut default_config) = config.package_type { - default_config.tarball_url = "https://example.com/test.tar.gz".into(); - } - let args = SbuildArgs::try_from(config.clone()).unwrap(); - - let expected_tarball_url = "https://example.com/test.tar.gz".to_string(); - assert_eq!( - args.context.tarball_url, expected_tarball_url, - "tarball_url should remain unchanged for HTTP URLs" - ); - } -} diff --git a/workspace/packager_deb/src/steps/create_debian_dir.rs b/workspace/packager_deb/src/steps/create_debian_dir.rs deleted file mode 100644 index 360cf9b8..00000000 --- a/workspace/packager_deb/src/steps/create_debian_dir.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::path::PathBuf; - -use debian::debcrafter::DebcrafterCmd; -use log::info; - -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; - -#[derive(Default)] -pub struct CreateDebianDir { - build_files_dir: PathBuf, - debcrafter_version: String, - spec_file: PathBuf, -} - -impl From for CreateDebianDir { - fn from(context: BuildContext) -> Self { - CreateDebianDir { - build_files_dir: context.build_files_dir.clone(), - debcrafter_version: context.debcrafter_version.clone(), - spec_file: context.spec_file.clone(), - } - } -} - -impl BuildStep for CreateDebianDir { - fn step(&self) -> Result<(), BuildError> { - let debcrafter = DebcrafterCmd::new(self.debcrafter_version.as_str()); - debcrafter.check_if_dpkg_parsechangelog_installed()?; - debcrafter.check_if_installed()?; - debcrafter.create_debian_dir(&self.spec_file, &self.build_files_dir)?; - info!( - "Created /debian dir under build_files_dir folder: {:?}", - self.build_files_dir - ); - Ok(()) - } -} diff --git a/workspace/packager_deb/src/steps/create_empty_tar.rs b/workspace/packager_deb/src/steps/create_empty_tar.rs deleted file mode 100644 index 81781379..00000000 --- a/workspace/packager_deb/src/steps/create_empty_tar.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use log::info; -use std::{path::PathBuf, process::Command}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum CreateEmptyTarError { - #[error("Failed to create virtual package tarball")] - TarballCreationFailed, -} -#[derive(Default)] -pub struct CreateEmptyTar { - tarball_path: PathBuf, - build_artifacts_dir: PathBuf, -} - -impl From for CreateEmptyTar { - fn from(context: BuildContext) -> Self { - CreateEmptyTar { - build_artifacts_dir: context.build_artifacts_dir.clone(), - tarball_path: context.tarball_path.clone(), - } - } -} - -impl BuildStep for CreateEmptyTar { - fn step(&self) -> Result<(), BuildError> { - info!("Creating empty .tar.gz for virtual package"); - let output = Command::new("tar") - .args([ - "czvf", - &self.tarball_path.display().to_string(), - "--files-from", - "/dev/null", - ]) - .current_dir(&self.build_artifacts_dir) - .output()?; - - if !output.status.success() { - return Err(CreateEmptyTarError::TarballCreationFailed.into()); - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::tempdir; - - impl BuildContext { - pub fn new() -> Self { - Self::default() - } - } - #[test] - fn test_download_source_virtual_package() { - let temp_dir = tempdir().expect("Failed to create temporary directory"); - - let build_artifacts_dir = temp_dir.path().to_path_buf(); - let tarball_name = "test_package.tar.gz"; - let tarball_path = temp_dir.path().join(tarball_name); - let tarball_path_str = temp_dir.path().join(tarball_name); - - let mut context = BuildContext::new(); - context.tarball_path = tarball_path_str; - context.build_artifacts_dir = build_artifacts_dir; - let step = CreateEmptyTar::from(context); - - let result = step.step(); - - assert!(result.is_ok()); - assert!(tarball_path.exists()); - } -} diff --git a/workspace/packager_deb/src/steps/dowload_git.rs b/workspace/packager_deb/src/steps/dowload_git.rs deleted file mode 100644 index bea4083b..00000000 --- a/workspace/packager_deb/src/steps/dowload_git.rs +++ /dev/null @@ -1,343 +0,0 @@ -use std::{ - fs, io, - path::{Path, PathBuf}, - process::{Command, Output}, -}; - -use filetime::FileTime; -use log::info; -use thiserror::Error; - -use crate::{ - configs::pkg_config::SubModule, - misc::build_pipeline::{BuildContext, BuildError, BuildStep}, -}; - -#[derive(Error, Debug)] -pub enum DownloadGitError { - #[error("git-lfs is not installed, please install it!")] - GitLfsNotInstalled, - - #[error("Failed to checkout tag {tag}: {reason}")] - CheckoutTagFailed { tag: String, reason: String }, - - #[error("Failed to initialize submodules: {0}")] - SubmoduleInitFailed(String), - - #[error("Failed to checkout submodule: {0}")] - SubmoduleCheckoutFailed(String), - - #[error("Failed to checkout commit {commit} for submodule {path}: {reason}")] - SubmoduleCommitFailed { - commit: String, - path: String, - reason: String, - }, - - #[error("Failed to create tarball: {0}")] - TarballCreationFailed(String), - - #[error("IO error: {0}")] - IoError(#[from] io::Error), -} - -#[derive(Default)] -pub struct DownloadGit { - build_artifacts_dir: PathBuf, - package_name: String, - git_tag: String, - git_url: String, - submodules: Vec, - tarball_path: PathBuf, -} - -impl From for DownloadGit { - fn from(context: BuildContext) -> Self { - Self { - build_artifacts_dir: context.build_artifacts_dir.clone(), - package_name: context.package_name.clone(), - git_tag: context.git_tag.clone(), - git_url: context.git_url.clone(), - submodules: context.submodules.clone(), - tarball_path: context.tarball_path.clone(), - } - } -} - -impl DownloadGit { - fn check_git_lfs() -> Result<(), DownloadGitError> { - Command::new("which") - .arg("git-lfs") - .output() - .map(|_| ()) - .map_err(|_| DownloadGitError::GitLfsNotInstalled) - } - - fn get_error_message(output: &Output) -> String { - String::from_utf8_lossy(&output.stderr).to_string() - } - - fn run_git_command( - args: &[&str], - current_dir: Option<&Path>, - error_type: impl FnOnce(String) -> DownloadGitError, - ) -> Result<(), DownloadGitError> { - let mut cmd = Command::new("git"); - - if let Some(dir) = current_dir { - cmd.current_dir(dir); - } - - let output = cmd.args(args).output().map_err(DownloadGitError::IoError)?; - - if !output.status.success() { - return Err(error_type(Self::get_error_message(&output))); - } - - Ok(()) - } - - fn clone_repo(git_url: &str, tag_version: &str, path: &Path) -> Result<(), DownloadGitError> { - let output = Command::new("git") - .args(&[ - "clone", - "--depth=1", - "--branch", - tag_version, - git_url, - &path.display().to_string(), - ]) - .output() - .map_err(DownloadGitError::IoError)?; - - if !output.status.success() { - return Err(DownloadGitError::CheckoutTagFailed { - tag: tag_version.to_string(), - reason: Self::get_error_message(&output), - }); - } - - Ok(()) - } - - fn init_submodules(path: &Path) -> Result<(), DownloadGitError> { - Self::run_git_command( - &["submodule", "init"], - Some(&path), - DownloadGitError::SubmoduleInitFailed, - )?; - - Self::run_git_command( - &["submodule", "update", "--init", "--recursive"], - Some(path), - DownloadGitError::SubmoduleInitFailed, - ) - } - - fn checkout_submodule_commits( - submodule: &SubModule, - base_path: &Path, - ) -> Result<(), DownloadGitError> { - let submodule_path = Path::new(base_path).join(&submodule.path); - println!( - "Checking out path: {:?} commit:{}", - submodule_path, submodule.commit - ); - - let fetch_commit_output = Command::new("git") - .current_dir(submodule_path.clone()) - .args(&["fetch", "origin", &submodule.commit.trim()]) - .output() - .map_err(|err| DownloadGitError::SubmoduleCheckoutFailed(err.to_string()))?; - - if !fetch_commit_output.status.success() { - return Err(DownloadGitError::SubmoduleCommitFailed { - commit: submodule.commit.clone(), - path: submodule.path.clone(), - reason: Self::get_error_message(&fetch_commit_output), - }); - } - let output = Command::new("git") - .current_dir(submodule_path) - .args(&["checkout", &submodule.commit.trim()]) - .output() - .map_err(|err| DownloadGitError::SubmoduleCheckoutFailed(err.to_string()))?; - - if !output.status.success() { - return Err(DownloadGitError::SubmoduleCommitFailed { - commit: submodule.commit.clone(), - path: submodule.path.clone(), - reason: Self::get_error_message(&output), - }); - } - - Ok(()) - } - - pub fn clone_and_checkout_tag( - git_url: &str, - tag_version: &str, - path: &Path, - git_submodules: &[SubModule], - ) -> Result<(), DownloadGitError> { - Self::check_git_lfs()?; - Self::clone_repo(git_url, tag_version, path)?; - Self::init_submodules(path)?; - Self::update_submodules(git_submodules, path)?; - - Ok(()) - } - - pub fn update_submodules( - git_submodules: &[SubModule], - current_dir: &Path, - ) -> Result<(), DownloadGitError> { - for submodule in git_submodules { - Self::checkout_submodule_commits(submodule, current_dir)?; - } - - Ok(()) - } - - fn create_tarball(&self) -> Result<(), DownloadGitError> { - info!( - "Creating tar from git repo from {}", - self.build_artifacts_dir.join(&self.package_name).display() - ); - - let output = Command::new("tar") - .args(&[ - "--sort=name", - "--owner=0", - "--group=0", - "--numeric-owner", - // does not work - // "--mtime='2019-01-01 00:00'", - "--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime", - "-czf", - &self.tarball_path.display().to_string(), - &self.package_name, - ]) - .current_dir(&self.build_artifacts_dir) - .output() - .map_err(DownloadGitError::IoError)?; - - if !output.status.success() { - return Err(DownloadGitError::TarballCreationFailed( - Self::get_error_message(&output), - )); - } - - Ok(()) - } - - fn set_creation_time>(dir_path: P, timestamp: FileTime) -> io::Result<()> { - filetime::set_file_mtime(&dir_path, timestamp)?; - filetime::set_file_atime(&dir_path, timestamp)?; - - let mut stack = vec![PathBuf::from(dir_path.as_ref())]; - - while let Some(current) = stack.pop() { - for entry in fs::read_dir(¤t)? { - let entry = entry?; - let file_type = entry.file_type()?; - let file_path = entry.path(); - - match file_type { - _ if file_type.is_dir() => { - stack.push(file_path.clone()); - filetime::set_file_mtime(&file_path, timestamp)?; - filetime::set_file_atime(&file_path, timestamp)?; - } - _ if file_type.is_file() => { - filetime::set_file_mtime(&file_path, timestamp)?; - filetime::set_file_atime(&file_path, timestamp)?; - } - _ if file_type.is_symlink() => { - filetime::set_symlink_file_times(&file_path, timestamp, timestamp)?; - } - _ => (), // Skip other file types - } - } - } - - Ok(()) - } - - fn prepare_build_directory(&self) -> Result { - let path = self.build_artifacts_dir.join(&self.package_name); - - if path.exists() { - fs::remove_dir_all(&path)?; - } - - fs::create_dir_all(&path)?; - - Ok(path) - } -} - -impl BuildStep for DownloadGit { - fn step(&self) -> Result<(), BuildError> { - let path = self.prepare_build_directory()?; - - Self::clone_and_checkout_tag(&self.git_url, &self.git_tag, &path, &self.submodules)?; - - fs::remove_dir_all(path.join(".git"))?; - - // Set consistent file timestamps for reproducibility: January 1, 2022 - let timestamp = FileTime::from_unix_time(1640995200, 0); - Self::set_creation_time(path, timestamp)?; - - self.create_tarball()?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::configs::pkg_config::{PackageType, PkgConfig}; - - use super::*; - use tempfile::tempdir; - - #[test] - #[ignore = "Only run on CI"] - fn test_clone_and_checkout_tag() { - let url = "https://github.com/status-im/nimbus-eth2.git"; - let temp_dir = tempdir().expect("Failed to create temporary directory"); - let repo_path = temp_dir.path(); - let tag_version = "v24.3.0"; - let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR"); - let cargo_workspace_dir = Path::new(cargo_manifest_dir) - .parent() - .unwrap() - .parent() - .unwrap() - .to_path_buf(); - let toml_file = - cargo_workspace_dir.join("examples/bookworm/git-package/nimbus/pkg-builder.toml"); - - let str = fs::read_to_string(toml_file).expect("Cannot read example toml"); - let config: PkgConfig = toml::from_str(&str).expect("Cannot parse file."); - match config.package_type { - PackageType::Git(gitconfig) => { - let result = DownloadGit::clone_and_checkout_tag( - url, - tag_version, - repo_path, - &gitconfig.submodules, - ); - assert!( - result.is_ok(), - "Failed to clone and checkout tag: {:?}", - result - ); - } - _ => panic!("Wrong type of file."), - } - - fs::remove_dir_all(temp_dir).unwrap(); - } -} diff --git a/workspace/packager_deb/src/steps/download_source.rs b/workspace/packager_deb/src/steps/download_source.rs deleted file mode 100644 index cba566a0..00000000 --- a/workspace/packager_deb/src/steps/download_source.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use log::info; -use std::{fs, path::PathBuf, process::Command}; - -#[derive(Default)] -pub struct DownloadSource { - tarball_url: String, - tarball_path: PathBuf, -} - -impl From for DownloadSource { - fn from(context: BuildContext) -> Self { - DownloadSource { - tarball_url: context.tarball_url.clone(), - tarball_path: context.tarball_path.clone(), - } - } -} -impl BuildStep for DownloadSource { - fn step(&self) -> Result<(), BuildError> { - info!("Downloading source {:?}", self.tarball_path); - let is_web = self.tarball_url.starts_with("http"); - - if is_web { - info!( - "Downloading tar: {} to location: {:?}", - self.tarball_url, self.tarball_path - ); - let status = Command::new("wget") - .arg("-q") - .arg("-O") - .arg(&self.tarball_path) - .arg(&self.tarball_url) - .status() - .map_err(|e| BuildError::CommandFailed(e.to_string()))?; - - if !status.success() { - return Err(BuildError::DownloadFailed); - } - } else { - info!( - "Copying tar: {} to location: {:?}", - self.tarball_url, self.tarball_path - ); - fs::copy(&self.tarball_url, &self.tarball_path) - .map_err(|e| BuildError::FileCopyFailed(e.to_string()))?; - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::misc::build_pipeline::BuildContext; - - use super::*; - use std::fs::File; - use std::io::Write; - use std::path::Path; - use tempfile::tempdir; - - use httpmock::prelude::*; - - fn setup_mock_server() -> MockServer { - // Start the mock server - let server = MockServer::start(); - - // Mock the endpoint to serve the tarball file - server.mock(|when, then| { - when.method(GET).path("/test_package.tar.gz"); - then.status(200) - .header("Content-Type", "application/octet-stream") - .body_from_file("tests/misc/test_package.tar.gz"); - }); - - server - } - #[test] - fn test_download_source_non_virtual_package() { - let server = setup_mock_server(); - - let temp_dir = tempdir().expect("Failed to create temporary directory"); - - let tarball_name = "test_package.tar.gz"; - let tarball_path = temp_dir.path().join(tarball_name); - let tarball_url = format!("{}/{}", server.base_url(), tarball_name); - - let mut context = BuildContext::default(); - context.tarball_path = tarball_path.clone(); - context.tarball_url = tarball_url; - let handler = DownloadSource::from(context); - - let result = handler.step(); - - assert!(result.is_ok()); - assert!(tarball_path.exists()); - } - - #[test] - fn test_handle_local_copy_success() { - // Create a temporary directory for testing - let dir = tempdir().unwrap(); - let source_path = dir.path().join("source.tar.gz"); - let dest_path = dir.path().join("dest.tar.gz"); - - // Create a dummy source file - { - let mut file = File::create(&source_path).unwrap(); - writeln!(file, "test content").unwrap(); - } - - let mut context = BuildContext::default(); - context.tarball_path = dest_path.clone(); - context.tarball_url = source_path.to_string_lossy().to_string(); - let handler = DownloadSource::from(context); - - let result = handler.step(); - assert!(result.is_ok()); - - // Verify the file was copied - assert!(Path::new(&dest_path).exists()); - } - - #[test] - fn test_handle_local_copy_failure() { - // Create a temporary directory for testing - let dir = tempdir().unwrap(); - let source_path = dir.path().join("nonexistent_source.tar.gz"); - let dest_path = dir.path().join("dest.tar.gz"); - - // No source file exists - - let mut context = BuildContext::default(); - context.tarball_path = dest_path; - context.tarball_url = source_path.to_string_lossy().to_string(); - let handler = DownloadSource::from(context); - - let result = handler.step(); - assert!(result.is_err()); - - match result { - Err(BuildError::FileCopyFailed(_)) => {} - _ => panic!("Expected FileCopyFailed error"), - } - } -} diff --git a/workspace/packager_deb/src/steps/extract_source.rs b/workspace/packager_deb/src/steps/extract_source.rs deleted file mode 100644 index 332919e9..00000000 --- a/workspace/packager_deb/src/steps/extract_source.rs +++ /dev/null @@ -1,217 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use log::info; -use std::{fs, io, path::PathBuf, process::Command}; - -#[derive(Default)] -pub struct ExtractSource { - build_files_dir: PathBuf, - tarball_path: PathBuf, -} - -impl From for ExtractSource { - fn from(context: BuildContext) -> Self { - ExtractSource { - build_files_dir: context.build_files_dir.clone(), - tarball_path: context.tarball_path.clone(), - // debcrafter_version: context.debcrafter_version.clone(), - // spec_file: context.spec_file.clone(), - } - } -} - -impl ExtractSource { - fn longest_common_prefix(strings: &[&str]) -> String { - if strings.is_empty() { - return String::new(); - } - if strings.len() == 1 { - let mut path_buf = PathBuf::from(strings[0]); - path_buf.pop(); - let common_prefix = path_buf.to_string_lossy().to_string(); - return common_prefix; - } - let first_string = &strings[0]; - let mut prefix = String::new(); - 'outer: for (i, c) in first_string.char_indices() { - for string in &strings[1..] { - if let Some(next_char) = string.chars().nth(i) { - if next_char != c { - break 'outer; - } - } else { - break 'outer; - } - } - prefix.push(c); - } - prefix - } - - fn components_to_strip(&self, tar_gz_file: String) -> Result { - let output = Command::new("tar") - .arg("--list") - .arg("-z") - .arg("-f") - .arg(tar_gz_file) - .output()?; - let output_str = String::from_utf8_lossy(&output.stdout); - let lines: Vec<&str> = output_str.lines().filter(|l| !l.ends_with('/')).collect(); - let common_prefix = Self::longest_common_prefix(&lines); - let components_to_strip = common_prefix.split('/').filter(|&x| !x.is_empty()).count(); - Ok(components_to_strip) - } -} - -impl BuildStep for ExtractSource { - fn step(&self) -> Result<(), BuildError> { - info!("Extracting source {:?}", &self.build_files_dir); - fs::create_dir_all(&self.build_files_dir).map_err(BuildError::IoError)?; - - let mut args = vec![ - "zxvf".to_string(), - self.tarball_path.display().to_string(), - "-C".to_string(), - self.build_files_dir.display().to_string(), - ]; - let numbers_to_strip = self - .components_to_strip(self.tarball_path.display().to_string()) - .map_err(BuildError::IoError)?; - - let strip = format!("--strip-components={}", numbers_to_strip); - if numbers_to_strip > 0 { - args.push(strip); - } - - info!("Stripping components: {} {:?}", numbers_to_strip, args); - let output = Command::new("tar") - .args(args) - .output() - .map_err(BuildError::IoError)?; - - if !output.status.success() { - let error_message = String::from_utf8(output.stderr) - .unwrap_or_else(|_| "Unknown error occurred during extraction".to_string()); - return Err(BuildError::ExtractionError(error_message)); - } - - info!( - "Extracted source to build_files_dir: {:?}", - self.build_files_dir - ); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use fs::File; - use std::path::Path; - use tempfile::tempdir; - - #[test] - fn test_longest_common_prefix_empty() { - let strings: Vec<&str> = vec![]; - let prefix = ExtractSource::longest_common_prefix(&strings); - assert_eq!(prefix, ""); - } - - #[test] - fn test_longest_common_prefix_single() { - let strings = vec!["folder/file.txt"]; - let prefix = ExtractSource::longest_common_prefix(&strings); - assert_eq!(prefix, "folder"); - } - - #[test] - fn test_longest_common_prefix_multiple() { - let strings = vec![ - "project/src/main.rs", - "project/src/lib.rs", - "project/Cargo.toml", - ]; - let prefix = ExtractSource::longest_common_prefix(&strings); - assert_eq!(prefix, "project/"); - } - - #[test] - fn test_longest_common_prefix_no_common() { - let strings = vec!["abc/def", "xyz/uvw"]; - let prefix = ExtractSource::longest_common_prefix(&strings); - assert_eq!(prefix, ""); - } - - #[test] - fn test_handle_success() -> Result<(), Box> { - let temp_dir = tempdir()?; - let build_dir = temp_dir.path().join("build"); - let tarball_path = temp_dir.path().join("source.tar.gz"); - - File::create(&tarball_path)?; - - let mut context = BuildContext::default(); - context.build_files_dir = build_dir.clone(); - context.tarball_path = tarball_path; - - let handler = ExtractSource::from(context); - - if !Path::new(&build_dir).exists() { - let result = handler.step(); - assert!(result.is_err()); - } - - assert!(Path::new(&build_dir).exists()); - - Ok(()) - } - - #[test] - fn test_handle_extraction_error() { - let temp_dir = tempdir().unwrap(); - let build_dir = temp_dir.path().join("build"); - let tarball_path = temp_dir.path().join("nonexistent.tar.gz"); - - let mut context = BuildContext::default(); - context.build_files_dir = build_dir; - context.tarball_path = tarball_path; - let handler = ExtractSource::from(context); - - let result = handler.step(); - assert!(result.is_err()); - - // match result { - // Err(BuildError::IoError(_)) => (), // Expected - // Err(e) => panic!("Unexpected error type: {:?}", e), - // Ok(_) => panic!("Expected an error but got Ok"), - // } - } - - #[test] - fn test_extract_source() { - let package_name = "test_package"; - let temp_dir = tempdir().expect("Failed to create temporary directory"); - let temp_dir = temp_dir.path(); - let tarball_path: PathBuf = PathBuf::from("tests/misc/test_package.tar.gz"); - - let build_files_dir = temp_dir.join(package_name); - - assert!(tarball_path.exists()); - - let mut context = BuildContext::default(); - context.build_files_dir = build_files_dir.clone(); - context.tarball_path = tarball_path.to_str().unwrap().into(); - let handler = ExtractSource::from(context); - - let result = handler.step(); - - assert!(result.is_ok(), "{:?}", result); - assert!(Path::new(&build_files_dir).exists()); - - let test_file_path = PathBuf::from(build_files_dir.clone()).join("empty_file.txt"); - - assert!( - test_file_path.exists(), - "Empty file not found after extraction" - ); - } -} diff --git a/workspace/packager_deb/src/steps/mod.rs b/workspace/packager_deb/src/steps/mod.rs deleted file mode 100644 index df2cc806..00000000 --- a/workspace/packager_deb/src/steps/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod create_debian_dir; -pub mod create_empty_tar; -pub mod dowload_git; -pub mod download_source; -pub mod extract_source; -pub mod package_dir_setup; -pub mod patch_source; -pub mod setup_sbuild; -pub mod verify_hash; diff --git a/workspace/packager_deb/src/steps/package_dir_setup.rs b/workspace/packager_deb/src/steps/package_dir_setup.rs deleted file mode 100644 index f1924df5..00000000 --- a/workspace/packager_deb/src/steps/package_dir_setup.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use log::info; -use std::{ - fs, - path::{Path, PathBuf}, -}; - -#[derive(Default)] -pub struct PackageDirSetup { - build_artifacts_dir: PathBuf, -} - -impl From for PackageDirSetup { - fn from(context: BuildContext) -> Self { - PackageDirSetup { - build_artifacts_dir: context.build_artifacts_dir.clone(), - } - } -} - -impl BuildStep for PackageDirSetup { - fn step(&self) -> Result<(), BuildError> { - let build_artifacts_dir = &self.build_artifacts_dir; - - if Path::new(build_artifacts_dir).exists() { - info!("Removing previous package folder {:?}", build_artifacts_dir); - - fs::remove_dir_all(build_artifacts_dir)?; - } - - info!("Creating package folder {:?}", build_artifacts_dir); - - fs::create_dir_all(build_artifacts_dir)?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::misc::build_pipeline::{BuildContext, BuildError}; - use std::path::PathBuf; - use tempfile::TempDir; - - fn setup_test_context() -> (BuildContext, TempDir) { - let temp_dir = TempDir::new().expect("Failed to create temp directory"); - let artifacts_dir = temp_dir.path().join("artifacts"); - - let mut context = BuildContext::new(); - context.build_artifacts_dir = artifacts_dir; - - (context, temp_dir) - } - - #[test] - fn test_handle_creates_new_directory() { - let (context, _temp_dir) = setup_test_context(); - let handler = PackageDirSetup::from(context); - - let result = handler.step(); - - assert!(result.is_ok()); - assert!(Path::new(&handler.build_artifacts_dir).exists()); - assert!(Path::new(&handler.build_artifacts_dir).is_dir()); - } - - #[test] - fn test_handle_removes_existing_directory() { - let (context, _temp_dir) = setup_test_context(); - - fs::create_dir_all(&context.build_artifacts_dir).expect("Failed to create test directory"); - - let test_file = PathBuf::from(&context.build_artifacts_dir).join("test_file.txt"); - fs::write(&test_file, "test content").expect("Failed to write test file"); - - assert!(test_file.exists()); - - let handler = PackageDirSetup::from(context); - let result = handler.step(); - - assert!(result.is_ok()); - assert!(Path::new(&handler.build_artifacts_dir).exists()); - assert!(Path::new(&handler.build_artifacts_dir).is_dir()); - - assert!(!test_file.exists()); - } - - #[test] - fn test_handle_with_permission_error() { - // This test would ideally test the error case when directory operations fail - // But it's hard to simulate in a portable way, so we're just checking the error mapping - // In a real test environment, you might use mock_fs or similar libraries - - let (mut context, _temp_dir) = setup_test_context(); - - context.build_artifacts_dir = "/root/forbidden_dir".into(); - - let handler = PackageDirSetup::from(context); - let result = handler.step(); - - assert!(result.is_err()); - - if let Err(BuildError::IoError(err)) = result { - assert_eq!(err.to_string(), "Permission denied (os error 13)"); - } else { - panic!("Expected IoError, got a different error or success"); - } - } -} diff --git a/workspace/packager_deb/src/steps/patch_source.rs b/workspace/packager_deb/src/steps/patch_source.rs deleted file mode 100644 index 74e1e6c7..00000000 --- a/workspace/packager_deb/src/steps/patch_source.rs +++ /dev/null @@ -1,260 +0,0 @@ -use std::{ - fs, - io::{BufRead, BufReader, Write}, - os::unix::fs::PermissionsExt, - path::{Path, PathBuf}, -}; - -use log::info; - -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; - -#[derive(Default)] -pub struct PatchSource { - build_files_dir: PathBuf, - homepage: String, - src_dir: PathBuf, -} - -impl From for PatchSource { - fn from(context: BuildContext) -> Self { - PatchSource { - build_files_dir: context.build_files_dir.clone(), - homepage: context.homepage.clone(), - src_dir: context.src_dir.clone(), - } - } -} - -impl PatchSource { - pub fn patch_quilt(build_files_dir: &PathBuf) -> Result<(), BuildError> { - let debian_source_format_path = build_files_dir.clone().join("debian/source/format"); - - info!( - "Setting up quilt format for patching. Debian source format path: {:?}", - debian_source_format_path - ); - if !debian_source_format_path.parent().unwrap().exists() { - fs::create_dir_all(&debian_source_format_path.parent().unwrap())?; - info!( - "Created debian/source directory at: {:?}", - debian_source_format_path.parent().unwrap() - ); - } - - if !Path::new(&debian_source_format_path).exists() { - fs::write(&debian_source_format_path, "3.0 (quilt)\n")?; - info!( - "Quilt format file created at: {:?}", - debian_source_format_path - ); - } else { - info!( - "Quilt format file already exists at: {:?}", - debian_source_format_path - ); - } - Ok(()) - } - - pub fn patch_pc_dir(build_files_dir: &PathBuf) -> Result<(), BuildError> { - let pc_version_path = build_files_dir.clone().join(".pc/version"); - - info!("Creating necessary directories for patching .pc"); - let pc_parent = pc_version_path.parent().unwrap().join(".pc"); - fs::create_dir_all(pc_parent)?; - let mut pc_version_file = fs::File::create(pc_version_path)?; - writeln!(pc_version_file, "2")?; - Ok(()) - } - - pub fn patch_standards_version( - build_files_dir: &PathBuf, - homepage: &String, - ) -> Result<(), BuildError> { - let debian_control_path: PathBuf = build_files_dir.clone().join("debian/control"); - info!( - "Adding Standards-Version to the control file. Debian control path: {:?}", - debian_control_path - ); - let input_file = fs::File::open(&debian_control_path)?; - let reader = BufReader::new(input_file); - - let original_content: Vec = reader.lines().map(|line| line.unwrap()).collect(); - let has_standards_version = original_content - .iter() - .any(|line| line.starts_with("Standards-Version")); - let standards_version_line = "Standards-Version: 4.5.1"; - let homepage_line = format!("Homepage: {}", homepage); - if !has_standards_version { - let mut insert_index = 0; - for (i, line) in original_content.iter().enumerate() { - if line.starts_with("Priority:") { - insert_index = i + 1; - break; - } - } - - let mut updated_content = original_content.clone(); - updated_content.insert(insert_index, standards_version_line.to_string()); - updated_content.insert(insert_index + 1, homepage_line.to_string()); - - let mut output_file = fs::File::create(&debian_control_path)?; - for line in updated_content { - writeln!(output_file, "{}", line)?; - } - - info!("Standards-Version added to the control file."); - } else { - info!("Standards-Version already exists in the control file. No changes made."); - } - Ok(()) - } - - pub fn copy_src_dir(build_files_dir: &PathBuf, src_dir: &PathBuf) -> Result<(), BuildError> { - let src_dir_path = Path::new(src_dir); - if src_dir_path.exists() { - Self::copy_directory_recursive(Path::new(src_dir), Path::new(&build_files_dir)) - .map_err(|err| BuildError::CopyDirectory(err.to_string()))?; - } - Ok(()) - } - - pub fn patch_rules_permission(build_files_dir: &PathBuf) -> Result<(), BuildError> { - info!( - "Adding executable permission for {:?}/debian/rules", - build_files_dir - ); - let debian_rules: PathBuf = build_files_dir.clone().join("debian/rules"); - - let mut permissions = fs::metadata(debian_rules.clone()) - .map_err(|_| BuildError::RulesPermissionGet)? - .permissions(); - permissions.set_mode(permissions.mode() | 0o111); - fs::set_permissions(debian_rules, permissions) - .map_err(|_| BuildError::RulesPermissionSet)?; - Ok(()) - } - - fn copy_directory_recursive(src_dir: &Path, dest_dir: &Path) -> Result<(), std::io::Error> { - if !src_dir.exists() { - return Err(std::io::Error::new( - std::io::ErrorKind::NotFound, - format!("Source directory {:?} does not exist", src_dir), - )); - } - - if !dest_dir.exists() { - fs::create_dir_all(dest_dir)?; - } - - for entry in fs::read_dir(src_dir)? { - let entry = entry?; - let entry_path = entry.path(); - let file_name = entry.file_name(); - - let dest_path = dest_dir.join(&file_name); - - if entry_path.is_dir() { - Self::copy_directory_recursive(&entry_path, &dest_path)?; - } else { - if let Err(e) = fs::copy(&entry_path, &dest_path) { - eprintln!( - "Failed to copy file from {:?} to {:?}: {}", - entry_path, dest_path, e - ); - return Err(e); - } - } - } - - Ok(()) - } -} - -impl BuildStep for PatchSource { - fn step(&self) -> Result<(), BuildError> { - // Patch quilt - Self::patch_quilt(&self.build_files_dir)?; - - // Patch .pc dir setup - Self::patch_pc_dir(&self.build_files_dir)?; - - // Patch .pc patch version number - Self::patch_standards_version(&self.build_files_dir, &self.homepage)?; - - // Only copy if src dir exists - Self::copy_src_dir(&self.build_files_dir, &self.src_dir)?; - - Self::patch_rules_permission(&self.build_files_dir)?; - - info!("Patching finished successfully!"); - Ok(()) // Added missing return value - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::fs::File; - use tempfile::tempdir; - - #[test] - fn patch_rules_permission_handles_nonexistent_directory() { - let result = PatchSource::patch_rules_permission(&"/nonexistent/dir".into()); - - assert!(result.is_err()); - } - - #[test] - fn patch_quilt_creates_source_dir_and_format_file() -> Result<(), Box> { - let temp_dir = tempdir()?; - let build_files_dir = temp_dir.path().to_path_buf(); - - let result = PatchSource::patch_quilt(&build_files_dir); - assert!(result.is_ok()); - - let debian_source_dir = temp_dir.path().join("debian/source"); - assert!(debian_source_dir.exists()); - - let debian_source_format_path = temp_dir.path().join("debian/source/format"); - let format_content = fs::read_to_string(debian_source_format_path)?; - assert_eq!(format_content, "3.0 (quilt)\n"); - - Ok(()) - } - - #[test] - fn patch_quilt_skips_creation_if_already_exists() -> Result<(), Box> { - let temp_dir = tempdir()?; - let temp_dir = temp_dir.path(); - let build_files_dir = temp_dir.to_path_buf(); - - fs::create_dir_all(temp_dir.join("debian/source")).expect("Failed to create dir for test."); - File::create(temp_dir.join("debian/source/format")).expect("Failed to create file."); - - let result = PatchSource::patch_quilt(&build_files_dir.into()); - assert!(result.is_ok()); - - let entries: Vec<_> = fs::read_dir(temp_dir)?.collect(); - assert_eq!(entries.len(), 1); - - Ok(()) - } - - #[test] - fn patch_rules_permission_adds_exec_permission() -> Result<(), Box> { - let temp_dir = tempdir()?; - let rules_path = temp_dir.path().join("debian/rules"); - fs::create_dir_all(temp_dir.path().join("debian")).expect("Could not create dir"); - File::create(&rules_path)?; - - let result = PatchSource::patch_rules_permission(&temp_dir.path().to_path_buf()); - assert!(result.is_ok()); - - let permissions = fs::metadata(&rules_path)?.permissions(); - assert_ne!(permissions.mode() & 0o111, 0); - - Ok(()) - } -} diff --git a/workspace/packager_deb/src/steps/setup_sbuild.rs b/workspace/packager_deb/src/steps/setup_sbuild.rs deleted file mode 100644 index b375059c..00000000 --- a/workspace/packager_deb/src/steps/setup_sbuild.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use dirs::home_dir; -use std::fs; -use std::io::Write; - -#[derive(Default)] -pub struct SetupSbuild {} - -impl From for SetupSbuild { - fn from(_context: BuildContext) -> Self { - SetupSbuild {} - } -} -impl BuildStep for SetupSbuild { - fn step(&self) -> Result<(), BuildError> { - let home_dir = home_dir().ok_or(BuildError::HomeDirNotFound)?; - let dest_path = home_dir.join(".sbuildrc"); - let content = include_str!("../.sbuildrc"); - let home_dir = home_dir.to_str().unwrap_or("/home/runner").to_string(); - let replaced_contents = content.replace("", &home_dir); - - let mut file = fs::File::create(dest_path) - .map_err(|err| BuildError::FileCreationError(err.to_string()))?; - - file.write_all(replaced_contents.as_bytes()) - .map_err(|err| BuildError::FileWriteError(err.to_string()))?; - - Ok(()) - } -} diff --git a/workspace/packager_deb/src/steps/verify_hash.rs b/workspace/packager_deb/src/steps/verify_hash.rs deleted file mode 100644 index 0c762bfa..00000000 --- a/workspace/packager_deb/src/steps/verify_hash.rs +++ /dev/null @@ -1,262 +0,0 @@ -use crate::misc::build_pipeline::{BuildContext, BuildError, BuildStep}; -use log::info; -use sha2::{Digest, Sha256, Sha512}; -use std::fs; -use std::io::Read; -use std::path::PathBuf; - -#[derive(Default)] -pub struct VerifyHash { - tarball_path: PathBuf, - tarball_hash: String, -} - -impl From for VerifyHash { - fn from(context: BuildContext) -> Self { - VerifyHash { - tarball_path: context.tarball_path.clone(), - tarball_hash: context.tarball_hash.clone(), - } - } -} - -impl VerifyHash { - fn calculate_sha256(mut reader: R) -> Result { - let mut hasher = Sha256::new(); - std::io::copy(&mut reader, &mut hasher)?; - let digest_bytes = hasher.finalize(); - let hex_digest = digest_bytes - .iter() - .map(|b| format!("{:02x}", b)) - .collect::(); - Ok(hex_digest) - } - - fn calculate_sha512(mut reader: R) -> Result { - let mut hasher = Sha512::new(); - std::io::copy(&mut reader, &mut hasher)?; - let digest_bytes = hasher.finalize(); - let hex_digest = digest_bytes - .iter() - .map(|b| format!("{:02x}", b)) - .collect::(); - Ok(hex_digest) - } - - fn verify_tarball_checksum( - &self, - tarball_path: &PathBuf, - expected_checksum: &str, - ) -> Result { - let mut file = fs::File::open(tarball_path) - .map_err(|err| BuildError::TarballOpenError(err.to_string()))?; - - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer) - .map_err(|err| BuildError::TarballReadError(err.to_string()))?; - - // Try SHA-512 first - let actual_sha512 = Self::calculate_sha512(&*buffer).unwrap_or_default(); - info!("sha512 hash {}", &actual_sha512); - if actual_sha512 == expected_checksum { - return Ok(true); - } - - // If SHA-512 doesn't match, try SHA-256 - let actual_sha256 = Self::calculate_sha256(&*buffer).unwrap_or_default(); - info!("sha256 hash {}", &actual_sha256); - if actual_sha256 == expected_checksum { - return Ok(true); - } - - Err(BuildError::HashMismatchError) - } -} - -impl BuildStep for VerifyHash { - fn step(&self) -> Result<(), BuildError> { - match self.verify_tarball_checksum(&self.tarball_path, &self.tarball_hash) { - Ok(_) => Ok(()), - Err(err) => Err(err), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::fs::File; - use std::io::Write; - use tempfile::tempdir; - - fn create_temp_file(content: &[u8]) -> Result<(tempfile::TempDir, String), std::io::Error> { - let dir = tempdir()?; - let file_path = dir.path().join("test_tarball.tar.gz"); - let mut file = File::create(&file_path)?; - file.write_all(content)?; - Ok((dir, file_path.to_string_lossy().to_string())) - } - - fn read_tarball(tarball_path: &str) -> Result, std::io::Error> { - let mut file = std::fs::File::open(tarball_path)?; - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer)?; - Ok(buffer) - } - - #[test] - fn test_calculate_sha256() { - let data = b"abc"; - let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; - - let result = VerifyHash::calculate_sha256(&data[..]).unwrap(); - assert_eq!(result, expected); - } - - #[test] - fn test_calculate_sha512() { - let data = b"abc"; - let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; - - let result = VerifyHash::calculate_sha512(&data[..]).unwrap(); - assert_eq!(result, expected); - } - - #[test] - fn test_verify_tarball_checksum_sha256_success() { - let content = b"test content"; - let (_dir, file_path) = create_temp_file(content).unwrap(); - let buffer = read_tarball(&file_path).unwrap(); - - let expected_checksum = VerifyHash::calculate_sha256(&*buffer).unwrap(); - - let handler = VerifyHash::from(BuildContext::new()); - - let result = handler.verify_tarball_checksum(&file_path.into(), &expected_checksum); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); - } - - #[test] - fn test_verify_tarball_checksum_sha512_success() { - let content = b"test content"; - let (_dir, file_path) = create_temp_file(content).unwrap(); - let buffer = read_tarball(&file_path).unwrap(); - - let expected_checksum = VerifyHash::calculate_sha512(&*buffer).unwrap(); - - let handler = VerifyHash::from(BuildContext::new()); - - let result = handler.verify_tarball_checksum(&file_path.into(), &expected_checksum); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); - } - - #[test] - fn test_verify_tarball_checksum_mismatch() { - let content = b"test content"; - let (_dir, file_path) = create_temp_file(content).unwrap(); - - let incorrect_checksum = "0000000000000000000000000000000000000000000000000000000000000000"; - - let handler = VerifyHash::from(BuildContext::new()); - - let result = handler.verify_tarball_checksum(&file_path.into(), &incorrect_checksum); - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), BuildError::HashMismatchError)); - } - - #[test] - fn test_handle_with_checksum() { - let content = b"test content"; - let (_dir, file_path) = create_temp_file(content).unwrap(); - let buffer = read_tarball(&file_path).unwrap(); - - let expected_checksum = VerifyHash::calculate_sha256(&*buffer).unwrap(); - - let mut context = BuildContext::default(); - context.tarball_hash = expected_checksum; - context.tarball_path = file_path.into(); - let handler: VerifyHash = VerifyHash::from(context); - - let result = handler.step(); - assert!(result.is_ok()); - } - - #[test] - fn test_handle_without_checksum() { - let mut context: BuildContext = BuildContext::default(); - context.tarball_path = "some/path".into(); - let handler: VerifyHash = VerifyHash::from(context); - - let result = handler.step(); - assert!(result.is_err()); - } - - #[test] - fn test_verify_hash_valid_checksum_512() { - let tarball_path = "tests/misc/test_package.tar.gz"; - let expected_checksum = "abd0b8e99f983926dbf60bdcbaef13f83ec7b31d56e68f6252ed05981b237c837044ce768038fc34b71f925e2fb19b7dee451897db512bb4a99e0e1bc96d8ab3"; - let mut context: BuildContext = BuildContext::default(); - context.tarball_hash = expected_checksum.to_string(); - context.tarball_path = tarball_path.into(); - let handler: VerifyHash = VerifyHash::from(context); - - let result = handler.step(); - - assert!(result.is_ok()); - } - - #[test] - fn test_verify_hash_invalid_checksum_512() { - let tarball_path = "tests/misc/test_package.tar.gz"; - let expected_checksum = "abd0b8e99f983926dbf60bdcbaef13f83ec7b31d56e68f6252ed05981b237c837044ce768038fc34b71f925e2fb19b7dee451897db512bb4a99e0e1bc96d8ab2"; - - let mut context: BuildContext = BuildContext::default(); - context.tarball_hash = expected_checksum.to_string(); - context.tarball_path = tarball_path.into(); - - let handler = VerifyHash::from(context); - let result = handler.step(); - - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().to_string(), - "Checksum verification failed: hashes do not match" - ); - } - - #[test] - fn test_verify_hash_valid_checksum_256() { - let tarball_path = "tests/misc/test_package.tar.gz"; - let expected_checksum = "b610e83c026d4c465636779240b6ed40a076593a61df5f6b9f9f59f1a929478d"; - - let mut context: BuildContext = BuildContext::default(); - context.tarball_hash = expected_checksum.to_string(); - context.tarball_path = tarball_path.into(); - let handler = VerifyHash::from(context); - - let result = handler.step(); - - assert!(result.is_ok()); - } - - #[test] - fn test_verify_hash_invalid_checksum_256() { - let tarball_path = "tests/misc/test_package.tar.gz"; - let expected_checksum = "b610e83c026d4c465636779240b6ed40a076593a61df5f6b9f9f59f1a929478_"; - - let mut context: BuildContext = BuildContext::default(); - context.tarball_hash = expected_checksum.to_string(); - context.tarball_path = tarball_path.into(); - let handler = VerifyHash::from(context); - - let result = handler.step(); - - assert!(result.is_err()); - assert_eq!( - result.err().unwrap().to_string(), - "Checksum verification failed: hashes do not match" - ); - } -} diff --git a/workspace/packager_deb/src/tools/autopkgtest_tool.rs b/workspace/packager_deb/src/tools/autopkgtest_tool.rs deleted file mode 100644 index 2dad942f..00000000 --- a/workspace/packager_deb/src/tools/autopkgtest_tool.rs +++ /dev/null @@ -1,207 +0,0 @@ -use std::{fs::create_dir_all, path::PathBuf, process::Command}; - -use debian::{ - autopkgtest::Autopkgtest, autopkgtest_image::AutopkgtestImageBuilder, execute::Execute, -}; -use log::{info, warn}; -use types::{config::Architecture, distribution::Distribution}; - -use crate::{ - configs::autopkgtest_version::AutopkgtestVersion, misc::distribution::DistributionTrait, - sbuild::SbuildError, -}; - -use super::tool_runner::{BuildTool, ToolRunner}; - -pub struct AutopkgtestToolArgs { - pub (crate) version: AutopkgtestVersion, - pub (crate) changes_file: PathBuf, - pub (crate) codename: Distribution, - pub (crate) deb_dir: PathBuf, - pub (crate) test_deps: Vec, - pub (crate) image_path: Option, - pub (crate) cache_dir: PathBuf, - pub (crate) arch: Architecture, -} - -pub struct AutopkgtestTool { - args: AutopkgtestToolArgs, -} - -impl AutopkgtestTool { - pub fn new(args: AutopkgtestToolArgs) -> Self { - AutopkgtestTool { args } - } -} - -impl BuildTool for AutopkgtestTool { - fn name(&self) -> &str { - "autopkgtest" - } - fn check_tool_version(&self) -> Result<(), SbuildError> { - let output = Command::new("apt") - .args(vec!["list", "--installed", "autopkgtest"]) - .output()?; - - if !output.status.success() { - return Err(SbuildError::GenericError(format!( - "Failed to check {} version", - self.name() - ))); - } - - let stdout_str = String::from_utf8_lossy(&output.stdout).to_string(); - let actual_version = extract_version_from_apt_output(&stdout_str)?; - - match self.args.version.cmp(&actual_version) { - std::cmp::Ordering::Less => warn!( - "Using newer {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Greater => warn!( - "Using older {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Equal => info!("{} versions match ({})", self.name(), self.args.version), - } - - Ok(()) - } - - fn configure(&mut self, _runner: &mut ToolRunner) -> Result<(), SbuildError> { - info!("Running prepare_autopkgtest_image"); - let builder = AutopkgtestImageBuilder::new() - .codename(&self.args.codename)? - .image_path( - &self.args.cache_dir.display().to_string(), - &self.args.codename, - &self.args.arch, - ) - .mirror(self.args.codename.get_repo_url()) - .arch(&self.args.arch); - let image_path = builder.get_image_path().unwrap(); - let image_path_parent = image_path.parent().unwrap(); - if !image_path.exists() { - create_dir_all(image_path_parent)?; - - builder.execute()?; - } - - self.args.image_path = Some(image_path.clone()); - Ok(()) - } - fn execute(&self) -> Result<(), SbuildError> { - Autopkgtest::new() - .changes_file(self.args.changes_file.to_str().ok_or(SbuildError::GenericError( - "Invalid changes file path".to_string(), - ))?) - .no_built_binaries() - .apt_upgrade() - .test_deps_not_in_debian(&&self.args.test_deps) - .qemu(self.args.image_path.clone().unwrap()) - .working_dir(&self.args.deb_dir) - .execute()?; - Ok(()) - } -} - -fn extract_version_from_apt_output(output: &str) -> Result { - let version = output - .lines() - .filter(|line| line.trim_start().starts_with("autopkgtest")) - .flat_map(|line| line.split_whitespace()) - .find(|&word| { - let has_digits = word.chars().any(|c| c.is_digit(10)); - let has_dot = word.contains('.'); - has_digits && has_dot - }) - .ok_or_else(|| SbuildError::GenericError("Could not find version string".to_string()))?; - - // For Ubuntu-style versions (e.g., "5.38ubuntu1~24.04.1"), take only major.minor - // For Debian-style versions (e.g., "5.20.3-1"), take the full version - let cleaned_version = if version.contains("ubuntu") || version.contains('~') { - // Ubuntu-style: take only major.minor - version - .split(|c: char| !c.is_digit(10) && c != '.') - .next() - .unwrap_or(version) - .trim() - } else { - // Debian-style: take the full version - version.trim() - }; - - let version = AutopkgtestVersion::try_from(cleaned_version)?; - Ok(version) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::configs::autopkgtest_version::AutopkgtestVersion; - - #[test] - fn test_extract_version_from_apt_output_debian() { - // Standard apt list output - let output = "Listing... Done\nautopkgtest/stable,now 5.20 amd64 [installed]"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_ok()); - let expected_version = AutopkgtestVersion::try_from("5.20").unwrap(); - assert_eq!(extracted.unwrap(), expected_version); - - // Multiple lines with version in the middle - let output = "Listing... Done\npkg1/stable 1.0\nautopkgtest/stable,now 5.20.3-1 amd64 [installed]\npkg2/stable 2.0"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_ok()); - let expected_version = AutopkgtestVersion::try_from("5.20.3-1").unwrap(); - assert_eq!(extracted.unwrap(), expected_version); - - // No version digit - let output = "Listing... Done\nautopkgtest not installed"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_err()); - - // Empty output - let output = ""; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_err()); - - // Version with multiple dots - let output = "autopkgtest/stable,now 5.20.3.2 amd64 [installed]"; - let extracted = extract_version_from_apt_output(output); - - assert!(extracted.is_err()); - } - - #[test] - fn test_extract_version_from_apt_output_ubuntu() { - // Standard apt list output - let output = - "Listing...\nautopkgtest/noble-updates,now 5.38ubuntu1~24.04.1 all [installed]"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_ok()); - let expected_version = AutopkgtestVersion::try_from("5.38").unwrap(); - assert_eq!(extracted.unwrap(), expected_version); - - // Multiple lines with version in the middle - let output = "Listing... Done\npkg1/stable 1.0\nListing...\nautopkgtest/noble-updates,now 5.38ubuntu1~24.04.1 all [installed]\npkg2/stable 2.0"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_ok()); - let expected_version = AutopkgtestVersion::try_from("5.38").unwrap(); - assert_eq!(extracted.unwrap(), expected_version); - - // No version digit - let output = "Listing... Done\nautopkgtest not installed"; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_err()); - - // Empty output - let output = ""; - let extracted = extract_version_from_apt_output(output); - assert!(extracted.is_err()); - } -} diff --git a/workspace/packager_deb/src/tools/lintian_tool.rs b/workspace/packager_deb/src/tools/lintian_tool.rs deleted file mode 100644 index ccd08a76..00000000 --- a/workspace/packager_deb/src/tools/lintian_tool.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::{path::PathBuf, process::Command}; - -use debian::{execute::Execute, lintian::Lintian}; -use log::{info, warn}; -use types::{distribution::Distribution, version::Version}; - -use crate::sbuild::SbuildError; - -use super::tool_runner::{BuildTool, ToolRunner}; - -pub struct LintianToolArgs { - pub (crate) version: Version, - pub (crate) changes_file: PathBuf, - pub (crate) codename: Distribution, -} - -pub struct LintianTool { - args: LintianToolArgs, -} - -impl LintianTool { - pub fn new(args: LintianToolArgs) -> Self { - LintianTool { args } - } -} - -impl BuildTool for LintianTool { - fn name(&self) -> &str { - "lintian" - } - fn check_tool_version(&self) -> Result<(), SbuildError> { - let output = Command::new(self.name()).arg("--version").output()?; - if !output.status.success() { - return Err(SbuildError::GenericError(format!( - "Failed to check {} version", - self.name() - ))); - } - let stdout_str = String::from_utf8_lossy(&output.stdout).to_string(); - let actual_version = Version::try_from(stdout_str)?; - - match self.args.version.cmp(&actual_version) { - std::cmp::Ordering::Less => warn!( - "Using newer {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Greater => warn!( - "Using older {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Equal => info!("{} versions match ({})", self.name(), self.args.version), - } - Ok(()) - } - fn configure(&mut self, _runner: &mut ToolRunner) -> Result<(), SbuildError> { - // Configure Lintian-specific options - Ok(()) - } - fn execute(&self) -> Result<(), SbuildError> { - Lintian::new() - .suppress_tag("bad-distribution-in-changes-file") - .info() - .extended_info() - .changes_file(&self.args.changes_file) - .tag_display_limit(0) - .fail_on_warning() - .fail_on_error() - .suppress_tag("debug-file-with-no-debug-symbols") - .with_codename(&self.args.codename) - .execute()?; - Ok(()) - } -} diff --git a/workspace/packager_deb/src/tools/mod.rs b/workspace/packager_deb/src/tools/mod.rs deleted file mode 100644 index b171cd1e..00000000 --- a/workspace/packager_deb/src/tools/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod autopkgtest_tool; -pub mod lintian_tool; -pub mod piuparts_tool; -pub mod sbuild_tool; -pub mod tool_runner; diff --git a/workspace/packager_deb/src/tools/piuparts_tool.rs b/workspace/packager_deb/src/tools/piuparts_tool.rs deleted file mode 100644 index 8cf8a631..00000000 --- a/workspace/packager_deb/src/tools/piuparts_tool.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::{path::PathBuf, process::Command}; - -use debian::{execute::Execute, piuparts::Piuparts}; -use log::{info, warn}; -use types::{distribution::Distribution, version::Version}; - -use crate::{ - configs::pkg_config::LanguageEnv, misc::distribution::DistributionTrait, sbuild::SbuildError, -}; - -use super::tool_runner::{BuildTool, ToolRunner}; - -pub struct PiupartsToolArgs { - pub(crate) version: Version, - pub(crate) codename: Distribution, - pub(crate) deb_dir: PathBuf, - pub(crate) language_env: Option, - pub(crate) deb_name: PathBuf, -} - -pub struct PiupartsTool { - args: PiupartsToolArgs, -} - -impl PiupartsTool { - pub fn new(args: PiupartsToolArgs) -> Self { - PiupartsTool { args } - } -} - -impl BuildTool for PiupartsTool { - fn name(&self) -> &str { - "piuparts" - } - fn check_tool_version(&self) -> Result<(), SbuildError> { - let output = Command::new(self.name()).arg("--version").output()?; - if !output.status.success() { - return Err(SbuildError::GenericError(format!( - "Failed to check {} version", - self.name() - ))); - } - let stdout_str = String::from_utf8_lossy(&output.stdout).to_string(); - let actual_version = Version::try_from(stdout_str.replace("piuparts ", "").trim())?; - - match self.args.version.cmp(&actual_version) { - std::cmp::Ordering::Less => warn!( - "Using newer {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Greater => warn!( - "Using older {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Equal => info!("{} versions match ({})", self.name(), self.args.version), - } - Ok(()) - } - fn configure(&mut self, _runner: &mut ToolRunner) -> Result<(), SbuildError> { - // Configure piuparts - Ok(()) - } - fn execute(&self) -> Result<(), SbuildError> { - Piuparts::new() - .distribution(&self.args.codename) - .mirror(&self.args.codename.get_repo_url()) - .bindmount_dev() - .keyring(&self.args.codename.get_keyring()) - .verbose() - .with_dotnet_env( - matches!(self.args.language_env, Some(LanguageEnv::Dotnet(_))), - &self.args.codename, - ) - .deb_file(&self.args.deb_name) - .deb_path(&self.args.deb_dir) - .execute()?; - Ok(()) - } -} diff --git a/workspace/packager_deb/src/tools/sbuild_tool.rs b/workspace/packager_deb/src/tools/sbuild_tool.rs deleted file mode 100644 index 8e04afe1..00000000 --- a/workspace/packager_deb/src/tools/sbuild_tool.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::{path::PathBuf, process::Command}; - -use debian::{execute::Execute, sbuild::SbuildBuilder}; -use log::{error, info, warn}; -use types::distribution::Distribution; - -use crate::{ - configs::{pkg_config::PackageType, sbuild_version::SbuildVersion}, - misc::{ - build_pipeline::BuildContext, - sbuild_pipelines::{SbuildGitPipeline, SbuildSourcePipeline, SbuildVirtualPipeline}, - }, - sbuild::SbuildError, -}; - -use super::tool_runner::{BuildTool, ToolRunner}; - -pub struct SbuildToolArgs { - pub(crate) version: SbuildVersion, - pub(crate) codename: Distribution, - pub(crate) cache_file: PathBuf, - pub(crate) build_chroot_setup_commands: Vec, - pub(crate) run_lintian: bool, - pub(crate) build_files_dir: PathBuf, - pub(crate) package_type: PackageType, - pub(crate) context: BuildContext, -} -pub struct SbuildTool { - args: SbuildToolArgs, -} - -impl SbuildTool { - pub fn new(args: SbuildToolArgs) -> Self { - SbuildTool { args } - } -} - -impl BuildTool for SbuildTool { - fn name(&self) -> &str { - "sbuild" - } - fn check_tool_version(&self) -> Result<(), SbuildError> { - let output = Command::new(self.name()).arg("--version").output()?; - if !output.status.success() { - return Err(SbuildError::GenericError(format!( - "Failed to check {} version", - self.name() - ))); - } - let stdout_str = String::from_utf8_lossy(&output.stdout).to_string(); - let actual_version = SbuildVersion::try_from(stdout_str)?; - - match self.args.version.cmp(&actual_version) { - std::cmp::Ordering::Less => warn!( - "Using newer {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Greater => error!( - "Using older {} version ({}) than expected ({})", - self.name(), - actual_version, - self.args.version - ), - std::cmp::Ordering::Equal => info!("{} versions match ({})", self.name(), self.args.version), - } - Ok(()) - } - fn configure(&mut self, _runner: &mut ToolRunner) -> Result<(), SbuildError> { - info!("Using build context: {:#?}", self.args.context); - match &self.args.package_type { - PackageType::Default(_) => { - let sbuild_setup = SbuildSourcePipeline::new(self.args.context.clone()); - sbuild_setup.execute()?; - } - PackageType::Git(_) => { - let sbuild_setup = SbuildGitPipeline::new(self.args.context.clone()); - sbuild_setup.execute()?; - } - PackageType::Virtual => { - let sbuild_setup = SbuildVirtualPipeline::new(self.args.context.clone()); - sbuild_setup.execute()?; - } - }; - Ok(()) - } - fn execute(&self) -> Result<(), SbuildError> { - let builder = SbuildBuilder::new() - .distribution(&self.args.codename) - .build_arch_all() - .build_source() - .cache_file(self.args.cache_file.clone()) - .verbose() - .chroot_mode_unshare() - .setup_commands(&self.args.build_chroot_setup_commands) - .no_run_piuparts() - .no_apt_upgrades() - .run_lintian(self.args.run_lintian) - .no_run_autopkgtest() - .working_dir(&self.args.build_files_dir); - - builder.execute()?; - - Ok(()) - } -} diff --git a/workspace/packager_deb/src/tools/tool_runner.rs b/workspace/packager_deb/src/tools/tool_runner.rs deleted file mode 100644 index 4b0d8fe5..00000000 --- a/workspace/packager_deb/src/tools/tool_runner.rs +++ /dev/null @@ -1,27 +0,0 @@ -use log::info; -// use types::version::Version; - -use crate::sbuild::SbuildError; - -pub trait BuildTool { - fn name(&self) -> &str; - fn check_tool_version(&self) -> Result<(), SbuildError>; - fn configure(&mut self, runner: &mut ToolRunner) -> Result<(), SbuildError>; - fn execute(&self) -> Result<(), SbuildError>; -} - -pub struct ToolRunner {} - -impl ToolRunner { - pub fn new() -> Self { - ToolRunner {} - } - - pub fn run_tool(&mut self, mut tool: T) -> Result<(), SbuildError> { - info!("Running {}...", tool.name()); - tool.check_tool_version()?; - tool.configure(self)?; - tool.execute()?; - Ok(()) - } -} diff --git a/workspace/packager_deb/test_file.txt b/workspace/packager_deb/test_file.txt deleted file mode 100644 index 08cf6101..00000000 --- a/workspace/packager_deb/test_file.txt +++ /dev/null @@ -1 +0,0 @@ -test content \ No newline at end of file diff --git a/workspace/packager_deb/tests/misc/test_package.tar.gz b/workspace/packager_deb/tests/misc/test_package.tar.gz deleted file mode 100644 index 07dc25a6..00000000 Binary files a/workspace/packager_deb/tests/misc/test_package.tar.gz and /dev/null differ diff --git a/workspace/pkg_builder/Cargo.toml b/workspace/pkg_builder/Cargo.toml deleted file mode 100644 index 6fbf97f3..00000000 --- a/workspace/pkg_builder/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "pkg-builder" -version = "0.3.1" -edition = "2024" -build = "src/build.rs" - -[[bin]] -name = "pkg-builder" -path = "src/main.rs" - - -[build-dependencies] -thiserror = { workspace = true } -serde = { workspace = true } -toml = { workspace = true } - -[dependencies] -cli = { workspace = true } \ No newline at end of file diff --git a/workspace/pkg_builder/bin_dependencies/.crates.toml b/workspace/pkg_builder/bin_dependencies/.crates.toml deleted file mode 100644 index 4fb4c9fa..00000000 --- a/workspace/pkg_builder/bin_dependencies/.crates.toml +++ /dev/null @@ -1,2 +0,0 @@ -[v1] -"debcrafter 0.2.0 (git+https://github.com/Kixunil/debcrafter?rev=8189263#8189263400e69b747dcbf45de0a702993566fe47)" = ["debcrafter"] diff --git a/workspace/pkg_builder/bin_dependencies/.crates2.json b/workspace/pkg_builder/bin_dependencies/.crates2.json deleted file mode 100644 index fa608923..00000000 --- a/workspace/pkg_builder/bin_dependencies/.crates2.json +++ /dev/null @@ -1 +0,0 @@ -{"installs":{"debcrafter 0.2.0 (git+https://github.com/Kixunil/debcrafter?rev=8189263#8189263400e69b747dcbf45de0a702993566fe47)":{"version_req":null,"bins":["debcrafter"],"features":[],"all_features":false,"no_default_features":false,"profile":"release","target":"x86_64-unknown-linux-gnu","rustc":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.0\nLLVM version: 19.1.7\n"}}} \ No newline at end of file diff --git a/workspace/pkg_builder/bin_dependencies/debcrafter_2711b53 b/workspace/pkg_builder/bin_dependencies/debcrafter_2711b53 deleted file mode 100755 index 683099f3..00000000 Binary files a/workspace/pkg_builder/bin_dependencies/debcrafter_2711b53 and /dev/null differ diff --git a/workspace/pkg_builder/bin_dependencies/debcrafter_8189263 b/workspace/pkg_builder/bin_dependencies/debcrafter_8189263 deleted file mode 100755 index 63357768..00000000 Binary files a/workspace/pkg_builder/bin_dependencies/debcrafter_8189263 and /dev/null differ diff --git a/workspace/pkg_builder/src/build.rs b/workspace/pkg_builder/src/build.rs deleted file mode 100644 index 53153fd3..00000000 --- a/workspace/pkg_builder/src/build.rs +++ /dev/null @@ -1,140 +0,0 @@ -use serde::Deserialize; -use std::fs; -use std::io; -use std::path::Path; -use std::process::Command; - -#[derive(Debug, Deserialize)] -pub struct Dependency { - pub url: String, - pub commit_hash: String, - pub binary_name: String, - pub original_binary_name: String, -} - -#[derive(Debug, Deserialize)] -pub struct Dependencies { - pub binaries: Vec, -} - -#[derive(Debug, Deserialize)] -pub struct Config { - pub dependencies: Dependencies, -} - -impl Config { - pub fn load_config() -> Result { - let toml_str = include_str!("dependencies.toml"); - let config = toml::from_str(toml_str).map_err(|e| ConfigError::TomlParseError(e))?; - Ok(config) - } -} - -#[derive(thiserror::Error, Debug)] -pub enum ConfigError { - #[error("Failed to parse TOML: {0}")] - TomlParseError(#[from] toml::de::Error), - - #[error("IO error: {0}")] - IoError(#[from] io::Error), - - #[error("Other error: {0}")] - Other(String), -} - -#[derive(thiserror::Error, Debug)] -pub enum CargoError { - #[error("Non-zero exit status: {0}")] - StatusError(String), - - #[error("IO error: {0}")] - IoError(#[from] io::Error), - - #[error("Other error: {0}")] - Other(String), -} - -pub struct Cargo<'a> { - repo_url: &'a str, - commit_hash: &'a str, -} - -impl<'a> Cargo<'a> { - // fn install_from_crates_io>(&self, bin_dir: P) -> Result<(), CargoError> { - // todo!() - // } - - fn install_from_git>(&self, bin_dir: P) -> Result<(), CargoError> { - let output = Command::new("cargo") - .arg("install") - .arg("--git") - .arg(self.repo_url) - .arg("--rev") - .arg(self.commit_hash) - .arg("--root") - .arg(bin_dir.as_ref()) - .output() - .map_err(|e| CargoError::IoError(e))?; - - if output.status.success() { - Ok(()) - } else { - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - Err(CargoError::StatusError(format!( - "Cargo install failed with exit code {:?}\nstdout: {}\nstderr: {}", - output.status.code(), - stdout, - stderr - ))) - } - } -} - -#[derive(thiserror::Error, Debug)] -pub enum DependencyError { - #[error(transparent)] - CargoError(#[from] CargoError), - - #[error("IO error: {0}")] - IoError(#[from] io::Error), - - #[error("Other error: {0}")] - Other(String), -} - -impl Dependency { - fn install_binary(&self, bin_dir: String) -> Result<(), DependencyError> { - fs::create_dir_all(&bin_dir).map_err(|e| DependencyError::IoError(e))?; - - let binary_path = Path::new(&bin_dir.clone()).join(&self.binary_name); - let bin_dir = Path::new(&bin_dir); - let original_binary_name_path = bin_dir.join("bin").join(&self.original_binary_name); - - if !binary_path.exists() { - let cargo = Cargo { - repo_url: &self.url, - commit_hash: &self.commit_hash, - }; - - cargo.install_from_git(bin_dir)?; - - fs::rename(original_binary_name_path, binary_path) - .map_err(|e| DependencyError::IoError(e))?; - } - - Ok(()) - } -} - -pub fn main() { - let bin_dir = format!("{}/bin_dependencies", "."); - let config = Config::load_config().expect("Could not load config"); - let dependencies = config.dependencies.binaries; - - dependencies.iter().for_each(|d| { - let _ = d.install_binary(bin_dir.clone()); - }); - - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/workspace/pkg_builder/src/dependencies.toml b/workspace/pkg_builder/src/dependencies.toml deleted file mode 100644 index 790bf7c9..00000000 --- a/workspace/pkg_builder/src/dependencies.toml +++ /dev/null @@ -1,5 +0,0 @@ -[dependencies] -binaries = [ - { url = "https://github.com/Kixunil/debcrafter", commit_hash = "2711b53", binary_name = "debcrafter_2711b53", original_binary_name="debcrafter"}, - { url = "https://github.com/Kixunil/debcrafter", commit_hash = "8189263", binary_name = "debcrafter_8189263", original_binary_name="debcrafter"} -] diff --git a/workspace/pkg_builder/src/main.rs b/workspace/pkg_builder/src/main.rs deleted file mode 100644 index 1303dea5..00000000 --- a/workspace/pkg_builder/src/main.rs +++ /dev/null @@ -1,14 +0,0 @@ -use cli::cli::run_cli; - -fn main() { - let result = run_cli(); - match result { - Ok(_) => { - std::process::exit(0); - } - Err(err) => { - println!("Failed to run: {:?}", err); - std::process::exit(1); - } - } -} diff --git a/workspace/types/Cargo.toml b/workspace/types/Cargo.toml deleted file mode 100644 index 4911dcb0..00000000 --- a/workspace/types/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "types" -version = "0.1.0" -edition = "2021" - -[lib] -name = "types" -path = "src/mod.rs" - -[dependencies] -serde ={ workspace = true} -thiserror = { workspace = true} -log = { workspace = true} -toml = { workspace = true} -semver = { workspace = true} -tempfile = {workspace = true} -url = { workspace = true } diff --git a/workspace/types/src/config.rs b/workspace/types/src/config.rs deleted file mode 100644 index 9a20249b..00000000 --- a/workspace/types/src/config.rs +++ /dev/null @@ -1,285 +0,0 @@ -use log::warn; -use semver::Version; -use serde::de::Error as SerdeError; -use serde::{Deserialize, Serialize}; -use std::fmt; -use std::{ - borrow::Cow, - cmp::Ordering, - env, fs, - io::{self, ErrorKind}, - marker::PhantomData, - path::PathBuf, -}; -use thiserror::Error; -use toml::de::Error as TomlError; - -use crate::{ - defaults::{CONFIG_FILE_NAME, WORKDIR_ROOT}, - distribution::Distribution, -}; - -/// Represents the raw configuration file content -#[derive(Debug, Clone)] -pub struct ConfigFile { - content: Cow<'static, str>, - _marker: PhantomData, - pub path: PathBuf, -} -impl AsRef for ConfigFile { - fn as_ref(&self) -> &str { - &self.content - } -} - -/// Errors that can occur during configuration handling -#[derive(Debug, Error)] -pub enum ConfigError { - /// Error parsing TOML content - #[error("TOML parsing error: {0}")] - TomlParse(#[from] toml::de::Error), - - /// I/O error during file operations - #[error("I/O error: {0}")] - Io(#[from] io::Error), - - /// Version parsing error - #[error("Version parsing error: {0}")] - VersionParse(#[from] semver::Error), - - /// Incompatible package version - #[error("{0}")] - IncompatibleVersion(String), -} - -pub trait ConfigType { - fn default_config_path() -> &'static str; -} - -impl ConfigFile { - /// Loads configuration from the specified location or the current directory - /// - /// # Arguments - /// - /// * `config_path` - Optional path to configuration file or directory - /// - /// # Returns - /// - /// * `Result, ConfigError>` - The loaded configuration or an error - pub fn load(config_path: Option) -> Result { - let path = Self::resolve_config_path(config_path)?; - let content = fs::read_to_string(&path).map_err(ConfigError::Io)?; - Ok(ConfigFile { - content: Cow::Owned(content), - _marker: PhantomData, - path, - }) - } - - /// Resolves the configuration file path - fn resolve_config_path(config_path: Option) -> Result { - let path = match config_path { - Some(location) => { - let path = PathBuf::from(location); - if path.is_dir() { - path.join(T::default_config_path()) - } else { - path - } - } - None => env::current_dir() - .map_err(ConfigError::Io)? - .join(T::default_config_path()), - }; - - if !path.exists() { - return Err(ConfigError::Io(io::Error::new( - ErrorKind::NotFound, - format!("Path does not exist: {}", path.display()), - ))); - } - - Ok(path) - } - - /// Parses the configuration content into the generic type T - /// - /// # Returns - /// - /// * `Result` - The parsed configuration or an error - pub fn parse(self) -> Result - where - T: for<'de> serde::Deserialize<'de>, - { - toml::from_str::(&self.content).map_err(|e| { - if let Some(span) = e.span() { - let detailed_message = - format!("Error at position {}-{}: {}", span.start, span.end, e); - ConfigError::from(TomlError::custom(detailed_message)) - } else { - ConfigError::from(e) - } - }) - } - - /// Convenience method to load and parse in one operation - /// - /// # Arguments - /// - /// * `config_path` - Optional path to configuration file or directory - /// - /// # Returns - /// - /// * `Result` - The parsed configuration or an error - pub fn load_and_parse(config_path: Option) -> Result - where - T: for<'de> serde::Deserialize<'de>, - { - Self::load(config_path)?.parse() - } -} - -// not needed, just for wrapping the header -#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)] -pub struct Config { - pub build_env: BuildEnv, -} -impl ConfigType for Config { - fn default_config_path() -> &'static str { - &CONFIG_FILE_NAME - } -} - -/// Build environment configuration -#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)] -pub struct BuildEnv { - /// Distribution codename - pub codename: Distribution, - - /// Working directory path - pub workdir: PathBuf, - - /// Required pkg-builder version - pub pkg_builder_version: Version, -} - -impl BuildEnv { - /// Validate and apply defaults to the build environment configuration - /// - /// # Arguments - /// - /// * `current_pkg_version` - The current pkg-builder version to validate against - /// - /// # Returns - /// - /// * `Result` - The validated configuration or an error - pub fn validate_and_apply_defaults( - mut self, - current_pkg_version: &str, - ) -> Result { - // Parse the current version for comparison - let current_version = - Version::parse(current_pkg_version).map_err(ConfigError::VersionParse)?; - - let required_version = &self.pkg_builder_version; - - match required_version.cmp(¤t_version) { - Ordering::Greater => { - let incompatible_version = ConfigError::IncompatibleVersion(format!( - "Required pkg-builder version {} is higher than current version {}", - required_version, current_version - )); - return Err(incompatible_version); - } - Ordering::Less => { - warn!( - "Required pkg-builder version {} is lower than current version {}. This may cause compatibility issues.", - required_version, current_version - ); - } - Ordering::Equal => { - // Versions match, no action needed - } - } - - if self.workdir.as_os_str().is_empty() { - let default_path = format!("{}/{}", WORKDIR_ROOT, self.codename); - self.workdir = PathBuf::from(default_path); - } - - Ok(self) - } -} - - -#[derive(Debug, Deserialize, PartialEq, Clone)] -pub enum Architecture { - #[serde(rename = "amd64")] - Amd64 -} - -impl fmt::Display for Architecture { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Architecture::Amd64 => write!(f, "amd64"), - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use std::fs::File; - use std::io::Write; - use tempfile::tempdir; - - #[test] - fn test_config_file_load() { - let dir = tempdir().unwrap(); - let config_path = dir.path().join(CONFIG_FILE_NAME); - let mut file = File::create(&config_path).unwrap(); - - writeln!( - file, - r#" - [build_env] - codename = "noble numbat" - workdir = "/tmp/test" - pkg_builder_version = "1.0.0" - "# - ) - .unwrap(); - - let config_file = - ConfigFile::::load(Some(dir.path().to_string_lossy().to_string())).unwrap(); - assert!(config_file.content.contains("noble numbat")); - } - - #[test] - fn test_config_file_parse() { - let dir = tempdir().unwrap(); - let config_path = dir.path().join(CONFIG_FILE_NAME); - let mut file = File::create(&config_path).unwrap(); - - writeln!( - file, - r#" - [build_env] - codename = "noble numbat" - workdir = "/tmp/test" - pkg_builder_version = "1.0.0" - "# - ) - .unwrap(); - - let config_file = - ConfigFile::::load(Some(dir.path().to_string_lossy().to_string())).unwrap(); - let config = config_file.parse(); - assert!(config.is_ok()); - let config = config.unwrap(); - assert_eq!(config.build_env.codename, Distribution::noble()); - assert_eq!(config.build_env.workdir, PathBuf::from("/tmp/test")); - assert_eq!(config.build_env.pkg_builder_version, Version::new(1, 0, 0)); - } -} diff --git a/workspace/types/src/debian.rs b/workspace/types/src/debian.rs deleted file mode 100644 index bceddec6..00000000 --- a/workspace/types/src/debian.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub enum DebCommandPayload { - Verify { - verify_config: Option, - no_package: Option, - }, - Lintian, - Piuparts, - Autopkgtest, - Package { - run_lintian: Option, - run_piuparts: Option, - run_autopkgtest: Option, - }, - EnvCreate, - EnvClean, -} diff --git a/workspace/types/src/defaults.rs b/workspace/types/src/defaults.rs deleted file mode 100644 index 9001219e..00000000 --- a/workspace/types/src/defaults.rs +++ /dev/null @@ -1,4 +0,0 @@ -/// Name of the default configuration file -pub const CONFIG_FILE_NAME: &str = "pkg-builder.toml"; -pub const VERIFY_CONFIG_FILE_NAME: &str = "pkg-builder-verify.toml"; -pub const WORKDIR_ROOT: &str = "~/.pkg-builder/packages"; diff --git a/workspace/types/src/distribution.rs b/workspace/types/src/distribution.rs deleted file mode 100644 index 6af9d189..00000000 --- a/workspace/types/src/distribution.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::fmt; - -use serde::de; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum DistributionError { - #[error("Unsupported distribution codename: {0}")] - UnsupportedCodename(String), -} - -/// Represents supported Linux distributions for VM image creation -/// -/// Each variant contains the specific codename for the distribution -/// which is used to identify compatible build commands and arguments. -#[derive(Debug, Clone, PartialEq)] -pub enum Distribution { - /// Debian distribution - Debian(DebianCodename), - /// Ubuntu distribution - Ubuntu(UbuntuCodename), -} -impl fmt::Display for Distribution { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Distribution::Debian(debian) => debian.fmt(f), - Distribution::Ubuntu(ubuntu) => ubuntu.fmt(f), - } - } -} -/// Supported Debian codenames -#[derive(Debug, Clone, PartialEq)] -pub enum DebianCodename { - Bookworm, -} - -impl DebianCodename { - /// Get the string representation of the codename - pub fn as_str(&self) -> &'static str { - match self { - DebianCodename::Bookworm => "bookworm", - } - } - - pub fn as_short(&self) -> &'static str { - match self { - DebianCodename::Bookworm => "bookworm", - } - } -} -impl fmt::Display for DebianCodename { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.as_str()) - } -} -/// Supported Ubuntu codenames -#[derive(Debug, Clone, PartialEq)] -pub enum UbuntuCodename { - Noble, - Jammy, -} - -impl UbuntuCodename { - /// Get the string representation of the codename - pub fn as_str(&self) -> &'static str { - match self { - UbuntuCodename::Noble => "noble numbat", - UbuntuCodename::Jammy => "jammy jellyfish", - } - } - pub fn as_short(&self) -> &'static str { - match self { - UbuntuCodename::Noble => "noble", - UbuntuCodename::Jammy => "jammy", - } - } -} - -impl fmt::Display for UbuntuCodename { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl Distribution { - /// Creates a Debian Bookworm distribution - pub fn bookworm() -> Self { - Distribution::Debian(DebianCodename::Bookworm) - } - - /// Creates an Ubuntu Noble Numbat distribution - pub fn noble() -> Self { - Distribution::Ubuntu(UbuntuCodename::Noble) - } - - /// Creates an Ubuntu Jammy Jellyfish distribution - pub fn jammy() -> Self { - Distribution::Ubuntu(UbuntuCodename::Jammy) - } - - /// Creates a Distribution from a codename string - /// - /// # Arguments - /// * `codename` - The distribution codename (e.g., "bookworm", "noble") - /// - /// # Returns - /// * `Result` - A Distribution instance or an error if unsupported - pub fn from_codename(codename: &str) -> Result { - match codename { - "bookworm" => Ok(Self::bookworm()), - "noble" | "noble numbat" => Ok(Self::noble()), - "jammy" | "jammy jellyfish" => Ok(Self::jammy()), - _ => Err(DistributionError::UnsupportedCodename(codename.to_string())), - } - } - - pub fn as_short(&self) -> &str { - match self { - Distribution::Debian(codename) => codename.as_short(), - Distribution::Ubuntu(codename) => codename.as_short(), - } - } -} - -impl AsRef for Distribution { - fn as_ref(&self) -> &str { - match self { - Distribution::Debian(codename) => codename.as_str(), - Distribution::Ubuntu(codename) => codename.as_str(), - } - } -} -impl Serialize for Distribution { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Distribution::Debian(codename) => serializer.serialize_str(codename.as_str()), - Distribution::Ubuntu(codename) => serializer.serialize_str(codename.as_str()), - } - } -} - -impl<'de> Deserialize<'de> for Distribution { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let codename = String::deserialize(deserializer)?; - Distribution::from_codename(&codename).map_err(|e| de::Error::custom(format!("{}", e))) - } -} diff --git a/workspace/types/src/mod.rs b/workspace/types/src/mod.rs deleted file mode 100644 index 81406efe..00000000 --- a/workspace/types/src/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod distribution; - -pub mod config; -pub mod debian; -pub mod defaults; -pub mod url; -pub mod version; diff --git a/workspace/types/src/url.rs b/workspace/types/src/url.rs deleted file mode 100644 index 052e1827..00000000 --- a/workspace/types/src/url.rs +++ /dev/null @@ -1,92 +0,0 @@ -use serde::{de, Deserialize, Deserializer, Serialize}; -use std::fmt; -use std::ops::{Deref, DerefMut}; -use url::Url as OriginalUrl; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Url(OriginalUrl); - -impl Serialize for Url { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.0.as_str()) - } -} - -impl Deref for Url { - type Target = OriginalUrl; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Url { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl From for Url { - fn from(url: OriginalUrl) -> Self { - Url(url) - } -} - -impl Url { - pub fn into_inner(self) -> OriginalUrl { - self.0 - } -} - -impl<'a> TryFrom<&'a str> for Url { - type Error = url::ParseError; - - fn try_from(s: &'a str) -> Result { - let inner = OriginalUrl::parse(s)?; - Ok(Url(inner)) - } -} - -impl TryFrom for Url { - type Error = url::ParseError; - - fn try_from(s: String) -> Result { - >::try_from(&s) - } -} - -impl<'de> Deserialize<'de> for Url { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct UrlVisitor; - - impl<'de> de::Visitor<'de> for UrlVisitor { - type Value = Url; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a string containing a valid URL") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - OriginalUrl::parse(value) - .map(Url) - .map_err(de::Error::custom) - } - } - - deserializer.deserialize_string(UrlVisitor) - } -} - -impl AsRef for Url { - fn as_ref(&self) -> &str { - self.0.as_str() - } -} diff --git a/workspace/types/src/version.rs b/workspace/types/src/version.rs deleted file mode 100644 index c4ea8b49..00000000 --- a/workspace/types/src/version.rs +++ /dev/null @@ -1,111 +0,0 @@ -use semver::Version as OriginalVersion; -use serde::{de, Deserialize, Deserializer, Serialize}; -use std::borrow::Cow; -use std::fmt; -use std::ops::{Deref, DerefMut}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Version { - inner: OriginalVersion, - original_string: Cow<'static, str>, -} - -impl fmt::Display for Version { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.original_string) - } -} - -impl Version { - pub fn as_str(&self) -> &str { - &self.original_string - } -} - -impl Serialize for Version { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.original_string) - } -} - -impl Deref for Version { - type Target = OriginalVersion; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for Version { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl From for Version { - fn from(version: OriginalVersion) -> Self { - let original_string = Cow::Owned(version.to_string()); - Version { - inner: version, - original_string, - } - } -} - -impl Version { - pub fn into_inner(self) -> OriginalVersion { - self.inner - } -} - -impl<'a> TryFrom<&'a str> for Version { - type Error = semver::Error; - - fn try_from(s: &'a str) -> Result { - let inner = OriginalVersion::parse(s)?; - Ok(Version { - inner, - original_string: Cow::Owned(s.to_string()), - }) - } -} - -impl TryFrom for Version { - type Error = semver::Error; - - fn try_from(s: String) -> Result { - >::try_from(&s) - } -} - -impl<'de> Deserialize<'de> for Version { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VersionVisitor; - - impl<'de> de::Visitor<'de> for VersionVisitor { - type Value = Version; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a string containing a valid semantic version (e.g., 1.2.3)") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let inner = OriginalVersion::parse(value).map_err(de::Error::custom)?; - Ok(Version { - inner, - original_string: Cow::Owned(value.to_string()), - }) - } - } - - deserializer.deserialize_string(VersionVisitor) - } -}