diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..41db8dbc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.go/ +.git/ +obj-x86_64-linux-gnu/ +unit.out +aptly.test +build/ diff --git a/.flake8 b/.flake8 index 607808a1..393ab659 100644 --- a/.flake8 +++ b/.flake8 @@ -1,7 +1,7 @@ [flake8] -max-line-length = 200 +max-line-length = 240 ignore = E126,E241,E741,W504 include = system exclude = - system/env \ No newline at end of file + system/env diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..0da3c1d3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: aptly-dev diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a58ddb7..17f28d64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,3 @@ -# Based on https://github.com/aptly-dev/aptly/blob/master/.travis.yml - name: CI on: @@ -13,32 +11,17 @@ on: defaults: run: # see: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell - shell: bash --noprofile --norc -eo pipefail -x {0} + shell: bash --noprofile --norc -eo pipefail {0} env: DEBIAN_FRONTEND: noninteractive jobs: - build: - name: test - runs-on: ubuntu-20.04 - continue-on-error: ${{ matrix.allow_failure }} + test: + name: "Test (Ubuntu 22.04)" + runs-on: ubuntu-22.04 + continue-on-error: false timeout-minutes: 30 - strategy: - fail-fast: true - matrix: - go: [1.16, 1.17, 1.18] - run_long_tests: [no] - allow_failure: [false] - include: - # Disable this for now as it's not clear how to select the latest master branch - # version of go using actions/setup-go@v2. - # - go: master - # run_long_tests: no - # allow_failure: true - - go: 1.17 - run_long_tests: yes - allow_failure: false env: NO_FTP_ACCESS: yes @@ -47,101 +30,253 @@ jobs: GOPROXY: "https://proxy.golang.org" steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} - - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: v1.45.0 - - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - - name: Install O/S packages + - name: "Install packages" run: | sudo apt-get update - sudo apt-get install -y graphviz gnupg1 gnupg2 gpgv1 gpgv2 git gcc make + sudo apt-get install -y --no-install-recommends graphviz gnupg2 gpgv2 git gcc make devscripts python3 python3-requests-unixsocket python3-termcolor python3-swiftclient python3-boto python3-azure-storage python3-etcd3 python3-plyvel flake8 - - name: Install Python packages + - name: "Checkout repository" + uses: actions/checkout@v4 + with: + # fetch the whole repo for `git describe` to work + fetch-depth: 0 + + - name: "Run flake8" run: | - pip install six packaging appdirs virtualenv - pip install -U pip setuptools - pip install -r system/requirements.txt + make flake8 - - name: Install Azurite + - name: "Read go version from go.mod" + run: | + gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod) + echo "Go Version: $gover" + echo "GOVER=$gover" >> $GITHUB_OUTPUT + id: goversion + + - name: "Setup Go" + uses: actions/setup-go@v3 + with: + go-version: ${{ steps.goversion.outputs.GOVER }} + + - name: "Install Azurite" id: azuright uses: potatoqualitee/azuright@v1.1 with: directory: ${{ runner.temp }} - - name: Get aptly version - run: | - make version - - - name: Make + - name: "Run Unit Tests" env: - RUN_LONG_TESTS: ${{ matrix.run_long_tests }} - AZURE_STORAGE_ENDPOINT: "127.0.0.1:10000" + RUN_LONG_TESTS: 'yes' + AZURE_STORAGE_ENDPOINT: "http://127.0.0.1:10000/devstoreaccount1" AZURE_STORAGE_ACCOUNT: "devstoreaccount1" AZURE_STORAGE_ACCESS_KEY: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | - make + sudo mkdir -p /srv ; sudo chown runner /srv + COVERAGE_DIR=${{ runner.temp }} make test - - name: Upload code coverage - if: matrix.run_long_tests + - name: "Run Benchmark" + run: | + COVERAGE_DIR=${{ runner.temp }} make bench + + - name: "Run System Tests" + env: + RUN_LONG_TESTS: 'yes' + AZURE_STORAGE_ENDPOINT: "http://127.0.0.1:10000/devstoreaccount1" + AZURE_STORAGE_ACCOUNT: "devstoreaccount1" + AZURE_STORAGE_ACCESS_KEY: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + sudo mkdir -p /srv ; sudo chown runner /srv + COVERAGE_DIR=${{ runner.temp }} make system-test + + - name: "Merge code coverage" + run: | + go install github.com/wadey/gocovmerge@latest + ~/go/bin/gocovmerge unit.out ${{ runner.temp }}/*.out > coverage.txt + + - name: "Upload code coverage" uses: codecov/codecov-action@v2 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage.txt - release: - name: release - needs: build - runs-on: ubuntu-20.04 + ci-debian-build: + name: "Build" + needs: test + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + name: ["Debian 13/testing", "Debian 12/bookworm", "Debian 11/bullseye", "Debian 10/buster", "Ubuntu 24.04", "Ubuntu 22.04", "Ubuntu 20.04"] + arch: ["amd64", "i386" , "arm64" , "armhf"] + include: + - name: "Debian 13/testing" + suite: trixie + image: debian:trixie-slim + - name: "Debian 12/bookworm" + suite: bookworm + image: debian:bookworm-slim + - name: "Debian 11/bullseye" + suite: bullseye + image: debian:bullseye-slim + - name: "Debian 10/buster" + suite: buster + image: debian:buster-slim + - name: "Ubuntu 24.04" + suite: noble + image: ubuntu:24.04 + - name: "Ubuntu 22.04" + suite: jammy + image: ubuntu:22.04 + - name: "Ubuntu 20.04" + suite: focal + image: ubuntu:20.04 + container: + image: ${{ matrix.image }} + env: + APT_LISTCHANGES_FRONTEND: none + DEBIAN_FRONTEND: noninteractive steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: "Install packages" + run: | + apt-get update + apt-get install -y --no-install-recommends make ca-certificates git curl build-essential devscripts dh-golang binutils-i686-linux-gnu binutils-aarch64-linux-gnu binutils-arm-linux-gnueabihf jq + git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - name: "Checkout repository" + uses: actions/checkout@v4 with: - # fetch the whole repot for `git describe` to - # work and get the nightly verion + # fetch the whole repo for `git describe` to work fetch-depth: 0 - - name: Setup Go - uses: actions/setup-go@v2 + - name: "Read go version from go.mod" + run: | + gover=$(sed -n 's/^go \(.*\)/\1/p' go.mod) + echo "Go Version: $gover" + echo "GOVER=$gover" >> $GITHUB_OUTPUT + id: goversion - - name: Make Release + - name: "Setup Go" + uses: actions/setup-go@v3 + with: + go-version: ${{ steps.goversion.outputs.GOVER }} + + - name: "Ensure CI build" + if: github.ref == 'refs/heads/master' + run: | + echo "FORCE_CI=true" >> $GITHUB_OUTPUT + id: force_ci + + - name: "Build Debian packages" + env: + FORCE_CI: ${{ steps.force_ci.outputs.FORCE_CI }} + run: | + make dpkg DEBARCH=${{ matrix.arch }} + + - name: "Check aptly credentials" + env: + APTLY_USER: ${{ secrets.APTLY_USER }} + APTLY_PASSWORD: ${{ secrets.APTLY_PASSWORD }} + run: | + found=no + if [ -n "$APTLY_USER" ] && [ -n "$APTLY_PASSWORD" ]; then + found=yes + fi + echo "Aptly credentials available: $found" + echo "FOUND=$found" >> $GITHUB_OUTPUT + id: aptlycreds + + - name: "Publish CI release to aptly" + if: github.ref == 'refs/heads/master' && steps.aptlycreds.outputs.FOUND == 'yes' + env: + APTLY_USER: ${{ secrets.APTLY_USER }} + APTLY_PASSWORD: ${{ secrets.APTLY_PASSWORD }} + run: | + .github/workflows/scripts/upload-artifacts.sh ci ${{ matrix.suite }} + + - name: "Publish release to aptly" + if: startsWith(github.event.ref, 'refs/tags') && steps.aptlycreds.outputs.FOUND == 'yes' + env: + APTLY_USER: ${{ secrets.APTLY_USER }} + APTLY_PASSWORD: ${{ secrets.APTLY_PASSWORD }} + run: | + .github/workflows/scripts/upload-artifacts.sh release ${{ matrix.suite }} + + ci-binary-build: + name: "Build" + needs: test + runs-on: ubuntu-latest + strategy: + matrix: + goos: [linux, freebsd, darwin] + goarch: ["386", "amd64", "arm", "arm64"] + exclude: + - goos: darwin + goarch: 386 + - goos: darwin + goarch: arm + steps: + - name: "Checkout repository" + uses: actions/checkout@v4 + with: + # fetch the whole repo for `git describe` to work + fetch-depth: 0 + + - name: "Read go version from go.mod" + run: | + echo "GOVER=$(sed -n 's/^go \(.*\)/\1/p' go.mod)" >> $GITHUB_OUTPUT + id: goversion + + - name: "Setup Go" + uses: actions/setup-go@v3 + with: + go-version: ${{ steps.goversion.outputs.GOVER }} + + - name: "Ensure CI build" + if: github.ref == 'refs/heads/master' + run: | + echo "FORCE_CI=true" >> $GITHUB_OUTPUT + id: force_ci + + - name: "Get aptly version" + env: + FORCE_CI: ${{ steps.force_ci.outputs.FORCE_CI }} + run: | + aptlyver=$(make -s version) + echo "Aptly Version: $aptlyver" + echo "VERSION=$aptlyver" >> $GITHUB_OUTPUT + id: releaseversion + + - name: "Build aptly ${{ matrix.goos }}/${{ matrix.goarch }}" env: GOBIN: /usr/local/bin + FORCE_CI: ${{ steps.force_ci.outputs.FORCE_CI }} run: | - make release + make binaries GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} - - name: Publish nightly release to aptly - if: github.ref == 'refs/heads/master' - env: - APTLY_USER: ${{ secrets.APTLY_USER }} - APTLY_PASSWORD: ${{ secrets.APTLY_PASSWORD }} - run: | - ./upload-artifacts.sh nightly - - - name: Publish release to aptly + - name: "Upload Artifacts" + uses: actions/upload-artifact@v4 if: startsWith(github.event.ref, 'refs/tags') - env: - APTLY_USER: ${{ secrets.APTLY_USER }} - APTLY_PASSWORD: ${{ secrets.APTLY_PASSWORD }} - run: | - ./upload-artifacts.sh release - - - name: Upload artifacts to GitHub Release - if: startsWith(github.event.ref, 'refs/tags') - uses: softprops/action-gh-release@v1 with: - body: Release ${{ github.ref }} generated by the CI. - files: build/* + name: aptly_${{ steps.releaseversion.outputs.VERSION }}_${{ matrix.goos }}_${{ matrix.goarch }} + path: build/aptly_${{ steps.releaseversion.outputs.VERSION }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip + compression-level: 0 # no compression + + gh-release: + name: "Github Release" + runs-on: ubuntu-latest + continue-on-error: false + needs: ci-binary-build + if: startsWith(github.event.ref, 'refs/tags') + steps: + - name: "Download Artifacts" + uses: actions/download-artifact@v4 + with: + path: out/ + + - name: "Release" + uses: softprops/action-gh-release@v2 + with: + files: "out/**/aptly_*.zip" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 00000000..8da4335a --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,72 @@ +name: golangci-lint +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: "Read go version from go.mod" + run: | + echo "GOVER=$(sed -n 's/^go \(.*\)/\1/p' go.mod)" >> $GITHUB_OUTPUT + id: goversion + + - name: "Setup Go" + uses: actions/setup-go@v3 + with: + go-version: ${{ steps.goversion.outputs.GOVER }} + + - name: Create VERSION file + run: | + make -s version | tr -d '\n' > VERSION + shell: sh + + - name: Install and initialize swagger + run: | + go install github.com/swaggo/swag/cmd/swag@latest + swag init -q --markdownFiles docs + shell: sh + + - name: golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + # Require: The version of golangci-lint to use. + # When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version. + # When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit. + version: v1.54.1 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # + # Note: By default, the `.golangci.yml` file should be at the root of the repository. + # The location of the configuration file can be changed by using `--config=` + # args: --timeout=30m --config=/my/path/.golangci.yml --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true, then all caching functionality will be completely disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true, then the action won't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true, then the action won't cache or restore ~/.cache/go-build. + # skip-build-cache: true + + # Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'. + # install-mode: "goinstall" diff --git a/.github/workflows/scripts/upload-artifacts.sh b/.github/workflows/scripts/upload-artifacts.sh new file mode 100755 index 00000000..e41697df --- /dev/null +++ b/.github/workflows/scripts/upload-artifacts.sh @@ -0,0 +1,144 @@ +#!/bin/sh + +set -e + +builds=build/ +packages=${builds}*.deb +folder=`mktemp -u tmp.XXXXXXXXXXXXXXX` +aptly_user="$APTLY_USER" +aptly_password="$APTLY_PASSWORD" +aptly_api="https://aptly-ops.aptly.info" +version=`make version` + +action=$1 +dist=$2 + +usage() { + echo "Usage: $0 ci buster|bullseye|bookworm|focal|jammy|noble" >&2 + echo " $0 release" >&2 +} + +# repos and publish must be created beforehand: +#!/bin/sh +#for dist in buster bullseye bookworm focal jammy noble +#do +# for build in ci release +# do +# echo +# echo "# Creating and publishing $build/$dist" +# aptly repo create -distribution=$dist -component=main aptly-$build-$dist +# aptly publish repo -multi-dist -architectures="amd64,i386,arm64,armhf" -acquire-by-hash -component=main \ +# -distribution=$dist -batch -keyring=aptly.pub \ +# aptly-$build-$dist \ +# s3:repo.aptly.info:$build +# done +#done + +if [ -z "$action" ]; then + usage + exit 1 +fi + +if [ "action" = "ci" ] && [ -z "$dist" ]; then + usage + exit 1 +fi + +if [ -z "$aptly_user" ] || [ -z "$aptly_password" ]; then + usage + echo Error: please set APTLY_USER and APTLY_PASSWORD + exit 1 +fi + +echo "Publishing version '$version' to $action for $dist...\n" + +upload() +{ + echo "\nUploading files:" + for file in $packages; do + echo " - $file" + jsonret=`curl -fsS -X POST -F "file=@$file" -u $aptly_user:$aptly_password ${aptly_api}/api/files/$folder` + done +} + +cleanup() { + echo "\nCleanup..." + jsonret=`curl -fsS -X DELETE -u $aptly_user:$aptly_password ${aptly_api}/api/files/$folder` +} +trap cleanup EXIT + +update_publish() { + _publish=$1 + _dist=$2 + jsonret=`curl -fsS -X PUT -H 'Content-Type: application/json' --data \ + '{"AcquireByHash": true, "MultiDist": true, + "Signing": {"Batch": true, "Keyring": "aptly.repo/aptly.pub", "secretKeyring": "aptly.repo/aptly.sec", "PassphraseFile": "aptly.repo/passphrase"}}' \ + -u $aptly_user:$aptly_password ${aptly_api}/api/publish/$_publish/$_dist?_async=true` + _task_id=`echo $jsonret | jq .ID` + _success=0 + for t in `seq 180` + do + jsonret=`curl -fsS -u $aptly_user:$aptly_password ${aptly_api}/api/tasks/$_task_id` + _state=`echo $jsonret | jq .State` + if [ "$_state" = "2" ]; then + _success=1 + curl -fsS -X DELETE -u $aptly_user:$aptly_password ${aptly_api}/api/tasks/$_task_id + break + fi + if [ "$_state" = "3" ]; then + echo Error: publish failed + exit 1 + fi + sleep 1 + done + if [ "$_success" -ne 1 ]; then + echo "Error: publish failed (timeout)" + exit 1 + fi +} + +if [ "$action" = "ci" ]; then + if echo "$version" | grep -vq "+"; then + # skip ci when on release tag + exit 0 + fi + + aptly_repository=aptly-ci-$dist + aptly_published=s3:repo.aptly.info:ci + +elif [ "$action" = "release" ]; then + aptly_repository=aptly-release-$dist + aptly_published=s3:repo.aptly.info:release +fi + +upload + +echo "\nAdding packages to $aptly_repository ..." +jsonret=`curl -fsS -X POST -u $aptly_user:$aptly_password ${aptly_api}/api/repos/$aptly_repository/file/$folder` + +echo "\nUpdating published repo $aptly_published ..." +update_publish $aptly_published $dist + +# if [ "$action" = "OBSOLETErelease" ]; then +# aptly_repository=aptly-release +# aptly_snapshot=aptly-$version +# aptly_published=s3:repo.aptly.info:./squeeze +# +# echo "\nAdding packages to $aptly_repository..." +# curl -fsS -X POST -u $aptly_user:$aptly_password ${aptly_api}/api/repos/$aptly_repository/file/$folder +# echo +# +# echo "\nCreating snapshot $aptly_snapshot from repo $aptly_repository..." +# curl -fsS -X POST -u $aptly_user:$aptly_password -H 'Content-Type: application/json' --data \ +# "{\"Name\":\"$aptly_snapshot\"}" ${aptly_api}/api/repos/$aptly_repository/snapshots +# echo +# +# echo "\nSwitching published repo $aptly_published to use snapshot $aptly_snapshot..." +# curl -fsS -X PUT -H 'Content-Type: application/json' --data \ +# "{\"AcquireByHash\": true, \"Snapshots\": [{\"Component\": \"main\", \"Name\": \"$aptly_snapshot\"}], +# \"Signing\": {\"Batch\": true, \"Keyring\": \"aptly.repo/aptly.pub\", +# \"secretKeyring\": \"aptly.repo/aptly.sec\", \"PassphraseFile\": \"aptly.repo/passphrase\"}}" \ +# -u $aptly_user:$aptly_password ${aptly_api}/api/publish/$aptly_published +# echo +# fi + diff --git a/.gitignore b/.gitignore index 347cbc1d..6b1b2081 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,14 @@ *.o *.a *.so +unit.out # Folders _obj _test +tmp/ + # Architecture specific extensions/prefixes *.[568vq] [568vq].out @@ -32,13 +35,36 @@ root/ man/aptly.1.html man/aptly.1.ronn -.goxc.local.json - system/env/ # created by make build for release artifacts +VERSION +aptly.test + build/ -pgp/keyrings/aptly2*.gpg -pgp/keyrings/aptly2*.gpg~ -pgp/keyrings/.#* +system/files/aptly2.gpg~ +system/files/aptly2_passphrase.gpg~ + +*.creds + +.go/ +obj-x86_64-linux-gnu/ + +# debian +debian/.debhelper/ +debian/aptly.debhelper.log +debian/aptly.postrm.debhelper +debian/aptly.substvars +debian/aptly/ +debian/debhelper-build-stamp +debian/files +debian/aptly-api/ +debian/aptly-api.debhelper.log +debian/aptly-api.postrm.debhelper +debian/aptly-api.substvars +debian/aptly-dbg.debhelper.log +debian/aptly-dbg.substvars +debian/aptly-dbg/ + +docs/ diff --git a/.golangci.yml b/.golangci.yml index 60d5a032..a8060193 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,7 +5,6 @@ run: linters: disable-all: true enable: - - deadcode - goconst - gofmt - goimports @@ -14,6 +13,4 @@ linters: - misspell - revive - staticcheck - - structcheck - - varcheck - vetshadow diff --git a/.goxc.json b/.goxc.json deleted file mode 100644 index 60f1940c..00000000 --- a/.goxc.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "AppName": "aptly", - "ArtifactsDest": "xc-out/", - "TasksExclude": [ - "rmbin", - "go-test", - "go-vet" - ], - "TasksAppend": [ - "bintray" - ], - "TaskSettings": { - "debs": { - "metadata": { - "maintainer": "Andrey Smirnov", - "maintainer-email": "me@smira.ru", - "description": "Debian repository management tool" - }, - "metadata-deb": { - "License": "MIT", - "Homepage": "https://www.aptly.info/", - "Depends": "bzip2, xz-utils, gnupg, gpgv", - "Suggests": "graphviz" - }, - "other-mapped-files": { - "/": "root/" - } - }, - "bintray": { - "repository": "aptly", - "subject": "smira", - "package": "aptly", - "downloadspage": "bintray.md" - } - }, - "ResourcesInclude": "README.rst,LICENSE,AUTHORS,man/aptly.1", - "BuildConstraints": "linux,386 linux,amd64 darwin,amd64 freebsd,386 freebsd,amd64", - "MainDirsExclude": "_man,vendor", - "BuildSettings": { - "LdFlagsXVars": { - "Version": "main.Version" - } - }, - "ConfigVersion": "0.9" -} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 574a8f4e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,106 +0,0 @@ -dist: xenial -sudo: required - -language: go - -go_import_path: github.com/aptly-dev/aptly - -addons: - apt: - packages: - - python-virtualenv - - graphviz - - gnupg2 - - gpgv2 - -env: - global: - - secure: "EcCzJsqQ3HnIkprBPS1YHErsETcb7KQFBYEzVDE7RYDApWeapLq+r/twMtWMd/fkGeLzr3kWSg7nhSadeHMLYeMl9j+U7ncC5CWG5NMBOj/jowlb9cMCCDlmzMoZLAgR6jm1cJyrWCLsWVlv+D0ZiB0fx4xaBZP/gIr9g6nEwC8=" - - secure: "OxiVNmre2JzUszwPNNilKDgIqtfX2gnRSsVz6nuySB1uO2yQsOQmKWJ9cVYgH2IB5H8eWXKOhexcSE28kz6TPLRuEcU9fnqKY3uEkdwm7rJfz9lf+7C4bJEUdA1OIzJppjnWUiXxD7CEPL1DlnMZM24eDQYqa/4WKACAgkK53gE=" - - NO_FTP_ACCESS: "yes" - - BOTO_CONFIG: /dev/null - - GO111MODULE: "on" - - GOPROXY: https://proxy.golang.org - -matrix: - allow_failures: - - go: master - env: RUN_LONG_TESTS=no - fast_finish: true - include: - - go: 1.11.x - env: RUN_LONG_TESTS=no - - go: 1.12.x - env: RUN_LONG_TESTS=no - - go: 1.13.x - env: RUN_LONG_TESTS=no - - go: 1.14.x - env: RUN_LONG_TESTS=yes - - go: 1.15.x - env: - - RUN_LONG_TESTS=yes - - DEPLOY_BINARIES=yes - - APTLY_USER=aptly - - secure: "ejVss+Ansvk9f237iXVd87KA8N/SkfJkEdr/KCw9WRkVw3M9WyYtFnqpakIUPFT8RsSc7MW+RU4OM90DsbE9dbDIL0oW+t6QH/IfGjNG2HjDiGEWN/tMLeAQTtzPaVqlItJBo0ILMF2K6NrgkYBYU+tZ8gk5w7CuARvAk82d00o=" - - go: master - env: RUN_LONG_TESTS=no - -before_install: - - virtualenv system/env - - . system/env/bin/activate - - pip install six packaging appdirs - - pip install -U pip setuptools - - pip install -r system/requirements.txt - - make version - -install: - - make prepare - -after_success: - - bash <(curl -s https://codecov.io/bash) - -notifications: - webhooks: - urls: - - "https://webhooks.gitter.im/e/c691da114a41eed6ec45" - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false - -before_deploy: - - make release - -deploy: - - provider: releases - api_key: - secure: XHxYAFBzzgOZyK6JXQpEp0kGrZPmd02esEJjwJXZpWT68kRzCCrBXg+x3vIcgRtl82oQbflv/ThNlGT80iqSmd+Itsa5lUJoJnRxbP8qSykfCXmkrgsHIxbGxWIL+JHAWmwQdkV91kDS04nmjl9MDptLId0tuleWwcMH6h1hgMg= - file_glob: true - file: build/* - skip_cleanup: true - on: - tags: true - condition: "$DEPLOY_BINARIES = yes" - - provider: s3 - access_key_id: - secure: "I2etn22HHsQjJNhr6zdM/P4VLCYwEA/6HEf2eGvwey93oLeog+KnDCUI7lwGAHYuwzyDGQbZZ6YdoNc3b0kxaRWT0W+ke78TAdJhTZ+xbqGfEWv1er0zklJLOsimYF097rDJw8g3Oh/Gjwt5TTp0GJ5l3IhJ6zepNsKCMuwQpJM=" - secret_access_key: - secure: "inRWX7FuyhkhKzGknSd2/mjZaNFZm/zHMejM99OF6PiGLNtyt/esdA0ToYL8B8Icl0/SISlLlEr/DDa4OGENKueFVeHrKH7OK0jVbWp9Yvw4hCXSlw9VmlkHDMQrC4gybS2Hf7el8N4AFVqyeUE7LqiP3WruHRdbE9XgOnTkLkg=" - bucket: aptly-nightly - skip_cleanup: true - acl: public-read - local_dir: build - on: - branch: master - condition: "$DEPLOY_BINARIES = yes" - - provider: script - script: bash upload-artifacts.sh nightly - skip_cleanup: true - on: - branch: master - condition: "$DEPLOY_BINARIES = yes" - - provider: script - script: bash upload-artifacts.sh release - skip_cleanup: true - on: - tags: true - condition: "$DEPLOY_BINARIES = yes" diff --git a/AUTHORS b/AUTHORS index 00bc4557..70a75464 100644 --- a/AUTHORS +++ b/AUTHORS @@ -49,3 +49,17 @@ List of contributors, in chronological order: * Samuel Mutel (https://github.com/smutel) * Russell Greene (https://github.com/russelltg) * Wade Simmons (https://github.com/wadey) +* Steven Stone (https://github.com/smstone) +* Josh Bayfield (https://github.com/jbayfield) +* Boxjan (https://github.com/boxjan) +* Mauro Regli (https://github.com/reglim) +* Alexander Zubarev (https://github.com/strike) +* Nicolas Dostert (https://github.com/acdn-ndostert) +* Ryan Gonzalez (https://github.com/refi64) +* Paul Cacheux (https://github.com/paulcacheux) +* Nic Waller (https://github.com/sf-nwaller) +* iofq (https://github.com/iofq) +* Noa Resare (https://github.com/nresare) +* Ramón N.Rodriguez (https://github.com/runitonmetal) +* Golf Hu (https://github.com/hudeng-go) +* Cookie Fei (https://github.com/wuhuang26) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index ab3791a8..297e9220 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [team@aptly.info](mailto:team@aptly.info). All +reported by contacting the project team on [Aptly Discussions](https://github.com/aptly-dev/aptly/discussions). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a54863d..edebdf22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: -The following is a set of guidelines for contributing to [aptly](https://github.com/smira/aplty) and related repositories, which are hosted in the [aptly-dev Organization](https://github.com/aptly-dev) on GitHub. +The following is a set of guidelines for contributing to [aptly](https://github.com/aptly-dev/aplty) and related repositories, which are hosted in the [aptly-dev Organization](https://github.com/aptly-dev) on GitHub. These are just guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. ## What should I know before I get started? @@ -11,7 +11,7 @@ These are just guidelines, not rules. Use your best judgment, and feel free to p This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. -Please report unacceptable behavior to [team@aptly.info](mailto:team@aptly.info). +Please report unacceptable behavior on [https://github.com/aptly-dev/aptly/discussions](https://github.com/aptly-dev/aptly/discussions) ### List of Repositories @@ -60,7 +60,7 @@ If you want to update website, please follow steps below: We're always looking for new contributions to [FAQ](https://www.aptly.info/doc/faq/), [tutorials](https://www.aptly.info/tutorial/), general fixes, clarifications, misspellings, grammar mistakes! -### Your First Code Contribution +### Code Contribution Please follow [next section](#development-setup) on development process. When change is ready, please submit PR following [PR template](.github/PULL_REQUEST_TEMPLATE.md). @@ -68,20 +68,6 @@ following [PR template](.github/PULL_REQUEST_TEMPLATE.md). Make sure that purpose of your change is clear, all the tests and checks pass, and all new code is covered with tests if that is possible. -## Development Setup - -This section describes local setup to start contributing to aptly source. - -### Go & Python - -You would need `Go` (latest version is recommended) and `Python` 2.7.x (3.x is not supported yet). - -If you're new to Go, follow [getting started guide](https://golang.org/doc/install) to install it and perform -initial setup. With Go 1.8+, default `$GOPATH` is `$HOME/go`, so rest of this document assumes that. - -Usually `$GOPATH/bin` is appended to your `$PATH` to make it easier to run built binaries, but you might choose -to prepend it or to skip this test if you're security conscious. - ### Forking and Cloning As aptly is using Go modules, aptly repository could be cloned to any location on the file system: @@ -98,7 +84,94 @@ to specify your remote name when pushing branches: git push -### Dependencies + +## Development Setup + +Working on aptly code can be done locally on the development machine, or for convenience by using docker. The next sections describe the setup process. + +### Docker Development Setup + +This section describes the docker setup to start contributing to aptly. + +#### Dependencies + +Install the following on your development machine: +- docker +- make +- git + + +#### Create docker container + +To build the development docker image, run: +``` +make docker-image +``` + +#### Build aptly + +To build the aptly in the development docker container, run: +``` +make docker-build +``` + +#### Running aptly commands + +To run aptly commands in the development docker container, run: +``` +make docker-aptly +``` + +Example: +``` +$ make docker-aptly +bash: cannot set terminal process group (16): Inappropriate ioctl for device +bash: no job control in this shell +aptly@b43e8473ef81:/app$ aptly version +aptly version: 1.5.0+189+g0fc90dff +``` + +#### Running unit tests + +In order to run aptly unit tests, enter the following: +``` +make docker-unit-tests +``` + +#### Running system tests + +In order to run aptly system tests, enter the following: +``` +make docker-system-tests +``` + +#### Running golangci-lint + +In order to run aptly unit tests, run: +``` +make docker-lint +``` + +#### More info + +Run `make help` for more information. + + +### Local Development Setup + +This section describes local setup to start contributing to aptly. + +#### Go & Python + +You would need `Go` (latest version is recommended) and `Python` 3.9 (or newer, the CI currently tests against 3.11). + +If you're new to Go, follow [getting started guide](https://golang.org/doc/install) to install it and perform +initial setup. With Go 1.8+, default `$GOPATH` is `$HOME/go`, so rest of this document assumes that. + +Usually `$GOPATH/bin` is appended to your `$PATH` to make it easier to run built binaries, but you might choose +to prepend it or to skip this test if you're security conscious. + +#### Dependencies You would need some additional tools and Python virtual environment to run tests and checks, install them with: @@ -110,7 +183,7 @@ Aptly is using Go modules to manage dependencies, download modules using: make modules -### Building +#### Building If you want to build aptly binary from your current source tree, run: @@ -124,7 +197,7 @@ Or, if it's not on your path: ~/go/bin/aptly -### Unit-tests +#### Unit-tests aptly has two kinds of tests: unit-tests and functional (system) tests. Functional tests are preferred way to test any feature, but some features are much easier to test with unit-tests (e.g. algorithms, failure scenarios, ...) @@ -133,7 +206,7 @@ aptly is using standard Go unit-test infrastructure plus [gocheck](http://labix. make test -### Functional Tests +#### Functional Tests Functional tests are implemented in Python, and they use custom test runner which is similar to Python unit-test runner. Most of the tests start with clean aptly state, run some aptly commands to prepare environment, and finally @@ -180,7 +253,7 @@ There are some packages available under `system/files/` directory which are used this default location. You can run aptly under different user or by using non-default config location with non-default aptly root directory. -### Style Checks +#### Style Checks Style checks could be run with: @@ -191,7 +264,7 @@ for the linter could be found in [.golangci.yml](.golangci.yml) file. Python code (system tests) are linted with [flake8 tool](https://pypi.python.org/pypi/flake8). -### Vendored Code +#### Vendored Code aptly is using Go vendoring for all the libraries aptly depends upon. `vendor/` directory is checked into the source repository to avoid any problems if source repositories go away. Go build process will automatically prefer vendored @@ -217,25 +290,3 @@ Bash and Zsh completion for aptly reside in the same repo under in [completion.d When new option or command is introduced, bash completion should be updated to reflect that change. When aptly package is being built, it automatically pulls bash completion and man page into the package. - -## Design - -This section requires future work. - -*TBD* - -### Database - -### Package Pool - -### Package - -### PackageList, PackageRefList - -### LocalRepo, RemoteRepo, Snapshot - -### PublishedRepository - -### Context - -### Collections, CollectionFactory diff --git a/Makefile b/Makefile index 1acb5035..363b2101 100644 --- a/Makefile +++ b/Makefile @@ -1,81 +1,188 @@ -GOVERSION=$(shell go version | awk '{print $$3;}') -ifdef TRAVIS_TAG - TAG=$(TRAVIS_TAG) -else - TAG="$(shell git describe --tags --always)" -endif -VERSION=$(shell echo $(TAG) | sed 's@^v@@' | sed 's@-@+@g') -PACKAGES=context database deb files gpg http query swift s3 utils +GOPATH=$(shell go env GOPATH) +VERSION=$(shell make -s version) PYTHON?=python3 -TESTS?= BINPATH?=$(GOPATH)/bin -RUN_LONG_TESTS?=yes +GOLANGCI_LINT_VERSION=v1.54.1 # version supporting go 1.19 +COVERAGE_DIR?=$(shell mktemp -d) +GOOS=$(shell go env GOHOSTOS) +GOARCH=$(shell go env GOHOSTARCH) -all: modules test bench check system-test +# Uncomment to update test outputs +# CAPTURE := "--capture" -prepare: - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.43.0 +help: ## Print this help + @grep -E '^[a-zA-Z][a-zA-Z0-9_-]*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -modules: - go mod download +prepare: ## Install go module dependencies + # Prepare go modules go mod verify go mod tidy -v + # Generate VERSION file + go generate -dev: - go get -u github.com/laher/goxc +releasetype: # Print release type: ci (on any branch/commit), release (on a tag) + @reltype=ci ; \ + gitbranch=`git rev-parse --abbrev-ref HEAD` ; \ + if [ "$$gitbranch" = "HEAD" ] && [ "$$FORCE_CI" != "true" ]; then \ + gittag=`git describe --tags --exact-match 2>/dev/null` ;\ + if echo "$$gittag" | grep -q '^v[0-9]'; then \ + reltype=release ; \ + fi ; \ + fi ; \ + echo $$reltype -check: system/env -ifeq ($(RUN_LONG_TESTS), yes) - golangci-lint run - system/env/bin/flake8 -endif +version: ## Print aptly version + @ci="" ; \ + if [ "`make -s releasetype`" = "ci" ]; then \ + ci=`TZ=UTC git show -s --format='+%cd.%h' --date=format-local:'%Y%m%d%H%M%S'`; \ + fi ; \ + if which dpkg-parsechangelog > /dev/null 2>&1; then \ + echo `dpkg-parsechangelog -S Version`$$ci; \ + else \ + echo `grep ^aptly -m1 debian/changelog | sed 's/.*(\([^)]\+\)).*/\1/'`$$ci ; \ + fi + +swagger-install: + # Install swag + @test -f $(BINPATH)/swag || GOOS=linux GOARCH=amd64 go install github.com/swaggo/swag/cmd/swag@latest + +swagger: swagger-install + # Generate swagger docs + @PATH=$(BINPATH)/:$(PATH) swag init --markdownFiles docs + +etcd-install: + # Install etcd + test -d /srv/etcd || system/t13_etcd/install-etcd.sh + +flake8: ## run flake8 on system test python files + flake8 system/ + +lint: + # Install golangci-lint + go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) + # Running lint + @PATH=$(BINPATH)/:$(PATH) golangci-lint run + + +build: prepare swagger ## Build aptly + go build -o build/aptly install: - go install -v -ldflags "-X main.Version=$(VERSION)" + @echo "\e[33m\e[1mBuilding aptly ...\e[0m" + go generate + @out=`mktemp`; if ! go install -v > $$out 2>&1; then cat $$out; rm -f $$out; echo "\nBuild failed\n"; exit 1; else rm -f $$out; fi -system/env: system/requirements.txt -ifeq ($(RUN_LONG_TESTS), yes) - rm -rf system/env - $(PYTHON) -m venv system/env - system/env/bin/pip install -r system/requirements.txt -endif +test: prepare swagger etcd-install ## Run unit tests + @echo "\e[33m\e[1mStarting etcd ...\e[0m" + @mkdir -p /tmp/etcd-data; system/t13_etcd/start-etcd.sh > /tmp/etcd-data/etcd.log 2>&1 & + @echo "\e[33m\e[1mRunning go test ...\e[0m" + go test -v ./... -gocheck.v=true -coverprofile=unit.out; echo $$? > .unit-test.ret + @echo "\e[33m\e[1mStopping etcd ...\e[0m" + @pid=`cat /tmp/etcd.pid`; kill $$pid + @rm -f /tmp/etcd-data/etcd.log + @ret=`cat .unit-test.ret`; if [ "$$ret" = "0" ]; then echo "\n\e[32m\e[1mUnit Tests SUCCESSFUL\e[0m"; else echo "\n\e[31m\e[1mUnit Tests FAILED\e[0m"; fi; rm -f .unit-test.ret; exit $$ret -system-test: install system/env -ifeq ($(RUN_LONG_TESTS), yes) +system-test: prepare swagger etcd-install ## Run system tests + # build coverage binary + go test -v -coverpkg="./..." -c -tags testruncli + # Download fixture-db, fixture-pool, etcd.db if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi - PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) -endif - -test: - go test -v ./... -gocheck.v=true -race -coverprofile=coverage.txt -covermode=atomic + test -f ~/etcd.db || (curl -o ~/etcd.db.xz http://repo.aptly.info/system-tests/etcd.db.xz && xz -d ~/etcd.db.xz) + # Run system tests + PATH=$(BINPATH)/:$(PATH) && FORCE_COLOR=1 $(PYTHON) system/run.py --long --coverage-dir $(COVERAGE_DIR) $(CAPTURE) $(TEST) bench: + @echo "\e[33m\e[1mRunning benchmark ...\e[0m" go test -v ./deb -run=nothing -bench=. -benchmem +serve: prepare swagger-install ## Run development server (auto recompiling) + test -f $(BINPATH)/air || go install github.com/air-verse/air@v1.52.3 + cp debian/aptly.conf ~/.aptly.conf + sed -i /enableSwaggerEndpoint/s/false/true/ ~/.aptly.conf + PATH=$(BINPATH):$$PATH air -build.pre_cmd 'swag init -q --markdownFiles docs' -build.exclude_dir docs,system,debian,pgp/keyrings,pgp/test-bins,completion.d,man,deb/testdata,console,_man,cmd,systemd -- api serve -listen 0.0.0.0:3142 + +dpkg: prepare swagger ## Build debian packages + @test -n "$(DEBARCH)" || (echo "please define DEBARCH"; exit 1) + # set debian version + @if [ "`make -s releasetype`" = "ci" ]; then \ + echo CI Build, setting version... ; \ + cp debian/changelog debian/changelog.dpkg-bak ; \ + DEBEMAIL="CI " dch -v `make -s version` "CI build" ; \ + fi + # Run dpkg-buildpackage + buildtype="any" ; \ + if [ "$(DEBARCH)" = "amd64" ]; then \ + buildtype="any,all" ; \ + fi ; \ + echo "\e[33m\e[1mBuilding: $$buildtype\e[0m" ; \ + dpkg-buildpackage -us -uc --build=$$buildtype -d --host-arch=$(DEBARCH) + # cleanup + @test -f debian/changelog.dpkg-bak && mv debian/changelog.dpkg-bak debian/changelog || true ; \ + mkdir -p build && mv ../*.deb build/ ; \ + cd build && ls -l *.deb + +binaries: prepare swagger ## Build binary releases (FreeBSD, MacOS, Linux tar) + # build aptly + GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o build/tmp/aptly -ldflags='-extldflags=-static' + # install + @mkdir -p build/tmp/man build/tmp/completion/bash_completion.d build/tmp/completion/zsh/vendor-completions + @cp man/aptly.1 build/tmp/man/ + @cp completion.d/aptly build/tmp/completion/bash_completion.d/ + @cp completion.d/_aptly build/tmp/completion/zsh/vendor-completions/ + @cp README.rst LICENSE AUTHORS build/tmp/ + @gzip -f build/tmp/man/aptly.1 + @path="aptly_$(VERSION)_$(GOOS)_$(GOARCH)"; \ + rm -rf "build/$$path"; \ + mv build/tmp build/"$$path"; \ + rm -rf build/tmp; \ + cd build; \ + zip -r "$$path".zip "$$path" > /dev/null \ + && echo "Built build/$${path}.zip"; \ + rm -rf "$$path" + +docker-image: ## Build aptly-dev docker image + @docker build -f system/Dockerfile . -t aptly-dev + +docker-build: ## Build aptly in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper build + +docker-shell: ## Run aptly and other commands in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper || true + +docker-deb: ## Build debian packages in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper dpkg DEBARCH=amd64 + +docker-unit-test: ## Run unit tests in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper test + +docker-system-test: ## Run system tests in docker container (add TEST=t04_mirror or TEST=UpdateMirror26Test to run only specific tests) + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper system-test TEST=$(TEST) + +docker-serve: ## Run development server (auto recompiling) on http://localhost:3142 + @docker run -it --rm -p 3142:3142 -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper serve || true + +docker-lint: ## Run golangci-lint in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper lint + +docker-binaries: ## Build binary releases (FreeBSD, MacOS, Linux tar) in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper binaries + +docker-man: ## Create man page in docker container + @docker run -it --rm -v ${PWD}:/work/src aptly-dev /work/src/system/docker-wrapper man + mem.png: mem.dat mem.gp gnuplot mem.gp open mem.png -goxc: dev - rm -rf root/ - mkdir -p root/usr/share/man/man1/ root/etc/bash_completion.d/ root/usr/share/zsh/vendor-completions/ - cp man/aptly.1 root/usr/share/man/man1 - cp completion.d/aptly root/etc/bash_completion.d/ - cp completion.d/_aptly root/usr/share/zsh/vendor-completions/ - gzip root/usr/share/man/man1/aptly.1 - goxc -pv=$(VERSION) -max-processors=2 $(GOXC_OPTS) - -release: GOXC_OPTS=-tasks-=bintray,go-vet,go-test,rmbin -release: goxc - rm -rf build/ - mkdir -p build/ - mv xc-out/$(VERSION)/aptly_$(VERSION)_* build/ - -man: +man: ## Create man pages make -C man -version: - @echo $(VERSION) +clean: ## remove local build and module cache + # Clean all generated and build files + test -d .go/ && chmod u+w -R .go/ && rm -rf .go/ || true + rm -rf build/ obj-*-linux-gnu* tmp/ + rm -f unit.out aptly.test VERSION docs/docs.go docs/swagger.json docs/swagger.yaml docs/swagger.conf + find system/ -type d -name __pycache__ -exec rm -rf {} \; 2>/dev/null || true -.PHONY: man modules version release goxc +.PHONY: help man prepare swagger version binaries docker-release docker-system-test docker-unit-test docker-lint docker-build docker-image build docker-shell clean releasetype dpkg serve docker-serve flake8 diff --git a/README.rst b/README.rst index 13e5b3f1..1b09a88e 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ aptly :target: https://codecov.io/gh/aptly-dev/aptly .. image:: https://badges.gitter.im/Join Chat.svg - :target: https://gitter.im/aptly-dev/aptly?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + :target: https://matrix.to/#/#aptly:gitter.im .. image:: https://goreportcard.com/badge/github.com/aptly-dev/aptly :target: https://goreportcard.com/report/aptly-dev/aptly diff --git a/api/api.go b/api/api.go index b8656178..a52406d8 100644 --- a/api/api.go +++ b/api/api.go @@ -3,17 +3,18 @@ package api import ( "fmt" - "log" "net/http" "sort" "strconv" "strings" + "sync/atomic" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/deb" "github.com/aptly-dev/aptly/query" "github.com/aptly-dev/aptly/task" "github.com/gin-gonic/gin" + "github.com/rs/zerolog/log" ) // Lock order acquisition (canonical): @@ -27,6 +28,23 @@ func apiVersion(c *gin.Context) { c.JSON(200, gin.H{"Version": aptly.Version}) } +// GET /api/ready +func apiReady(isReady *atomic.Value) func(*gin.Context) { + return func(c *gin.Context) { + if isReady == nil || !isReady.Load().(bool) { + c.JSON(503, gin.H{"Status": "Aptly is unavailable"}) + return + } + + c.JSON(200, gin.H{"Status": "Aptly is ready"}) + } +} + +// GET /api/healthy +func apiHealthy(c *gin.Context) { + c.JSON(200, gin.H{"Status": "Aptly is healthy"}) +} + type dbRequestKind int const ( @@ -137,20 +155,29 @@ func maybeRunTaskInBackground(c *gin.Context, name string, resources []string, p // Run this task in background if configured globally or per-request background := truthy(c.DefaultQuery("_async", strconv.FormatBool(context.Config().AsyncAPI))) if background { - log.Println("Executing task asynchronously") + log.Debug().Msg("Executing task asynchronously") task, conflictErr := runTaskInBackground(name, resources, proc) if conflictErr != nil { - c.AbortWithError(409, conflictErr) + AbortWithJSONError(c, 409, conflictErr) return } c.JSON(202, task) } else { - log.Println("Executing task synchronously") - out := context.Progress() - detail := task.Detail{} - retValue, err := proc(out, &detail) + log.Debug().Msg("Executing task synchronously") + task, conflictErr := runTaskInBackground(name, resources, proc) + if conflictErr != nil { + AbortWithJSONError(c, 409, conflictErr) + return + } + + // wait for task to finish + context.TaskList().WaitForTaskByID(task.ID) + + retValue, _ := context.TaskList().GetTaskReturnValueByID(task.ID) + err, _ := context.TaskList().GetTaskErrorByID(task.ID) + context.TaskList().DeleteTaskByID(task.ID) if err != nil { - c.AbortWithError(retValue.Code, err) + AbortWithJSONError(c, retValue.Code, err) return } if retValue != nil { @@ -168,7 +195,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory list, err := deb.NewPackageListFromRefList(reflist, collectionFactory.PackageCollection(), nil) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -176,7 +203,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory if queryS != "" { q, err := query.Parse(c.Request.URL.Query().Get("q")) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -193,7 +220,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory sort.Strings(architecturesList) if len(architecturesList) == 0 { - c.AbortWithError(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly")) + AbortWithJSONError(c, 400, fmt.Errorf("unable to determine list of architectures, please specify explicitly")) return } } @@ -203,11 +230,41 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory list, err = list.Filter([]deb.PackageQuery{q}, withDeps, nil, context.DependencyOptions(), architecturesList) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to search: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to search: %s", err)) return } } + // filter packages by version + if c.Request.URL.Query().Get("maximumVersion") == "1" { + list.PrepareIndex() + list.ForEach(func(p *deb.Package) error { + versionQ, err := query.Parse(fmt.Sprintf("Name (%s), $Version (<= %s)", p.Name, p.Version)) + if err != nil { + fmt.Println("filter packages by version, query string parse err: ", err) + c.AbortWithError(500, fmt.Errorf("unable to parse %s maximum version query string: %s", p.Name, err)) + } else { + tmpList, err := list.Filter([]deb.PackageQuery{versionQ}, false, + nil, 0, []string{}) + + if err == nil { + if tmpList.Len() > 0 { + tmpList.ForEach(func(tp *deb.Package) error { + list.Remove(tp) + return nil + }) + list.Add(p) + } + } else { + fmt.Println("filter packages by version, filter err: ", err) + c.AbortWithError(500, fmt.Errorf("unable to get %s maximum version: %s", p.Name, err)) + } + } + + return nil + }) + } + if c.Request.URL.Query().Get("format") == "details" { list.ForEach(func(p *deb.Package) error { result = append(result, p) @@ -219,3 +276,8 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory c.JSON(200, list.Strings()) } } + +func AbortWithJSONError(c *gin.Context, code int, err error) *gin.Error { + c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8") + return c.AbortWithError(code, err) +} diff --git a/api/api_test.go b/api/api_test.go index 2e55638e..8c62b31d 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -1,16 +1,20 @@ package api import ( + "bytes" "encoding/json" - ctx "github.com/aptly-dev/aptly/context" - "github.com/gin-gonic/gin" + "fmt" "io" - "io/ioutil" "net/http" "net/http/httptest" "os" + "strings" "testing" + "github.com/aptly-dev/aptly/aptly" + ctx "github.com/aptly-dev/aptly/context" + "github.com/gin-gonic/gin" + "github.com/smira/flag" . "gopkg.in/check.v1" @@ -30,12 +34,13 @@ type ApiSuite struct { var _ = Suite(&ApiSuite{}) func createTestConfig() *os.File { - file, err := ioutil.TempFile("", "aptly") + file, err := os.CreateTemp("", "aptly") if err != nil { return nil } jsonString, err := json.Marshal(gin.H{ - "architectures": []string{}, + "architectures": []string{}, + "enableMetricsEndpoint": true, }) if err != nil { return nil @@ -44,9 +49,12 @@ func createTestConfig() *os.File { return file } -func (s *ApiSuite) SetUpSuite(c *C) { +func (s *ApiSuite) setupContext() error { + aptly.Version = "testVersion" file := createTestConfig() - c.Assert(file, NotNil) + if nil == file { + return fmt.Errorf("unable to create the test configuration file") + } s.configFile = file flags := flag.NewFlagSet("fakeFlags", flag.ContinueOnError) @@ -57,10 +65,19 @@ func (s *ApiSuite) SetUpSuite(c *C) { s.flags = flags context, err := ctx.NewContext(s.flags) - c.Assert(err, IsNil) + if nil != err { + return err + } s.context = context s.router = Router(context) + + return nil +} + +func (s *ApiSuite) SetUpSuite(c *C) { + err := s.setupContext() + c.Assert(err, IsNil) } func (s *ApiSuite) TearDownSuite(c *C) { @@ -85,11 +102,52 @@ func (s *ApiSuite) HTTPRequest(method string, url string, body io.Reader) (*http return w, nil } +func (s *ApiSuite) TestGinRunsInReleaseMode(c *C) { + c.Check(gin.Mode(), Equals, gin.ReleaseMode) +} + func (s *ApiSuite) TestGetVersion(c *C) { response, err := s.HTTPRequest("GET", "/api/version", nil) c.Assert(err, IsNil) c.Check(response.Code, Equals, 200) - c.Check(response.Body.String(), Matches, ".*Version.*") + c.Check(response.Body.String(), Matches, "{\"Version\":\""+aptly.Version+"\"}") +} + +func (s *ApiSuite) TestGetReadiness(c *C) { + response, err := s.HTTPRequest("GET", "/api/ready", nil) + c.Assert(err, IsNil) + c.Check(response.Code, Equals, 200) + c.Check(response.Body.String(), Matches, "{\"Status\":\"Aptly is ready\"}") +} + +func (s *ApiSuite) TestGetHealthiness(c *C) { + response, err := s.HTTPRequest("GET", "/api/healthy", nil) + c.Assert(err, IsNil) + c.Check(response.Code, Equals, 200) + c.Check(response.Body.String(), Matches, "{\"Status\":\"Aptly is healthy\"}") +} + +func (s *ApiSuite) TestGetMetrics(c *C) { + response, err := s.HTTPRequest("GET", "/api/metrics", nil) + c.Assert(err, IsNil) + c.Check(response.Code, Equals, 200) + b := strings.Replace(response.Body.String(), "\n", "", -1) + c.Check(b, Matches, ".*# TYPE aptly_api_http_requests_in_flight gauge.*") + c.Check(b, Matches, ".*# TYPE aptly_api_http_requests_total counter.*") + c.Check(b, Matches, ".*# TYPE aptly_api_http_request_size_bytes summary.*") + c.Check(b, Matches, ".*# TYPE aptly_api_http_response_size_bytes summary.*") + c.Check(b, Matches, ".*# TYPE aptly_api_http_request_duration_seconds summary.*") + c.Check(b, Matches, ".*# TYPE aptly_build_info gauge.*") + c.Check(b, Matches, ".*aptly_build_info.*version=\"testVersion\".*") +} + +func (s *ApiSuite) TestRepoCreate(c *C) { + body, err := json.Marshal(gin.H{ + "Name": "dummy", + }) + c.Assert(err, IsNil) + _, err = s.HTTPRequest("POST", "/api/repos", bytes.NewReader(body)) + c.Assert(err, IsNil) } func (s *ApiSuite) TestTruthy(c *C) { diff --git a/api/error.go b/api/error.go new file mode 100644 index 00000000..d966880d --- /dev/null +++ b/api/error.go @@ -0,0 +1,5 @@ +package api + +type Error struct { + Error string `json:"error"` +} diff --git a/api/files.go b/api/files.go index 41b59b2d..7ae682f8 100644 --- a/api/files.go +++ b/api/files.go @@ -6,8 +6,11 @@ import ( "os" "path/filepath" "strings" + "sync" + "github.com/aptly-dev/aptly/utils" "github.com/gin-gonic/gin" + "github.com/saracen/walker" ) func verifyPath(path string) bool { @@ -24,27 +27,31 @@ func verifyPath(path string) bool { func verifyDir(c *gin.Context) bool { if !verifyPath(c.Params.ByName("dir")) { - c.AbortWithError(400, fmt.Errorf("wrong dir")) + AbortWithJSONError(c, 400, fmt.Errorf("wrong dir")) return false } return true } -// GET /files +// @Summary Get files +// @Description Get list of uploaded files. +// @Tags Files +// @Produce json +// @Success 200 {array} string "List of files" +// @Router /api/files [get] func apiFilesListDirs(c *gin.Context) { list := []string{} + listLock := &sync.Mutex{} - err := filepath.Walk(context.UploadPath(), func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - + err := walker.Walk(context.UploadPath(), func(path string, info os.FileInfo) error { if path == context.UploadPath() { return nil } if info.IsDir() { + listLock.Lock() + defer listLock.Unlock() list = append(list, filepath.Base(path)) return filepath.SkipDir } @@ -53,7 +60,7 @@ func apiFilesListDirs(c *gin.Context) { }) if err != nil && !os.IsNotExist(err) { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -66,17 +73,17 @@ func apiFilesUpload(c *gin.Context) { return } - path := filepath.Join(context.UploadPath(), c.Params.ByName("dir")) + path := filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir"))) err := os.MkdirAll(path, 0777) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } err = c.Request.ParseMultipartForm(10 * 1024 * 1024) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -86,7 +93,7 @@ func apiFilesUpload(c *gin.Context) { for _, file := range files { src, err := file.Open() if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } defer src.Close() @@ -94,14 +101,14 @@ func apiFilesUpload(c *gin.Context) { destPath := filepath.Join(path, filepath.Base(file.Filename)) dst, err := os.Create(destPath) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } defer dst.Close() _, err = io.Copy(dst, src) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -109,6 +116,7 @@ func apiFilesUpload(c *gin.Context) { } } + apiFilesUploadedCounter.WithLabelValues(c.Params.ByName("dir")).Inc() c.JSON(200, stored) } @@ -120,9 +128,10 @@ func apiFilesListFiles(c *gin.Context) { } list := []string{} - root := filepath.Join(context.UploadPath(), c.Params.ByName("dir")) + listLock := &sync.Mutex{} + root := filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir"))) - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + err := filepath.Walk(root, func(path string, _ os.FileInfo, err error) error { if err != nil { return err } @@ -131,6 +140,8 @@ func apiFilesListFiles(c *gin.Context) { return nil } + listLock.Lock() + defer listLock.Unlock() list = append(list, filepath.Base(path)) return nil @@ -138,9 +149,9 @@ func apiFilesListFiles(c *gin.Context) { if err != nil { if os.IsNotExist(err) { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) } else { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) } return } @@ -154,9 +165,9 @@ func apiFilesDeleteDir(c *gin.Context) { return } - err := os.RemoveAll(filepath.Join(context.UploadPath(), c.Params.ByName("dir"))) + err := os.RemoveAll(filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir")))) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -169,15 +180,17 @@ func apiFilesDeleteFile(c *gin.Context) { return } - if !verifyPath(c.Params.ByName("name")) { - c.AbortWithError(400, fmt.Errorf("wrong file")) + dir := utils.SanitizePath(c.Params.ByName("dir")) + name := utils.SanitizePath(c.Params.ByName("name")) + if !verifyPath(name) { + AbortWithJSONError(c, 400, fmt.Errorf("wrong file")) return } - err := os.Remove(filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("name"))) + err := os.Remove(filepath.Join(context.UploadPath(), dir, name)) if err != nil { if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } } diff --git a/api/gpg.go b/api/gpg.go index 640e45c7..72e938d2 100644 --- a/api/gpg.go +++ b/api/gpg.go @@ -2,13 +2,13 @@ package api import ( "fmt" - "io/ioutil" "os" "os/exec" "path/filepath" "strings" "github.com/aptly-dev/aptly/pgp" + "github.com/aptly-dev/aptly/utils" "github.com/gin-gonic/gin" ) @@ -24,9 +24,13 @@ func apiGPGAddKey(c *gin.Context) { if c.Bind(&b) != nil { return } + b.Keyserver = utils.SanitizePath(b.Keyserver) + b.GpgKeyID = utils.SanitizePath(b.GpgKeyID) + b.GpgKeyArmor = utils.SanitizePath(b.GpgKeyArmor) + // b.Keyring can be an absolute path var err error - args := []string{"--no-default-keyring"} + args := []string{"--no-default-keyring", "--allow-non-selfsigned-uid"} keyring := "trustedkeys.gpg" if len(b.Keyring) > 0 { keyring = b.Keyring @@ -37,9 +41,9 @@ func apiGPGAddKey(c *gin.Context) { } if len(b.GpgKeyArmor) > 0 { var tempdir string - tempdir, err = ioutil.TempDir(os.TempDir(), "aptly") + tempdir, err = os.MkdirTemp(os.TempDir(), "aptly") if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } defer os.RemoveAll(tempdir) @@ -47,11 +51,11 @@ func apiGPGAddKey(c *gin.Context) { keypath := filepath.Join(tempdir, "key") keyfile, e := os.Create(keypath) if e != nil { - c.AbortWithError(400, e) + AbortWithJSONError(c, 400, e) return } if _, e = keyfile.WriteString(b.GpgKeyArmor); e != nil { - c.AbortWithError(400, e) + AbortWithJSONError(c, 400, e) } args = append(args, "--import", keypath) @@ -62,10 +66,10 @@ func apiGPGAddKey(c *gin.Context) { args = append(args, keys...) } - finder := pgp.GPG1Finder() + finder := pgp.GPGDefaultFinder() gpg, _, err := finder.FindGPG() if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -74,11 +78,11 @@ func apiGPGAddKey(c *gin.Context) { // there is no error handling for such as gpg will do this for us cmd := exec.Command(gpg, args...) fmt.Printf("running %s %s\n", gpg, strings.Join(args, " ")) - cmd.Stdout = os.Stdout - if err = cmd.Run(); err != nil { - c.AbortWithError(400, err) + out, err := cmd.CombinedOutput() + if err != nil { + c.JSON(400, string(out)) return } - c.JSON(200, gin.H{}) + c.JSON(200, string(out)) } diff --git a/api/graph.go b/api/graph.go index c79b861e..d04e687f 100644 --- a/api/graph.go +++ b/api/graph.go @@ -43,25 +43,25 @@ func apiGraph(c *gin.Context) { stdin, err := command.StdinPipe() if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } _, err = io.Copy(stdin, buf) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } err = stdin.Close() if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } output, err = command.Output() if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err)) return } diff --git a/api/metrics.go b/api/metrics.go new file mode 100644 index 00000000..94a9dc25 --- /dev/null +++ b/api/metrics.go @@ -0,0 +1,116 @@ +package api + +import ( + "fmt" + "runtime" + + "github.com/aptly-dev/aptly/aptly" + "github.com/aptly-dev/aptly/deb" + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/rs/zerolog/log" +) + +var ( + apiRequestsInFlightGauge = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "aptly_api_http_requests_in_flight", + Help: "Number of concurrent HTTP api requests currently handled.", + }, + []string{"method", "path"}, + ) + apiRequestsTotalCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "aptly_api_http_requests_total", + Help: "Total number of api requests.", + }, + []string{"code", "method", "path"}, + ) + apiRequestSizeSummary = promauto.NewSummaryVec( + prometheus.SummaryOpts{ + Name: "aptly_api_http_request_size_bytes", + Help: "Api HTTP request size in bytes.", + }, + []string{"code", "method", "path"}, + ) + apiResponseSizeSummary = promauto.NewSummaryVec( + prometheus.SummaryOpts{ + Name: "aptly_api_http_response_size_bytes", + Help: "Api HTTP response size in bytes.", + }, + []string{"code", "method", "path"}, + ) + apiRequestsDurationSummary = promauto.NewSummaryVec( + prometheus.SummaryOpts{ + Name: "aptly_api_http_request_duration_seconds", + Help: "Duration of api requests in seconds.", + }, + []string{"code", "method", "path"}, + ) + apiVersionGauge = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "aptly_build_info", + Help: "Metric with a constant '1' value labeled by version and goversion from which aptly was built.", + }, + []string{"version", "goversion"}, + ) + apiFilesUploadedCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "aptly_api_files_uploaded_total", + Help: "Total number of uploaded files labeled by upload directory.", + }, + []string{"directory"}, + ) + apiReposPackageCountGauge = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "aptly_repos_package_count", + Help: "Current number of published packages labeled by source, distribution and component.", + }, + []string{"source", "distribution", "component"}, + ) +) + +type metricsCollectorRegistrar struct { + hasRegistered bool +} + +func (r *metricsCollectorRegistrar) Register(router *gin.Engine) { + if !r.hasRegistered { + apiVersionGauge.WithLabelValues(aptly.Version, runtime.Version()).Set(1) + router.Use(instrumentHandlerInFlight(apiRequestsInFlightGauge, getBasePath)) + router.Use(instrumentHandlerCounter(apiRequestsTotalCounter, getBasePath)) + router.Use(instrumentHandlerRequestSize(apiRequestSizeSummary, getBasePath)) + router.Use(instrumentHandlerResponseSize(apiResponseSizeSummary, getBasePath)) + router.Use(instrumentHandlerDuration(apiRequestsDurationSummary, getBasePath)) + r.hasRegistered = true + } +} + +var MetricsCollectorRegistrar = metricsCollectorRegistrar{hasRegistered: false} + +func countPackagesByRepos() { + err := context.NewCollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error { + err := context.NewCollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.NewCollectionFactory()) + if err != nil { + msg := fmt.Sprintf( + "Error %s found while determining package count for metrics endpoint (prefix:%s / distribution:%s / component:%s\n).", + err, repo.StoragePrefix(), repo.Distribution, repo.Components()) + log.Warn().Msg(msg) + return err + } + + components := repo.Components() + for _, c := range components { + count := float64(len(repo.RefList(c).Refs)) + apiReposPackageCountGauge.WithLabelValues(fmt.Sprintf("%s", (repo.SourceNames())), repo.Distribution, c).Set(count) + } + + return nil + }) + + if err != nil { + msg := fmt.Sprintf("Error %s found while listing published repos for metrics endpoint", err) + log.Warn().Msg(msg) + } +} diff --git a/api/middleware.go b/api/middleware.go index 10294251..8d18eedb 100644 --- a/api/middleware.go +++ b/api/middleware.go @@ -9,59 +9,36 @@ import ( "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" -) - -var ( - apiRequestsInFlightGauge = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "aptly_api_http_requests_in_flight", - Help: "Number of concurrent HTTP api requests currently handled.", - }, - []string{"method", "path"}, - ) - apiRequestsTotalCounter = promauto.NewCounterVec( - prometheus.CounterOpts{ - Name: "aptly_api_http_requests_total", - Help: "Total number of api requests.", - }, - []string{"code", "method", "path"}, - ) - apiRequestSizeSummary = promauto.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "aptly_api_http_request_size_bytes", - Help: "Api HTTP request size in bytes.", - }, - []string{"code", "method", "path"}, - ) - apiResponseSizeSummary = promauto.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "aptly_api_http_response_size_bytes", - Help: "Api HTTP response size in bytes.", - }, - []string{"code", "method", "path"}, - ) - apiRequestsDurationSummary = promauto.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "aptly_api_http_request_duration_seconds", - Help: "Duration of api requests in seconds.", - }, - []string{"code", "method", "path"}, - ) + "github.com/rs/zerolog/log" ) // Only use base path as label value (e.g.: /api/repos) because of time series cardinality // See https://prometheus.io/docs/practices/naming/#labels func getBasePath(c *gin.Context) string { - return fmt.Sprintf("%s%s", getURLSegment(c.Request.URL.Path, 0), getURLSegment(c.Request.URL.Path, 1)) + segment0, err := getURLSegment(c.Request.URL.Path, 0) + if err != nil { + return "/" + } + segment1, err := getURLSegment(c.Request.URL.Path, 1) + if err != nil { + return *segment0 + } + + return *segment0 + *segment1 } -func getURLSegment(url string, idx int) string { - var urlSegments = strings.Split(url, "/") - +func getURLSegment(url string, idx int) (*string, error) { + urlSegments := strings.Split(url, "/") // Remove segment at index 0 because it's an empty string - var segmentAtIndex = urlSegments[1:cap(urlSegments)][idx] - return fmt.Sprintf("/%s", segmentAtIndex) + urlSegments = urlSegments[1:cap(urlSegments)] + + if len(urlSegments) <= idx { + return nil, fmt.Errorf("index %d out of range, only has %d url segments", idx, len(urlSegments)) + } + + segmentAtIndex := urlSegments[idx] + s := fmt.Sprintf("/%s", segmentAtIndex) + return &s, nil } func instrumentHandlerInFlight(g *prometheus.GaugeVec, pathFunc func(*gin.Context) string) func(*gin.Context) { @@ -101,3 +78,39 @@ func instrumentHandlerDuration(obs prometheus.ObserverVec, pathFunc func(*gin.Co obs.WithLabelValues(strconv.Itoa(c.Writer.Status()), c.Request.Method, pathFunc(c)).Observe(time.Since(now).Seconds()) } } + +// JSONLogger is a gin middleware that takes an instance of Logger and uses it for writing access +// logs that include error messages if there are any. +func JSONLogger() gin.HandlerFunc { + return func(c *gin.Context) { + // Start timer + start := time.Now() + path := c.Request.URL.Path + raw := c.Request.URL.RawQuery + + // Process request + c.Next() + + ts := time.Now() + if raw != "" { + path = path + "?" + raw + } + + errorMessage := strings.TrimSuffix(c.Errors.ByType(gin.ErrorTypePrivate).String(), "\n") + l := log.With().Str("remote", c.ClientIP()).Logger(). + With().Str("method", c.Request.Method).Logger(). + With().Str("path", path).Logger(). + With().Str("protocol", c.Request.Proto).Logger(). + With().Str("code", fmt.Sprint(c.Writer.Status())).Logger(). + With().Str("latency", ts.Sub(start).String()).Logger(). + With().Str("agent", c.Request.UserAgent()).Logger() + + if c.Writer.Status() >= 400 && c.Writer.Status() < 500 { + l.Warn().Msg(errorMessage) + } else if c.Writer.Status() >= 500 { + l.Error().Msg(errorMessage) + } else { + l.Info().Msg(errorMessage) + } + } +} diff --git a/api/middleware_test.go b/api/middleware_test.go new file mode 100644 index 00000000..0681785c --- /dev/null +++ b/api/middleware_test.go @@ -0,0 +1,255 @@ +package api + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "sync/atomic" + + "github.com/aptly-dev/aptly/utils" + "github.com/gin-gonic/gin" + . "gopkg.in/check.v1" +) + +type MiddlewareSuite struct { + router http.Handler + context *gin.Context + logReader *os.File + logWriter *os.File +} + +var _ = Suite(&MiddlewareSuite{}) + +func (s *MiddlewareSuite) SetUpTest(c *C) { + r, w, err := os.Pipe() + c.Assert(err, IsNil) + + utils.SetupJSONLogger("debug", w) + mw := JSONLogger() + + router := gin.New() + router.UseRawPath = true + router.Use(mw) + router.Use(gin.Recovery(), gin.ErrorLogger()) + + root := router.Group("/api") + isReady := &atomic.Value{} + isReady.Store(false) + root.GET("/ready", apiReady(isReady)) + root.GET("/healthy", apiHealthy) + + s.router = router + s.logReader = r + s.logWriter = w +} + +func (s *MiddlewareSuite) TearDownTest(c *C) { + s.router = nil + s.context = nil + s.logReader = nil + s.logWriter = nil +} + +func (s *MiddlewareSuite) HTTPRequest(method string, url string, body io.Reader) { + recorder := httptest.NewRecorder() + s.context, _ = gin.CreateTestContext(recorder) + req, _ := http.NewRequestWithContext(s.context, method, url, body) + s.context.Request = req + req.Header.Add("Content-Type", "application/json") + s.router.ServeHTTP(httptest.NewRecorder(), req) +} + +func (s *MiddlewareSuite) TestJSONMiddleware4xx(c *C) { + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, s.logReader) + fmt.Println(buf.String()) + outC <- buf.String() + }() + + s.HTTPRequest(http.MethodGet, "/", nil) + s.logWriter.Close() + capturedOutput := <-outC + + var jsonMap map[string]interface{} + json.Unmarshal([]byte(capturedOutput), &jsonMap) + + if val, ok := jsonMap["level"]; ok { + c.Check(val, Equals, "warn") + } else { + c.Errorf("Log message didn't have a 'level' key, obtained %s", capturedOutput) + } + + if val, ok := jsonMap["method"]; ok { + c.Check(val, Equals, "GET") + } else { + c.Errorf("Log message didn't have a 'method' key, obtained %s", capturedOutput) + } + + if val, ok := jsonMap["path"]; ok { + c.Check(val, Equals, "/") + } else { + c.Errorf("Log message didn't have a 'path' key, obtained %s", capturedOutput) + } + + if val, ok := jsonMap["protocol"]; ok { + c.Check(val, Equals, "HTTP/1.1") + } else { + c.Errorf("Log message didn't have a 'protocol' key, obtained %s", capturedOutput) + } + + if val, ok := jsonMap["code"]; ok { + c.Check(val, Equals, "404") + } else { + c.Errorf("Log message didn't have a 'code' key, obtained %s", capturedOutput) + } + + if _, ok := jsonMap["remote"]; !ok { + c.Errorf("Log message didn't have a 'remote' key, obtained %s", capturedOutput) + } + + if _, ok := jsonMap["latency"]; !ok { + c.Errorf("Log message didn't have a 'latency' key, obtained %s", capturedOutput) + } + + if _, ok := jsonMap["agent"]; !ok { + c.Errorf("Log message didn't have a 'agent' key, obtained %s", capturedOutput) + } + + if _, ok := jsonMap["time"]; !ok { + c.Errorf("Log message didn't have a 'time' key, obtained %s", capturedOutput) + } +} + +func (s *MiddlewareSuite) TestJSONMiddleware2xx(c *C) { + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, s.logReader) + fmt.Println(buf.String()) + outC <- buf.String() + }() + + s.HTTPRequest(http.MethodGet, "/api/healthy", nil) + s.logWriter.Close() + capturedOutput := <-outC + + var jsonMap map[string]interface{} + json.Unmarshal([]byte(capturedOutput), &jsonMap) + + if val, ok := jsonMap["level"]; ok { + c.Check(val, Equals, "info") + } else { + c.Errorf("Log message didn't have a 'level' key, obtained %s", capturedOutput) + } +} + +func (s *MiddlewareSuite) TestJSONMiddleware5xx(c *C) { + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, s.logReader) + fmt.Println(buf.String()) + outC <- buf.String() + }() + + s.HTTPRequest(http.MethodGet, "/api/ready", nil) + s.logWriter.Close() + capturedOutput := <-outC + + var jsonMap map[string]interface{} + json.Unmarshal([]byte(capturedOutput), &jsonMap) + + if val, ok := jsonMap["level"]; ok { + c.Check(val, Equals, "error") + } else { + c.Errorf("Log message didn't have a 'level' key, obtained %s", capturedOutput) + } +} + +func (s *MiddlewareSuite) TestJSONMiddlewareRaw(c *C) { + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, s.logReader) + fmt.Println(buf.String()) + outC <- buf.String() + }() + + s.HTTPRequest(http.MethodGet, "/api/healthy?test=raw", nil) + s.logWriter.Close() + capturedOutput := <-outC + + var jsonMap map[string]interface{} + json.Unmarshal([]byte(capturedOutput), &jsonMap) + + fmt.Println(capturedOutput) + + if val, ok := jsonMap["level"]; ok { + c.Check(val, Equals, "info") + } else { + c.Errorf("Log message didn't have a 'level' key, obtained %s", capturedOutput) + } +} + +func (s *MiddlewareSuite) TestGetBasePath(c *C) { + s.HTTPRequest(http.MethodGet, "", nil) + path := getBasePath(s.context) + c.Check(path, Equals, "/") + + s.HTTPRequest(http.MethodGet, "/", nil) + path = getBasePath(s.context) + c.Check(path, Equals, "/") + + s.HTTPRequest(http.MethodGet, "/api", nil) + path = getBasePath(s.context) + c.Check(path, Equals, "/api") + + s.HTTPRequest(http.MethodGet, "/api/repos/testRepo", nil) + path = getBasePath(s.context) + c.Check(path, Equals, "/api/repos") +} + +func (s *MiddlewareSuite) TestGetURLSegment(c *C) { + url := "/" + segment, err := getURLSegment(url, 0) + if err != nil { + c.Error(err) + } + c.Check(*segment, Equals, "/") + + _, err = getURLSegment(url, 1) + if err == nil { + c.Error("Invalid return value") + } + + url = "/api" + segment, err = getURLSegment(url, 0) + if err != nil { + c.Error(err) + } + c.Check(*segment, Equals, "/api") + + _, err = getURLSegment(url, 1) + if err == nil { + c.Error("Invalid return value") + } + + url = "/api/repos/testRepo" + segment, err = getURLSegment(url, 0) + if err != nil { + c.Error(err) + } + c.Check(*segment, Equals, "/api") + + segment, err = getURLSegment(url, 1) + if err != nil { + c.Error(err) + } + c.Check(*segment, Equals, "/repos") +} diff --git a/api/mirror.go b/api/mirror.go index 7775f871..0052f2a5 100644 --- a/api/mirror.go +++ b/api/mirror.go @@ -2,8 +2,8 @@ package api import ( "fmt" - "log" "net/http" + "os" "sort" "strings" "sync" @@ -14,19 +14,16 @@ import ( "github.com/aptly-dev/aptly/query" "github.com/aptly-dev/aptly/task" "github.com/gin-gonic/gin" + "github.com/rs/zerolog/log" ) -func getVerifier(ignoreSignatures bool, keyRings []string) (pgp.Verifier, error) { - if ignoreSignatures { - return nil, nil - } - +func getVerifier(keyRings []string) (pgp.Verifier, error) { verifier := context.GetVerifier() for _, keyRing := range keyRings { verifier.AddKeyring(keyRing) } - err := verifier.InitKeyring() + err := verifier.InitKeyring(false) if err != nil { return nil, err } @@ -34,7 +31,13 @@ func getVerifier(ignoreSignatures bool, keyRings []string) (pgp.Verifier, error) return verifier, nil } -// GET /api/mirrors +// @Summary Get mirrors +// @Description **Show list of currently available mirrors** +// @Description Each mirror is returned as in “show” API. +// @Tags Mirrors +// @Produce json +// @Success 200 {array} deb.RemoteRepo +// @Router /api/mirrors [get] func apiMirrorsList(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.RemoteRepoCollection() @@ -48,24 +51,49 @@ func apiMirrorsList(c *gin.Context) { c.JSON(200, result) } -// POST /api/mirrors +type mirrorCreateParams struct { + // Name of mirror to be created + Name string `binding:"required" json:"Name" example:"mirror2"` + // Url of the archive to mirror + ArchiveURL string `binding:"required" json:"ArchiveURL" example:"http://deb.debian.org/debian"` + // Distribution name to mirror + Distribution string ` json:"Distribution" example:"'buster', for flat repositories use './'"` + // Package query that is applied to mirror packages + Filter string ` json:"Filter" example:"xserver-xorg"` + // Components to mirror, if not specified aptly would fetch all components + Components []string ` json:"Components" example:"main"` + // Limit mirror to those architectures, if not specified aptly would fetch all architectures + Architectures []string ` json:"Architectures" example:"amd64"` + // Gpg keyring(s) for verifying Release file + Keyrings []string ` json:"Keyrings" example:"trustedkeys.gpg"` + // Set "true" to mirror source packages + DownloadSources bool ` json:"DownloadSources"` + // Set "true" to mirror udeb files + DownloadUdebs bool ` json:"DownloadUdebs"` + // Set "true" to mirror installer files + DownloadInstaller bool ` json:"DownloadInstaller"` + // Set "true" to include dependencies of matching packages when filtering + FilterWithDeps bool ` json:"FilterWithDeps"` + // Set "true" to skip if the given components are in the Release file + SkipComponentCheck bool ` json:"SkipComponentCheck"` + // Set "true" to skip the verification of architectures + SkipArchitectureCheck bool ` json:"SkipArchitectureCheck"` + // Set "true" to skip the verification of Release file signatures + IgnoreSignatures bool ` json:"IgnoreSignatures"` +} + +// @Summary Create mirror +// @Description **Create a mirror** +// @Tags Mirrors +// @Consume json +// @Param request body mirrorCreateParams true "Parameters" +// @Produce json +// @Success 200 {object} deb.RemoteRepo +// @Failure 400 {object} Error "Bad Request" +// @Router /api/mirrors [post] func apiMirrorsCreate(c *gin.Context) { var err error - var b struct { - Name string `binding:"required"` - ArchiveURL string `binding:"required"` - Distribution string - Filter string - Components []string - Architectures []string - Keyrings []string - DownloadSources bool - DownloadUdebs bool - DownloadInstaller bool - FilterWithDeps bool - SkipComponentCheck bool - IgnoreSignatures bool - } + var b mirrorCreateParams b.DownloadSources = context.Config().DownloadSourcePackages b.IgnoreSignatures = context.Config().GpgDisableVerify @@ -81,7 +109,7 @@ func apiMirrorsCreate(c *gin.Context) { if strings.HasPrefix(b.ArchiveURL, "ppa:") { b.ArchiveURL, b.Distribution, b.Components, err = deb.ParsePPA(b.ArchiveURL, context.Config()) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } } @@ -89,7 +117,7 @@ func apiMirrorsCreate(c *gin.Context) { if b.Filter != "" { _, err = query.Parse(b.Filter) if err != nil { - c.AbortWithError(400, fmt.Errorf("unable to create mirror: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("unable to create mirror: %s", err)) return } } @@ -98,39 +126,50 @@ func apiMirrorsCreate(c *gin.Context) { b.DownloadSources, b.DownloadUdebs, b.DownloadInstaller) if err != nil { - c.AbortWithError(400, fmt.Errorf("unable to create mirror: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("unable to create mirror: %s", err)) return } repo.Filter = b.Filter repo.FilterWithDeps = b.FilterWithDeps repo.SkipComponentCheck = b.SkipComponentCheck + repo.SkipArchitectureCheck = b.SkipArchitectureCheck repo.DownloadSources = b.DownloadSources repo.DownloadUdebs = b.DownloadUdebs - verifier, err := getVerifier(b.IgnoreSignatures, b.Keyrings) + verifier, err := getVerifier(b.Keyrings) if err != nil { - c.AbortWithError(400, fmt.Errorf("unable to initialize GPG verifier: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("unable to initialize GPG verifier: %s", err)) return } downloader := context.NewDownloader(nil) - err = repo.Fetch(downloader, verifier) + err = repo.Fetch(downloader, verifier, b.IgnoreSignatures) if err != nil { - c.AbortWithError(400, fmt.Errorf("unable to fetch mirror: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("unable to fetch mirror: %s", err)) return } err = collection.Add(repo) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to add mirror: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to add mirror: %s", err)) return } c.JSON(201, repo) } -// DELETE /api/mirrors/:name +// @Summary Delete Mirror +// @Description **Delete a mirror** +// @Tags Mirrors +// @Param name path string true "mirror name" +// @Param force query int true "force: 1 to enable" +// @Produce json +// @Success 200 {object} task.ProcessReturnValue +// @Failure 404 {object} Error "Mirror not found" +// @Failure 403 {object} Error "Unable to delete mirror with snapshots" +// @Failure 500 {object} Error "Unable to delete" +// @Router /api/mirrors/{name} [delete] func apiMirrorsDrop(c *gin.Context) { name := c.Params.ByName("name") force := c.Request.URL.Query().Get("force") == "1" @@ -141,13 +180,13 @@ func apiMirrorsDrop(c *gin.Context) { repo, err := mirrorCollection.ByName(name) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to drop: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to drop: %s", err)) return } resources := []string{string(repo.Key())} taskName := fmt.Sprintf("Delete mirror %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := repo.CheckLock() if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to drop: %v", err) @@ -157,7 +196,7 @@ func apiMirrorsDrop(c *gin.Context) { snapshots := snapshotCollection.ByRemoteRepoSource(repo) if len(snapshots) > 0 { - return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("won't delete mirror with snapshots, use 'force=1' to override") + return &task.ProcessReturnValue{Code: http.StatusForbidden, Value: nil}, fmt.Errorf("won't delete mirror with snapshots, use 'force=1' to override") } } @@ -169,7 +208,15 @@ func apiMirrorsDrop(c *gin.Context) { }) } -// GET /api/mirrors/:name +// @Summary Show Mirror +// @Description **Get mirror information by name** +// @Tags Mirrors +// @Param name path string true "mirror name" +// @Produce json +// @Success 200 {object} deb.RemoteRepo +// @Failure 404 {object} Error "Mirror not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/mirrors/{name} [get] func apiMirrorsShow(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.RemoteRepoCollection() @@ -177,19 +224,30 @@ func apiMirrorsShow(c *gin.Context) { name := c.Params.ByName("name") repo, err := collection.ByName(name) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to show: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to show: %s", err)) return } err = collection.LoadComplete(repo) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to show: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to show: %s", err)) } c.JSON(200, repo) } -// GET /api/mirrors/:name/packages +// @Summary List Mirror Packages +// @Description **Get a list of packages from a mirror** +// @Tags Mirrors +// @Param name path string true "mirror name" +// @Param q query string false "search query" +// @Param format query string false "format: `details` for more detailed information" +// @Produce json +// @Success 200 {array} deb.Package "List of Packages" +// @Failure 400 {object} Error "Unable to determine list of architectures" +// @Failure 404 {object} Error "Mirror not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/mirrors/{name}/packages [get] func apiMirrorsPackages(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.RemoteRepoCollection() @@ -197,17 +255,17 @@ func apiMirrorsPackages(c *gin.Context) { name := c.Params.ByName("name") repo, err := collection.ByName(name) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to show: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to show: %s", err)) return } err = collection.LoadComplete(repo) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to show: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to show: %s", err)) } if repo.LastDownloadDate.IsZero() { - c.AbortWithError(404, fmt.Errorf("unable to show package list, mirror hasn't been downloaded yet")) + AbortWithJSONError(c, 404, fmt.Errorf("unable to show package list, mirror hasn't been downloaded yet")) return } @@ -216,7 +274,7 @@ func apiMirrorsPackages(c *gin.Context) { list, err := deb.NewPackageListFromRefList(reflist, collectionFactory.PackageCollection(), nil) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -224,7 +282,7 @@ func apiMirrorsPackages(c *gin.Context) { if queryS != "" { q, err := query.Parse(c.Request.URL.Query().Get("q")) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -241,7 +299,7 @@ func apiMirrorsPackages(c *gin.Context) { sort.Strings(architecturesList) if len(architecturesList) == 0 { - c.AbortWithError(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly")) + AbortWithJSONError(c, 400, fmt.Errorf("unable to determine list of architectures, please specify explicitly")) return } } @@ -251,7 +309,7 @@ func apiMirrorsPackages(c *gin.Context) { list, err = list.Filter([]deb.PackageQuery{q}, withDeps, nil, context.DependencyOptions(), architecturesList) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to search: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to search: %s", err)) } } @@ -267,36 +325,65 @@ func apiMirrorsPackages(c *gin.Context) { } } -// PUT /api/mirrors/:name +type mirrorUpdateParams struct { + // Change mirror name to `Name` + Name string ` json:"Name" example:"mirror1"` + // Url of the archive to mirror + ArchiveURL string ` json:"ArchiveURL" example:"http://deb.debian.org/debian"` + // Package query that is applied to mirror packages + Filter string ` json:"Filter" example:"xserver-xorg"` + // Limit mirror to those architectures, if not specified aptly would fetch all architectures + Architectures []string ` json:"Architectures" example:"amd64"` + // Components to mirror, if not specified aptly would fetch all components + Components []string ` json:"Components" example:"main"` + // Gpg keyring(s) for verifing Release file + Keyrings []string ` json:"Keyrings" example:"trustedkeys.gpg"` + // Set "true" to include dependencies of matching packages when filtering + FilterWithDeps bool ` json:"FilterWithDeps"` + // Set "true" to mirror source packages + DownloadSources bool ` json:"DownloadSources"` + // Set "true" to mirror udeb files + DownloadUdebs bool ` json:"DownloadUdebs"` + // Set "true" to skip checking if the given components are in the Release file + SkipComponentCheck bool ` json:"SkipComponentCheck"` + // Set "true" to skip checking if the given architectures are in the Release file + SkipArchitectureCheck bool ` json:"SkipArchitectureCheck"` + // Set "true" to ignore checksum errors + IgnoreChecksums bool ` json:"IgnoreChecksums"` + // Set "true" to skip the verification of Release file signatures + IgnoreSignatures bool ` json:"IgnoreSignatures"` + // Set "true" to force a mirror update even if another process is already updating the mirror (use with caution!) + ForceUpdate bool ` json:"ForceUpdate"` + // Set "true" to skip downloading already downloaded packages + SkipExistingPackages bool ` json:"SkipExistingPackages"` +} + +// @Summary Update Mirror +// @Description **Update Mirror and download packages** +// @Tags Mirrors +// @Param name path string true "mirror name to update" +// @Consume json +// @Param request body mirrorUpdateParams true "Parameters" +// @Produce json +// @Success 200 {object} task.ProcessReturnValue "Mirror was updated successfully" +// @Success 202 {object} task.Task "Mirror is being updated" +// @Failure 400 {object} Error "Unable to determine list of architectures" +// @Failure 404 {object} Error "Mirror not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/mirrors/{name} [put] func apiMirrorsUpdate(c *gin.Context) { var ( err error remote *deb.RemoteRepo + b mirrorUpdateParams ) - var b struct { - Name string - ArchiveURL string - Filter string - Architectures []string - Components []string - Keyrings []string - FilterWithDeps bool - DownloadSources bool - DownloadUdebs bool - SkipComponentCheck bool - IgnoreChecksums bool - IgnoreSignatures bool - ForceUpdate bool - SkipExistingPackages bool - } - collectionFactory := context.NewCollectionFactory() collection := collectionFactory.RemoteRepoCollection() remote, err = collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -304,12 +391,14 @@ func apiMirrorsUpdate(c *gin.Context) { b.DownloadUdebs = remote.DownloadUdebs b.DownloadSources = remote.DownloadSources b.SkipComponentCheck = remote.SkipComponentCheck + b.SkipArchitectureCheck = remote.SkipArchitectureCheck b.FilterWithDeps = remote.FilterWithDeps b.Filter = remote.Filter b.Architectures = remote.Architectures b.Components = remote.Components + b.IgnoreSignatures = context.Config().GpgDisableVerify - log.Printf("%s: Starting mirror update\n", b.Name) + log.Info().Msgf("%s: Starting mirror update", b.Name) if c.Bind(&b) != nil { return @@ -318,14 +407,14 @@ func apiMirrorsUpdate(c *gin.Context) { if b.Name != remote.Name { _, err = collection.ByName(b.Name) if err == nil { - c.AbortWithError(409, fmt.Errorf("unable to rename: mirror %s already exists", b.Name)) + AbortWithJSONError(c, 409, fmt.Errorf("unable to rename: mirror %s already exists", b.Name)) return } } if b.DownloadUdebs != remote.DownloadUdebs { if remote.IsFlat() && b.DownloadUdebs { - c.AbortWithError(400, fmt.Errorf("unable to update: flat mirrors don't support udebs")) + AbortWithJSONError(c, 400, fmt.Errorf("unable to update: flat mirrors don't support udebs")) return } } @@ -338,14 +427,15 @@ func apiMirrorsUpdate(c *gin.Context) { remote.DownloadUdebs = b.DownloadUdebs remote.DownloadSources = b.DownloadSources remote.SkipComponentCheck = b.SkipComponentCheck + remote.SkipArchitectureCheck = b.SkipArchitectureCheck remote.FilterWithDeps = b.FilterWithDeps remote.Filter = b.Filter remote.Architectures = b.Architectures remote.Components = b.Components - verifier, err := getVerifier(b.IgnoreSignatures, b.Keyrings) + verifier, err := getVerifier(b.Keyrings) if err != nil { - c.AbortWithError(400, fmt.Errorf("unable to initialize GPG verifier: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("unable to initialize GPG verifier: %s", err)) return } @@ -353,7 +443,7 @@ func apiMirrorsUpdate(c *gin.Context) { maybeRunTaskInBackground(c, "Update mirror "+b.Name, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { downloader := context.NewDownloader(out) - err := remote.Fetch(downloader, verifier) + err := remote.Fetch(downloader, verifier, b.IgnoreSignatures) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) } @@ -365,7 +455,7 @@ func apiMirrorsUpdate(c *gin.Context) { } } - err = remote.DownloadPackageIndexes(out, downloader, verifier, collectionFactory, b.SkipComponentCheck) + err = remote.DownloadPackageIndexes(out, downloader, verifier, collectionFactory, b.IgnoreSignatures, b.SkipComponentCheck) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) } @@ -458,7 +548,7 @@ func apiMirrorsUpdate(c *gin.Context) { } }() - log.Printf("%s: Spawning background processes...\n", b.Name) + log.Info().Msgf("%s: Spawning background processes...", b.Name) var wg sync.WaitGroup for i := 0; i < context.Config().DownloadConcurrency; i++ { wg.Add(1) @@ -476,7 +566,16 @@ func apiMirrorsUpdate(c *gin.Context) { var e error // provision download location - task.TempDownPath, e = context.PackagePool().(aptly.LocalPackagePool).GenerateTempPath(task.File.Filename) + if pp, ok := context.PackagePool().(aptly.LocalPackagePool); ok { + task.TempDownPath, e = pp.GenerateTempPath(task.File.Filename) + } else { + var file *os.File + file, e = os.CreateTemp("", task.File.Filename) + if e == nil { + task.TempDownPath = file.Name() + file.Close() + } + } if e != nil { pushError(e) continue @@ -494,6 +593,20 @@ func apiMirrorsUpdate(c *gin.Context) { continue } + // and import it back to the pool + task.File.PoolPath, err = context.PackagePool().Import(task.TempDownPath, task.File.Filename, &task.File.Checksums, true, collectionFactory.ChecksumCollection(nil)) + if err != nil { + //return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to import file: %s", err) + pushError(err) + continue + } + + // update "attached" files if any + for _, additionalAtask := range task.Additional { + additionalAtask.File.PoolPath = task.File.PoolPath + additionalAtask.File.Checksums = task.File.Checksums + } + task.Done = true taskFinished <- task case <-context.Done(): @@ -505,32 +618,22 @@ func apiMirrorsUpdate(c *gin.Context) { } // Wait for all download goroutines to finish - log.Printf("%s: Waiting for background processes to finish...\n", b.Name) + log.Info().Msgf("%s: Waiting for background processes to finish...", b.Name) wg.Wait() - log.Printf("%s: Background processes finished\n", b.Name) + log.Info().Msgf("%s: Background processes finished", b.Name) close(taskFinished) - for idx := range queue { + defer func() { + for _, task := range queue { + if task.TempDownPath == "" { + continue + } - atask := &queue[idx] - - if !atask.Done { - // download not finished yet - continue + if err := os.Remove(task.TempDownPath); err != nil && !os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, "Failed to delete %s: %v\n", task.TempDownPath, err) + } } - - // and import it back to the pool - atask.File.PoolPath, err = context.PackagePool().Import(atask.TempDownPath, atask.File.Filename, &atask.File.Checksums, true, collectionFactory.ChecksumCollection(nil)) - if err != nil { - return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to import file: %s", err) - } - - // update "attached" files if any - for _, additionalAtask := range atask.Additional { - additionalAtask.File.PoolPath = atask.File.PoolPath - additionalAtask.File.Checksums = atask.File.Checksums - } - } + }() select { case <-context.Done(): @@ -539,18 +642,18 @@ func apiMirrorsUpdate(c *gin.Context) { } if len(errors) > 0 { - log.Printf("%s: Unable to update because of previous errors\n", b.Name) + log.Info().Msgf("%s: Unable to update because of previous errors", b.Name) return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: download errors:\n %s", strings.Join(errors, "\n ")) } - log.Printf("%s: Finalizing download\n", b.Name) + log.Info().Msgf("%s: Finalizing download...", b.Name) remote.FinalizeDownload(collectionFactory, out) err = collectionFactory.RemoteRepoCollection().Update(remote) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) } - log.Printf("%s: Mirror updated successfully!\n", b.Name) + log.Info().Msgf("%s: Mirror updated successfully", b.Name) return &task.ProcessReturnValue{Code: http.StatusNoContent, Value: nil}, nil }) } diff --git a/api/packages.go b/api/packages.go index e560076a..09ae785a 100644 --- a/api/packages.go +++ b/api/packages.go @@ -9,9 +9,24 @@ func apiPackagesShow(c *gin.Context) { collectionFactory := context.NewCollectionFactory() p, err := collectionFactory.PackageCollection().ByKey([]byte(c.Params.ByName("key"))) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } c.JSON(200, p) } + +// @Summary Get packages +// @Description Get list of packages. +// @Tags Packages +// @Consume json +// @Produce json +// @Param q query string false "search query" +// @Param format query string false "format: `details` for more detailed information" +// @Success 200 {array} string "List of packages" +// @Router /api/packages [get] +func apiPackages(c *gin.Context) { + collectionFactory := context.NewCollectionFactory() + collection := collectionFactory.PackageCollection() + showPackages(c, collection.AllPackageRefs(), collectionFactory) +} diff --git a/api/packages_test.go b/api/packages_test.go new file mode 100644 index 00000000..221a5ab1 --- /dev/null +++ b/api/packages_test.go @@ -0,0 +1,18 @@ +package api + +import ( + . "gopkg.in/check.v1" +) + +type PackagesSuite struct { + ApiSuite +} + +var _ = Suite(&PackagesSuite{}) + +func (s *PackagesSuite) TestPackagesGetMaximumVersion(c *C) { + response, err := s.HTTPRequest("GET", "/api/repos/dummy/packages?maximumVersion=1", nil) + c.Assert(err, IsNil) + c.Check(response.Code, Equals, 200) + c.Check(response.Body.String(), Equals, "[]") +} diff --git a/api/publish.go b/api/publish.go index d2287dbd..9873cd58 100644 --- a/api/publish.go +++ b/api/publish.go @@ -16,7 +16,6 @@ import ( // SigningOptions is a shared between publish API GPG options structure type SigningOptions struct { Skip bool - Batch bool GpgKey string Keyring string SecretKeyring string @@ -33,7 +32,9 @@ func getSigner(options *SigningOptions) (pgp.Signer, error) { signer.SetKey(options.GpgKey) signer.SetKeyRing(options.Keyring, options.SecretKeyring) signer.SetPassphrase(options.Passphrase, options.PassphraseFile) - signer.SetBatch(options.Batch) + + // If Batch is false, GPG will ask for passphrase on stdin, which would block the api process + signer.SetBatch(true) err := signer.Init() if err != nil { @@ -43,16 +44,23 @@ func getSigner(options *SigningOptions) (pgp.Signer, error) { return signer, nil } -// Replace '_' with '/' and double '__' with single '_' -func parseEscapedPath(path string) string { +// Replace '_' with '/' and double '__' with single '_', SanitizePath +func slashEscape(path string) string { result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1) + result = utils.SanitizePath(result) if result == "" { result = "." } return result } -// GET /publish +// @Summary Get publish points +// @Description Get list of available publish points. Each publish point is returned as in “show” API. +// @Tags Publish +// @Produce json +// @Success 200 {array} deb.PublishedRepo +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish [get] func apiPublishList(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.PublishedRepoCollection() @@ -60,7 +68,7 @@ func apiPublishList(c *gin.Context) { result := make([]*deb.PublishedRepo, 0, collection.Len()) err := collection.ForEach(func(repo *deb.PublishedRepo) error { - err := collection.LoadComplete(repo, collectionFactory) + err := collection.LoadShallow(repo, collectionFactory) if err != nil { return err } @@ -71,7 +79,7 @@ func apiPublishList(c *gin.Context) { }) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -80,7 +88,7 @@ func apiPublishList(c *gin.Context) { // POST /publish/:prefix func apiPublishRepoOrSnapshot(c *gin.Context) { - param := parseEscapedPath(c.Params.ByName("prefix")) + param := slashEscape(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) var b struct { @@ -100,20 +108,23 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { Architectures []string Signing SigningOptions AcquireByHash *bool + MultiDist bool } if c.Bind(&b) != nil { return } + b.Distribution = utils.SanitizePath(b.Distribution) + signer, err := getSigner(&b.Signing) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to initialize GPG signer: %s", err)) return } if len(b.Sources) == 0 { - c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty")) + AbortWithJSONError(c, 400, fmt.Errorf("unable to publish: soures are empty")) return } @@ -123,7 +134,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { var resources []string collectionFactory := context.NewCollectionFactory() - if b.SourceKind == "snapshot" { + if b.SourceKind == deb.SourceSnapshot { var snapshot *deb.Snapshot snapshotCollection := collectionFactory.SnapshotCollection() @@ -134,14 +145,14 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { snapshot, err = snapshotCollection.ByName(source.Name) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to publish: %s", err)) return } resources = append(resources, string(snapshot.ResourceKey())) err = snapshotCollection.LoadComplete(snapshot) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to publish: %s", err)) return } @@ -158,26 +169,26 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { localRepo, err = localCollection.ByName(source.Name) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to publish: %s", err)) return } resources = append(resources, string(localRepo.Key())) err = localCollection.LoadComplete(localRepo) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to publish: %s", err)) } sources = append(sources, localRepo) } } else { - c.AbortWithError(400, fmt.Errorf("unknown SourceKind")) + AbortWithJSONError(c, 400, fmt.Errorf("unknown SourceKind")) return } - published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory) + published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory, b.MultiDist) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to publish: %s", err)) return } @@ -211,7 +222,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { } published.SkipBz2 = context.Config().SkipBz2Publishing - if b.SkipContents != nil { + if b.SkipBz2 != nil { published.SkipBz2 = *b.SkipBz2 } @@ -241,9 +252,9 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { // PUT /publish/:prefix/:distribution func apiPublishUpdateSwitch(c *gin.Context) { - param := parseEscapedPath(c.Params.ByName("prefix")) + param := slashEscape(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) - distribution := c.Params.ByName("distribution") + distribution := utils.SanitizePath(c.Params.ByName("distribution")) var b struct { ForceOverwrite bool @@ -256,6 +267,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { Name string `binding:"required"` } AcquireByHash *bool + MultiDist *bool } if c.Bind(&b) != nil { @@ -264,7 +276,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { signer, err := getSigner(&b.Signing) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to initialize GPG signer: %s", err)) return } @@ -273,12 +285,12 @@ func apiPublishUpdateSwitch(c *gin.Context) { published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) if err != nil { - c.AbortWithError(404, fmt.Errorf("unable to update: %s", err)) + AbortWithJSONError(c, 404, fmt.Errorf("unable to update: %s", err)) return } err = collection.LoadComplete(published, collectionFactory) if err != nil { - c.AbortWithError(500, fmt.Errorf("unable to update: %s", err)) + AbortWithJSONError(c, 500, fmt.Errorf("unable to update: %s", err)) return } @@ -288,7 +300,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { if published.SourceKind == deb.SourceLocalRepo { if len(b.Snapshots) > 0 { - c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo")) + AbortWithJSONError(c, 400, fmt.Errorf("snapshots shouldn't be given when updating local repo")) return } updatedComponents = published.Components() @@ -296,23 +308,17 @@ func apiPublishUpdateSwitch(c *gin.Context) { published.UpdateLocalRepo(component) } } else if published.SourceKind == "snapshot" { - publishedComponents := published.Components() for _, snapshotInfo := range b.Snapshots { - if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) { - c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component)) - return - } - snapshotCollection := collectionFactory.SnapshotCollection() snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name) if err2 != nil { - c.AbortWithError(404, err2) + AbortWithJSONError(c, 404, err2) return } err2 = snapshotCollection.LoadComplete(snapshot) if err2 != nil { - c.AbortWithError(500, err2) + AbortWithJSONError(c, 500, err2) return } @@ -321,7 +327,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { updatedSnapshots = append(updatedSnapshots, snapshot.Name) } } else { - c.AbortWithError(500, fmt.Errorf("unknown published repository type")) + AbortWithJSONError(c, 500, fmt.Errorf("unknown published repository type")) return } @@ -337,9 +343,13 @@ func apiPublishUpdateSwitch(c *gin.Context) { published.AcquireByHash = *b.AcquireByHash } + if b.MultiDist != nil { + published.MultiDist = *b.MultiDist + } + resources = append(resources, string(published.Key())) taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", ")) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) @@ -367,7 +377,7 @@ func apiPublishDrop(c *gin.Context) { force := c.Request.URL.Query().Get("force") == "1" skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1" - param := parseEscapedPath(c.Params.ByName("prefix")) + param := slashEscape(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) distribution := c.Params.ByName("distribution") @@ -376,14 +386,14 @@ func apiPublishDrop(c *gin.Context) { published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) if err != nil { - c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("unable to drop: %s", err)) + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("unable to drop: %s", err)) return } resources := []string{string(published.Key())} taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := collection.Remove(context, storage, prefix, distribution, collectionFactory, out, force, skipCleanup) if err != nil { diff --git a/api/repos.go b/api/repos.go index 24b2530d..bc55dd9f 100644 --- a/api/repos.go +++ b/api/repos.go @@ -5,6 +5,7 @@ import ( "net/http" "os" "path/filepath" + "sort" "strings" "text/template" @@ -17,7 +18,44 @@ import ( "github.com/gin-gonic/gin" ) -// GET /api/repos +// GET /repos +func reposListInAPIMode(localRepos map[string]utils.FileSystemPublishRoot) gin.HandlerFunc { + return func(c *gin.Context) { + c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8") + c.Writer.Flush() + c.Writer.WriteString("
\n")
+		if len(localRepos) == 0 {
+			c.Writer.WriteString("default\n")
+		}
+		for publishPrefix := range localRepos {
+			c.Writer.WriteString(fmt.Sprintf("%[1]s\n", publishPrefix))
+		}
+		c.Writer.WriteString("
") + c.Writer.Flush() + } +} + +// GET /repos/:storage/*pkgPath +func reposServeInAPIMode(c *gin.Context) { + pkgpath := c.Param("pkgPath") + + storage := c.Param("storage") + if storage == "-" { + storage = "" + } else { + storage = "filesystem:" + storage + } + + publicPath := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage).PublicPath() + c.FileFromFS(pkgpath, http.Dir(publicPath)) +} + +// @Summary Get repos +// @Description Get list of available repos. Each repo is returned as in “show” API. +// @Tags Repos +// @Produce json +// @Success 200 {array} deb.LocalRepo +// @Router /api/repos [get] func apiReposList(c *gin.Context) { result := []*deb.LocalRepo{} @@ -31,7 +69,18 @@ func apiReposList(c *gin.Context) { c.JSON(200, result) } -// POST /api/repos +// @Summary Create repository +// @Description Create a local repository. +// @Tags Repos +// @Produce json +// @Consume json +// @Param Name query string false "Name of repository to be created." +// @Param Comment query string false "Text describing local repository, for the user" +// @Param DefaultDistribution query string false "Default distribution when publishing from this local repo" +// @Param DefaultComponent query string false "Default component when publishing from this local repo" +// @Success 201 {object} deb.LocalRepo +// @Failure 400 {object} Error "Repository already exists" +// @Router /api/repos [post] func apiReposCreate(c *gin.Context) { var b struct { Name string `binding:"required"` @@ -52,7 +101,7 @@ func apiReposCreate(c *gin.Context) { collection := collectionFactory.LocalRepoCollection() err := collection.Add(repo) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -77,7 +126,7 @@ func apiReposEdit(c *gin.Context) { repo, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -85,7 +134,7 @@ func apiReposEdit(c *gin.Context) { _, err := collection.ByName(*b.Name) if err == nil { // already exists - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } repo.Name = *b.Name @@ -102,7 +151,7 @@ func apiReposEdit(c *gin.Context) { err = collection.Update(repo) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -110,13 +159,21 @@ func apiReposEdit(c *gin.Context) { } // GET /api/repos/:name +// @Summary Get repository info by name +// @Description Returns basic information about local repository. +// @Tags Repos +// @Produce json +// @Param name path string true "Repository name" +// @Success 200 {object} deb.LocalRepo +// @Failure 404 {object} Error "Repository not found" +// @Router /api/repos/{name} [get] func apiReposShow(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.LocalRepoCollection() repo, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -135,13 +192,13 @@ func apiReposDrop(c *gin.Context) { repo, err := collection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } resources := []string{string(repo.Key())} taskName := fmt.Sprintf("Delete repo %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { published := publishedCollection.ByLocalRepo(repo) if len(published) > 0 { return &task.ProcessReturnValue{Code: http.StatusConflict, Value: nil}, fmt.Errorf("unable to drop, local repo is published") @@ -165,13 +222,13 @@ func apiReposPackagesShow(c *gin.Context) { repo, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(repo) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -193,18 +250,18 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li repo, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(repo) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } resources := []string{string(repo.Key())} - maybeRunTaskInBackground(c, taskNamePrefix+repo.Name, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskNamePrefix+repo.Name, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { out.Printf("Loading packages...\n") list, err := deb.NewPackageListFromRefList(repo.RefList(), collectionFactory.PackageCollection(), nil) if err != nil { @@ -262,7 +319,22 @@ func apiReposPackageFromFile(c *gin.Context) { apiReposPackageFromDir(c) } -// POST /repos/:name/file/:dir +// @Summary Add packages from uploaded file/directory +// @Description Import packages from files (uploaded using File Upload API) to the local repository. If directory specified, aptly would discover package files automatically. +// @Description Adding same package to local repository is not an error. +// @Description By default aptly would try to remove every successfully processed file and directory `dir` (if it becomes empty after import). +// @Tags Repos +// @Param name path string true "Repository name" +// @Param dir path string true "Directory to add" +// @Consume json +// @Param noRemove query string false "when value is set to 1, don’t remove any files" +// @Param forceReplace query string false "when value is set to 1, remove packages conflicting with package being added (in local repository)" +// @Produce json +// @Success 200 {string} string "OK" +// @Failure 400 {object} Error "wrong file" +// @Failure 404 {object} Error "Repository not found" +// @Failure 500 {object} Error "Error adding files" +// @Router /api/repos/{name}/{dir} [post] func apiReposPackageFromDir(c *gin.Context) { forceReplace := c.Request.URL.Query().Get("forceReplace") == "1" noRemove := c.Request.URL.Query().Get("noRemove") == "1" @@ -271,10 +343,10 @@ func apiReposPackageFromDir(c *gin.Context) { return } - dirParam := c.Params.ByName("dir") - fileParam := c.Params.ByName("file") + dirParam := utils.SanitizePath(c.Params.ByName("dir")) + fileParam := utils.SanitizePath(c.Params.ByName("file")) if fileParam != "" && !verifyPath(fileParam) { - c.AbortWithError(400, fmt.Errorf("wrong file")) + AbortWithJSONError(c, 400, fmt.Errorf("wrong file")) return } @@ -284,13 +356,13 @@ func apiReposPackageFromDir(c *gin.Context) { name := c.Params.ByName("name") repo, err := collection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(repo) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -306,7 +378,7 @@ func apiReposPackageFromDir(c *gin.Context) { resources := []string{string(repo.Key())} resources = append(resources, sources...) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { verifier := context.GetVerifier() var ( @@ -382,6 +454,150 @@ func apiReposPackageFromDir(c *gin.Context) { }) } +// POST /repos/:name/copy/:src/:file +func apiReposCopyPackage(c *gin.Context) { + dstRepoName := c.Params.ByName("name") + srcRepoName := c.Params.ByName("src") + fileName := c.Params.ByName("file") + + jsonBody := struct { + WithDeps bool `json:"with-deps,omitempty"` + DryRun bool `json:"dry-run,omitempty"` + }{ + WithDeps: false, + DryRun: false, + } + + err := c.Bind(&jsonBody) + if err != nil { + return + } + + collectionFactory := context.NewCollectionFactory() + dstRepo, err := collectionFactory.LocalRepoCollection().ByName(dstRepoName) + if err != nil { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("dest repo error: %s", err)) + return + } + + err = collectionFactory.LocalRepoCollection().LoadComplete(dstRepo) + if err != nil { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("dest repo error: %s", err)) + return + } + + var ( + srcRefList *deb.PackageRefList + srcRepo *deb.LocalRepo + ) + + srcRepo, err = collectionFactory.LocalRepoCollection().ByName(srcRepoName) + if err != nil { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("src repo error: %s", err)) + return + } + + if srcRepo.UUID == dstRepo.UUID { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("dest and source are identical")) + return + } + + err = collectionFactory.LocalRepoCollection().LoadComplete(srcRepo) + if err != nil { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("src repo error: %s", err)) + return + } + + srcRefList = srcRepo.RefList() + taskName := fmt.Sprintf("Copy packages from repo %s to repo %s", srcRepoName, dstRepoName) + resources := []string{string(dstRepo.Key()), string(srcRepo.Key())} + + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { + reporter := &aptly.RecordingResultReporter{ + Warnings: []string{}, + AddedLines: []string{}, + RemovedLines: []string{}, + } + + dstList, err := deb.NewPackageListFromRefList(dstRepo.RefList(), collectionFactory.PackageCollection(), context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to load packages in dest: %s", err) + + } + + srcList, err := deb.NewPackageListFromRefList(srcRefList, collectionFactory.PackageCollection(), context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to load packages in src: %s", err) + } + + srcList.PrepareIndex() + + var architecturesList []string + + if jsonBody.WithDeps { + dstList.PrepareIndex() + + // Calculate architectures + if len(context.ArchitecturesList()) > 0 { + architecturesList = context.ArchitecturesList() + } else { + architecturesList = dstList.Architectures(false) + } + + sort.Strings(architecturesList) + + if len(architecturesList) == 0 { + return &task.ProcessReturnValue{Code: http.StatusUnprocessableEntity, Value: nil}, fmt.Errorf("unable to determine list of architectures, please specify explicitly") + } + } + + // srcList.Filter|FilterWithProgress only accept query list + queries := make([]deb.PackageQuery, 1) + queries[0], err = query.Parse(fileName) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusUnprocessableEntity, Value: nil}, fmt.Errorf("unable to parse query '%s': %s", fileName, err) + } + + toProcess, err := srcList.FilterWithProgress(queries, jsonBody.WithDeps, dstList, context.DependencyOptions(), architecturesList, context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("filter error: %s", err) + } + + if toProcess.Len() == 0 { + return &task.ProcessReturnValue{Code: http.StatusUnprocessableEntity, Value: nil}, fmt.Errorf("no package found for filter: '%s'", fileName) + } + + err = toProcess.ForEach(func(p *deb.Package) error { + err = dstList.Add(p) + if err != nil { + return err + } + + name := fmt.Sprintf("added %s-%s(%s)", p.Name, p.Version, p.Architecture) + reporter.AddedLines = append(reporter.AddedLines, name) + return nil + }) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("error processing dest add: %s", err) + } + + if jsonBody.DryRun { + reporter.Warning("Changes not saved, as dry run has been requested") + } else { + dstRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(dstList)) + + err = collectionFactory.LocalRepoCollection().Update(dstRepo) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save: %s", err) + } + } + + return &task.ProcessReturnValue{Code: http.StatusOK, Value: gin.H{ + "Report": reporter, + }}, nil + }) +} + // POST /repos/:name/include/:dir/:file func apiReposIncludePackageFromFile(c *gin.Context) { // redirect all work to dir method @@ -404,10 +620,10 @@ func apiReposIncludePackageFromDir(c *gin.Context) { var sources []string var taskName string - dirParam := c.Params.ByName("dir") - fileParam := c.Params.ByName("file") + dirParam := utils.SanitizePath(c.Params.ByName("dir")) + fileParam := utils.SanitizePath(c.Params.ByName("file")) if fileParam != "" && !verifyPath(fileParam) { - c.AbortWithError(400, fmt.Errorf("wrong file")) + AbortWithJSONError(c, 400, fmt.Errorf("wrong file")) return } @@ -421,7 +637,7 @@ func apiReposIncludePackageFromDir(c *gin.Context) { repoTemplate, err := template.New("repo").Parse(repoTemplateString) if err != nil { - c.AbortWithError(400, fmt.Errorf("error parsing repo template: %s", err)) + AbortWithJSONError(c, 400, fmt.Errorf("error parsing repo template: %s", err)) return } @@ -432,7 +648,7 @@ func apiReposIncludePackageFromDir(c *gin.Context) { // repo template string is simple text so only use resource key of specific repository repo, err := collectionFactory.LocalRepoCollection().ByName(repoTemplateString) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -440,7 +656,7 @@ func apiReposIncludePackageFromDir(c *gin.Context) { } resources = append(resources, sources...) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { var ( err error verifier = context.GetVerifier() diff --git a/api/router.go b/api/router.go index d3b4e98f..d5b6e612 100644 --- a/api/router.go +++ b/api/router.go @@ -2,36 +2,92 @@ package api import ( "net/http" + "os" + "sync/atomic" + "github.com/aptly-dev/aptly/aptly" ctx "github.com/aptly-dev/aptly/context" + "github.com/aptly-dev/aptly/utils" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/rs/zerolog/log" + + _ "github.com/aptly-dev/aptly/docs" // import docs + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" ) var context *ctx.AptlyContext func apiMetricsGet() gin.HandlerFunc { return func(c *gin.Context) { + countPackagesByRepos() promhttp.Handler().ServeHTTP(c.Writer, c.Request) } } +func redirectSwagger(c *gin.Context) { + if c.Request.URL.Path == "/docs/" { + c.Redirect(http.StatusMovedPermanently, "/docs/index.html") + return + } + c.Next() +} + // Router returns prebuilt with routes http.Handler +// @title Aptly API +// @version 1.0 +// @description Aptly REST API Documentation + +// @contact.name Aptly +// @contact.url http://github.com/aptly-dev/aptly +// @contact.email support@aptly.info + +// @license.name MIT License +// @license.url http://www. + +// @BasePath /api func Router(c *ctx.AptlyContext) http.Handler { - context = c - - router := gin.Default() - router.UseRawPath = true - router.Use(gin.ErrorLogger()) - - if c.Config().EnableMetricsEndpoint { - router.Use(instrumentHandlerInFlight(apiRequestsInFlightGauge, getBasePath)) - router.Use(instrumentHandlerCounter(apiRequestsTotalCounter, getBasePath)) - router.Use(instrumentHandlerRequestSize(apiRequestSizeSummary, getBasePath)) - router.Use(instrumentHandlerResponseSize(apiResponseSizeSummary, getBasePath)) - router.Use(instrumentHandlerDuration(apiRequestsDurationSummary, getBasePath)) + if aptly.EnableDebug { + gin.SetMode(gin.DebugMode) + } else { + gin.SetMode(gin.ReleaseMode) } + router := gin.New() + context = c + + router.UseRawPath = true + + if c.Config().LogFormat == "json" { + c.StructuredLogging(true) + utils.SetupJSONLogger(c.Config().LogLevel, os.Stdout) + gin.DefaultWriter = utils.LogWriter{Logger: log.Logger} + router.Use(JSONLogger()) + } else { + c.StructuredLogging(false) + utils.SetupDefaultLogger(c.Config().LogLevel) + router.Use(gin.Logger()) + } + + router.Use(gin.Recovery(), gin.ErrorLogger()) + + if c.Config().EnableSwaggerEndpoint { + router.Use(redirectSwagger) + url := ginSwagger.URL("/docs/doc.json") + router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url)) + } + + if c.Config().EnableMetricsEndpoint { + MetricsCollectorRegistrar.Register(router) + } + + if c.Config().ServeInAPIMode { + router.GET("/repos/", reposListInAPIMode(c.Config().FileSystemPublishRoots)) + router.GET("/repos/:storage/*pkgPath", reposServeInAPIMode) + } + + api := router.Group("/api") if context.Flags().Lookup("no-lock").Value.Get().(bool) { // We use a goroutine to count the number of // concurrent requests. When no more requests are @@ -40,7 +96,7 @@ func Router(c *ctx.AptlyContext) http.Handler { go acquireDatabase() - router.Use(func(c *gin.Context) { + api.Use(func(c *gin.Context) { var err error errCh := make(chan error) @@ -48,7 +104,7 @@ func Router(c *ctx.AptlyContext) http.Handler { err = <-errCh if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -56,7 +112,7 @@ func Router(c *ctx.AptlyContext) http.Handler { dbRequests <- dbRequest{releasedb, errCh} err = <-errCh if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) } }() @@ -64,99 +120,113 @@ func Router(c *ctx.AptlyContext) http.Handler { }) } - root := router.Group("/api") - { if c.Config().EnableMetricsEndpoint { - root.GET("/metrics", apiMetricsGet()) + api.GET("/metrics", apiMetricsGet()) } - root.GET("/version", apiVersion) + api.GET("/version", apiVersion) + api.GET("/storage", apiDiskFree) + + isReady := &atomic.Value{} + isReady.Store(false) + defer isReady.Store(true) + api.GET("/ready", apiReady(isReady)) + api.GET("/healthy", apiHealthy) } { - root.GET("/repos", apiReposList) - root.POST("/repos", apiReposCreate) - root.GET("/repos/:name", apiReposShow) - root.PUT("/repos/:name", apiReposEdit) - root.DELETE("/repos/:name", apiReposDrop) + api.GET("/repos", apiReposList) + api.POST("/repos", apiReposCreate) + api.GET("/repos/:name", apiReposShow) + api.PUT("/repos/:name", apiReposEdit) + api.DELETE("/repos/:name", apiReposDrop) - root.GET("/repos/:name/packages", apiReposPackagesShow) - root.POST("/repos/:name/packages", apiReposPackagesAdd) - root.DELETE("/repos/:name/packages", apiReposPackagesDelete) + api.GET("/repos/:name/packages", apiReposPackagesShow) + api.POST("/repos/:name/packages", apiReposPackagesAdd) + api.DELETE("/repos/:name/packages", apiReposPackagesDelete) - root.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile) - root.POST("/repos/:name/file/:dir", apiReposPackageFromDir) + api.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile) + api.POST("/repos/:name/file/:dir", apiReposPackageFromDir) + api.POST("/repos/:name/copy/:src/:file", apiReposCopyPackage) - root.POST("/repos/:name/include/:dir/:file", apiReposIncludePackageFromFile) - root.POST("/repos/:name/include/:dir", apiReposIncludePackageFromDir) + api.POST("/repos/:name/include/:dir/:file", apiReposIncludePackageFromFile) + api.POST("/repos/:name/include/:dir", apiReposIncludePackageFromDir) - root.POST("/repos/:name/snapshots", apiSnapshotsCreateFromRepository) + api.POST("/repos/:name/snapshots", apiSnapshotsCreateFromRepository) } { - root.POST("/mirrors/:name/snapshots", apiSnapshotsCreateFromMirror) + api.POST("/mirrors/:name/snapshots", apiSnapshotsCreateFromMirror) } { - root.GET("/mirrors", apiMirrorsList) - root.GET("/mirrors/:name", apiMirrorsShow) - root.GET("/mirrors/:name/packages", apiMirrorsPackages) - root.POST("/mirrors", apiMirrorsCreate) - root.PUT("/mirrors/:name", apiMirrorsUpdate) - root.DELETE("/mirrors/:name", apiMirrorsDrop) + api.GET("/mirrors", apiMirrorsList) + api.GET("/mirrors/:name", apiMirrorsShow) + api.GET("/mirrors/:name/packages", apiMirrorsPackages) + api.POST("/mirrors", apiMirrorsCreate) + api.PUT("/mirrors/:name", apiMirrorsUpdate) + api.DELETE("/mirrors/:name", apiMirrorsDrop) } { - root.POST("/gpg/key", apiGPGAddKey) + api.POST("/gpg/key", apiGPGAddKey) } { - root.GET("/files", apiFilesListDirs) - root.POST("/files/:dir", apiFilesUpload) - root.GET("/files/:dir", apiFilesListFiles) - root.DELETE("/files/:dir", apiFilesDeleteDir) - root.DELETE("/files/:dir/:name", apiFilesDeleteFile) + api.GET("/s3", apiS3List) } { - root.GET("/publish", apiPublishList) - root.POST("/publish", apiPublishRepoOrSnapshot) - root.POST("/publish/:prefix", apiPublishRepoOrSnapshot) - root.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) - root.DELETE("/publish/:prefix/:distribution", apiPublishDrop) + api.GET("/files", apiFilesListDirs) + api.POST("/files/:dir", apiFilesUpload) + api.GET("/files/:dir", apiFilesListFiles) + api.DELETE("/files/:dir", apiFilesDeleteDir) + api.DELETE("/files/:dir/:name", apiFilesDeleteFile) } { - root.GET("/snapshots", apiSnapshotsList) - root.POST("/snapshots", apiSnapshotsCreate) - root.PUT("/snapshots/:name", apiSnapshotsUpdate) - root.GET("/snapshots/:name", apiSnapshotsShow) - root.GET("/snapshots/:name/packages", apiSnapshotsSearchPackages) - root.DELETE("/snapshots/:name", apiSnapshotsDrop) - root.GET("/snapshots/:name/diff/:withSnapshot", apiSnapshotsDiff) + + api.GET("/publish", apiPublishList) + api.POST("/publish", apiPublishRepoOrSnapshot) + api.POST("/publish/:prefix", apiPublishRepoOrSnapshot) + api.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) + api.DELETE("/publish/:prefix/:distribution", apiPublishDrop) } { - root.GET("/packages/:key", apiPackagesShow) + api.GET("/snapshots", apiSnapshotsList) + api.POST("/snapshots", apiSnapshotsCreate) + api.PUT("/snapshots/:name", apiSnapshotsUpdate) + api.GET("/snapshots/:name", apiSnapshotsShow) + api.GET("/snapshots/:name/packages", apiSnapshotsSearchPackages) + api.DELETE("/snapshots/:name", apiSnapshotsDrop) + api.GET("/snapshots/:name/diff/:withSnapshot", apiSnapshotsDiff) + api.POST("/snapshots/:name/merge", apiSnapshotsMerge) + api.POST("/snapshots/:name/pull", apiSnapshotsPull) } { - root.GET("/graph.:ext", apiGraph) + api.GET("/packages/:key", apiPackagesShow) + api.GET("/packages", apiPackages) + } + + { + api.GET("/graph.:ext", apiGraph) } { - root.POST("/db/cleanup", apiDbCleanup) + api.POST("/db/cleanup", apiDbCleanup) } { - root.GET("/tasks", apiTasksList) - root.POST("/tasks-clear", apiTasksClear) - root.GET("/tasks-wait", apiTasksWait) - root.GET("/tasks/:id/wait", apiTasksWaitForTaskByID) - root.GET("/tasks/:id/output", apiTasksOutputShow) - root.GET("/tasks/:id/detail", apiTasksDetailShow) - root.GET("/tasks/:id/return_value", apiTasksReturnValueShow) - root.GET("/tasks/:id", apiTasksShow) - root.DELETE("/tasks/:id", apiTasksDelete) - root.POST("/tasks-dummy", apiTasksDummy) + api.GET("/tasks", apiTasksList) + api.POST("/tasks-clear", apiTasksClear) + api.GET("/tasks-wait", apiTasksWait) + api.GET("/tasks/:id/wait", apiTasksWaitForTaskByID) + api.GET("/tasks/:id/output", apiTasksOutputShow) + api.GET("/tasks/:id/detail", apiTasksDetailShow) + api.GET("/tasks/:id/return_value", apiTasksReturnValueShow) + api.GET("/tasks/:id", apiTasksShow) + api.DELETE("/tasks/:id", apiTasksDelete) + api.POST("/tasks-dummy", apiTasksDummy) } return router diff --git a/api/s3.go b/api/s3.go new file mode 100644 index 00000000..33ed0c83 --- /dev/null +++ b/api/s3.go @@ -0,0 +1,19 @@ +package api + +import ( + "github.com/gin-gonic/gin" +) + +// @Summary Get S3 buckets +// @Description Get list of S3 buckets. +// @Tags S3 +// @Produce json +// @Success 200 {array} string "List of S3 buckets" +// @Router /api/s3 [get] +func apiS3List(c *gin.Context) { + keys := []string{} + for k := range context.Config().S3PublishRoots { + keys = append(keys, k) + } + c.JSON(200, keys) +} diff --git a/api/snapshot.go b/api/snapshot.go index e4334e6c..3e84b1f2 100644 --- a/api/snapshot.go +++ b/api/snapshot.go @@ -3,15 +3,23 @@ package api import ( "fmt" "net/http" + "sort" + "strings" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/database" "github.com/aptly-dev/aptly/deb" + "github.com/aptly-dev/aptly/query" "github.com/aptly-dev/aptly/task" "github.com/gin-gonic/gin" ) -// GET /api/snapshots +// @Summary Get snapshots +// @Description Get list of available snapshots. Each snapshot is returned as in “show” API. +// @Tags Snapshots +// @Produce json +// @Success 200 {array} deb.Snapshot +// @Router /api/snapshots [get] func apiSnapshotsList(c *gin.Context) { SortMethodString := c.Request.URL.Query().Get("sort") @@ -55,14 +63,14 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) { repo, err = collection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } // including snapshot resource key resources := []string{string(repo.Key()), "S" + b.Name} taskName := fmt.Sprintf("Create snapshot of mirror %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := repo.CheckLock() if err != nil { return &task.ProcessReturnValue{Code: http.StatusConflict, Value: nil}, err @@ -123,20 +131,20 @@ func apiSnapshotsCreate(c *gin.Context) { for i := range b.SourceSnapshots { sources[i], err = snapshotCollection.ByName(b.SourceSnapshots[i]) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = snapshotCollection.LoadComplete(sources[i]) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } resources = append(resources, string(sources[i].ResourceKey())) } - maybeRunTaskInBackground(c, "Create snapshot "+b.Name, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, "Create snapshot "+b.Name, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { list := deb.NewPackageList() // verify package refs and build package list @@ -160,7 +168,7 @@ func apiSnapshotsCreate(c *gin.Context) { if err != nil { return &task.ProcessReturnValue{Code: http.StatusBadRequest, Value: nil}, err } - return &task.ProcessReturnValue{Code: http.StatusCreated, Value: nil}, nil + return &task.ProcessReturnValue{Code: http.StatusCreated, Value: snapshot}, nil }) } @@ -188,14 +196,14 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) { repo, err = collection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } // including snapshot resource key resources := []string{string(repo.Key()), "S" + b.Name} taskName := fmt.Sprintf("Create snapshot of repo %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := collection.LoadComplete(repo) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err @@ -240,13 +248,13 @@ func apiSnapshotsUpdate(c *gin.Context) { snapshot, err = collection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } resources := []string{string(snapshot.ResourceKey()), "S" + b.Name} taskName := fmt.Sprintf("Update snapshot %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { _, err := collection.ByName(b.Name) if err == nil { return &task.ProcessReturnValue{Code: http.StatusConflict, Value: nil}, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name) @@ -275,13 +283,13 @@ func apiSnapshotsShow(c *gin.Context) { snapshot, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(snapshot) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -299,13 +307,13 @@ func apiSnapshotsDrop(c *gin.Context) { snapshot, err := snapshotCollection.ByName(name) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } resources := []string{string(snapshot.ResourceKey())} taskName := fmt.Sprintf("Delete snapshot %s", name) - maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { published := publishedCollection.BySnapshot(snapshot) if len(published) > 0 { @@ -336,32 +344,32 @@ func apiSnapshotsDiff(c *gin.Context) { snapshotA, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } snapshotB, err := collection.ByName(c.Params.ByName("withSnapshot")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(snapshotA) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } err = collection.LoadComplete(snapshotB) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } // Calculate diff diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), collectionFactory.PackageCollection()) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } @@ -385,15 +393,303 @@ func apiSnapshotsSearchPackages(c *gin.Context) { snapshot, err := collection.ByName(c.Params.ByName("name")) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } err = collection.LoadComplete(snapshot) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } showPackages(c, snapshot.RefList(), collectionFactory) } + +type snapshotsMergeParams struct { + // List of snapshot names to be merged + Sources []string `binding:"required" json:"Sources" example:"snapshot1"` +} + +// @Summary Snapshot Merge +// @Description **Merge several source snapshots into a new snapshot** +// @Description +// @Description Merge happens from left to right. By default, packages with the same name-architecture pair are replaced during merge (package from latest snapshot on the list wins). +// @Description +// @Description If only one snapshot is specified, merge copies source into destination. +// @Tags Snapshots +// @Param name path string true "Name of the snapshot to be created" +// @Param latest query int false "merge only the latest version of each package" +// @Param no-remove query int false "all versions of packages are preserved during merge" +// @Consume json +// @Param request body snapshotsMergeParams true "Parameters" +// @Produce json +// @Success 200 +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Not Found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/snapshots/{name}/merge [post] +func apiSnapshotsMerge(c *gin.Context) { + var ( + err error + snapshot *deb.Snapshot + body snapshotsMergeParams + ) + + name := c.Params.ByName("name") + + if c.Bind(&body) != nil { + return + } + + if len(body.Sources) < 1 { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("At least one source snapshot is required")) + return + } + + latest := c.Request.URL.Query().Get("latest") == "1" + noRemove := c.Request.URL.Query().Get("no-remove") == "1" + overrideMatching := !latest && !noRemove + + if noRemove && latest { + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("no-remove and latest are mutually exclusive")) + return + } + + collectionFactory := context.NewCollectionFactory() + snapshotCollection := collectionFactory.SnapshotCollection() + + sources := make([]*deb.Snapshot, len(body.Sources)) + resources := make([]string, len(sources)) + for i := range body.Sources { + sources[i], err = snapshotCollection.ByName(body.Sources[i]) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) + return + } + + err = snapshotCollection.LoadComplete(sources[i]) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, err) + return + } + resources[i] = string(sources[i].ResourceKey()) + } + + maybeRunTaskInBackground(c, "Merge snapshot "+name, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { + result := sources[0].RefList() + for i := 1; i < len(sources); i++ { + result = result.Merge(sources[i].RefList(), overrideMatching, false) + } + + if latest { + result.FilterLatestRefs() + } + + sourceDescription := make([]string, len(sources)) + for i, s := range sources { + sourceDescription[i] = fmt.Sprintf("'%s'", s.Name) + } + + snapshot = deb.NewSnapshotFromRefList(name, sources, result, + fmt.Sprintf("Merged from sources: %s", strings.Join(sourceDescription, ", "))) + + err = collectionFactory.SnapshotCollection().Add(snapshot) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to create snapshot: %s", err) + } + + return &task.ProcessReturnValue{Code: http.StatusCreated, Value: snapshot}, nil + }) +} + +type snapshotsPullParams struct { + // Source name to be searched for packages and dependencies + Source string `binding:"required" json:"Source" example:"source-snapshot"` + // Name of the snapshot to be created + Destination string `binding:"required" json:"Destination" example:"idestination-snapshot"` + // List of package queries (i.e. name of package to be pulled from `Source`) + Queries []string `binding:"required" json:"Queries" example:"xserver-xorg"` + // List of architectures (optional) + Architectures []string ` json:"Architectures" example:"amd64, armhf"` +} + +// @Summary Snapshot Pull +// @Description **Pulls new packages and dependencies from a source snapshot into a new snapshot** +// @Description +// @Description May also upgrade package versions if name snapshot already contains packages being pulled. New snapshot `Destination` is created as result of this process. +// @Description If architectures are limited (with config architectures or parameter `Architectures`, only mentioned architectures are processed, otherwise aptly will process all architectures in the snapshot. +// @Description If following dependencies by source is enabled (using dependencyFollowSource config), pulling binary packages would also pull corresponding source packages as well. +// @Description By default aptly would remove packages matching name and architecture while importing: e.g. when importing software_1.3_amd64, package software_1.2.9_amd64 would be removed. +// @Description +// @Description With flag `no-remove` both package versions would stay in the snapshot. +// @Description +// @Description Aptly pulls first package matching each of package queries, but with flag -all-matches all matching packages would be pulled. +// @Tags Snapshots +// @Param name path string true "Name of the snapshot to be created" +// @Param all-matches query int false "pull all the packages that satisfy the dependency version requirements (default is to pull first matching package): 1 to enable" +// @Param dry-run query int false "don’t create destination snapshot, just show what would be pulled: 1 to enable" +// @Param no-deps query int false "don’t process dependencies, just pull listed packages: 1 to enable" +// @Param no-remove query int false "don’t remove other package versions when pulling package: 1 to enable" +// @Consume json +// @Param request body snapshotsPullParams true "Parameters" +// @Produce json +// @Success 200 +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Not Found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/snapshots/{name}/pull [post] +func apiSnapshotsPull(c *gin.Context) { + var ( + err error + destinationSnapshot *deb.Snapshot + body snapshotsPullParams + ) + + name := c.Params.ByName("name") + + if err = c.BindJSON(&body); err != nil { + AbortWithJSONError(c, http.StatusBadRequest, err) + return + } + + allMatches := c.Request.URL.Query().Get("all-matches") == "1" + dryRun := c.Request.URL.Query().Get("dry-run") == "1" + noDeps := c.Request.URL.Query().Get("no-deps") == "1" + noRemove := c.Request.URL.Query().Get("no-remove") == "1" + + collectionFactory := context.NewCollectionFactory() + + // Load snapshot + toSnapshot, err := collectionFactory.SnapshotCollection().ByName(name) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) + return + } + err = collectionFactory.SnapshotCollection().LoadComplete(toSnapshot) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, err) + return + } + + // Load snapshot + sourceSnapshot, err := collectionFactory.SnapshotCollection().ByName(body.Source) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) + return + } + err = collectionFactory.SnapshotCollection().LoadComplete(sourceSnapshot) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, err) + return + } + + resources := []string{string(sourceSnapshot.ResourceKey()), string(toSnapshot.ResourceKey())} + taskName := fmt.Sprintf("Pull snapshot %s into %s and save as %s", body.Source, name, body.Destination) + maybeRunTaskInBackground(c, taskName, resources, func(_ aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { + // convert snapshots to package list + toPackageList, err := deb.NewPackageListFromRefList(toSnapshot.RefList(), collectionFactory.PackageCollection(), context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + sourcePackageList, err := deb.NewPackageListFromRefList(sourceSnapshot.RefList(), collectionFactory.PackageCollection(), context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + + toPackageList.PrepareIndex() + sourcePackageList.PrepareIndex() + + var architecturesList []string + + if len(context.ArchitecturesList()) > 0 { + architecturesList = context.ArchitecturesList() + } else { + architecturesList = toPackageList.Architectures(false) + } + + architecturesList = append(architecturesList, body.Architectures...) + sort.Strings(architecturesList) + + if len(architecturesList) == 0 { + err := fmt.Errorf("unable to determine list of architectures, please specify explicitly") + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + + // Build architecture query: (arch == "i386" | arch == "amd64" | ...) + var archQuery deb.PackageQuery = &deb.FieldQuery{Field: "$Architecture", Relation: deb.VersionEqual, Value: ""} + for _, arch := range architecturesList { + archQuery = &deb.OrQuery{L: &deb.FieldQuery{Field: "$Architecture", Relation: deb.VersionEqual, Value: arch}, R: archQuery} + } + + queries := make([]deb.PackageQuery, len(body.Queries)) + for i, q := range body.Queries { + queries[i], err = query.Parse(q) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + // Add architecture filter + queries[i] = &deb.AndQuery{L: queries[i], R: archQuery} + } + + // Filter with dependencies as requested + destinationPackageList, err := sourcePackageList.FilterWithProgress(queries, !noDeps, toPackageList, context.DependencyOptions(), architecturesList, context.Progress()) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + destinationPackageList.PrepareIndex() + + removedPackages := []string{} + addedPackages := []string{} + alreadySeen := map[string]bool{} + + destinationPackageList.ForEachIndexed(func(pkg *deb.Package) error { + key := pkg.Architecture + "_" + pkg.Name + _, seen := alreadySeen[key] + + // If we haven't seen such name-architecture pair and were instructed to remove, remove it + if !noRemove && !seen { + // Remove all packages with the same name and architecture + packageSearchResults := toPackageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}, true) + for _, p := range packageSearchResults { + toPackageList.Remove(p) + removedPackages = append(removedPackages, p.String()) + } + } + + // If !allMatches, add only first matching name-arch package + if !seen || allMatches { + toPackageList.Add(pkg) + addedPackages = append(addedPackages, pkg.String()) + } + + alreadySeen[key] = true + + return nil + }) + alreadySeen = nil + + if dryRun { + response := struct { + AddedPackages []string `json:"added_packages"` + RemovedPackages []string `json:"removed_packages"` + }{ + AddedPackages: addedPackages, + RemovedPackages: removedPackages, + } + + return &task.ProcessReturnValue{Code: http.StatusOK, Value: response}, nil + } + + // Create snapshot + destinationSnapshot = deb.NewSnapshotFromPackageList(body.Destination, []*deb.Snapshot{toSnapshot, sourceSnapshot}, toPackageList, + fmt.Sprintf("Pulled into '%s' with '%s' as source, pull request was: '%s'", toSnapshot.Name, sourceSnapshot.Name, strings.Join(body.Queries, ", "))) + + err = collectionFactory.SnapshotCollection().Add(destinationSnapshot) + if err != nil { + return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, err + } + + return &task.ProcessReturnValue{Code: http.StatusCreated, Value: destinationSnapshot}, nil + }) +} diff --git a/api/storage.go b/api/storage.go new file mode 100644 index 00000000..4d306b0b --- /dev/null +++ b/api/storage.go @@ -0,0 +1,43 @@ +package api + +import ( + "fmt" + "syscall" + + "github.com/gin-gonic/gin" +) + +type diskFree struct { + // Storage size [MiB] + Total uint64 + // Available Storage [MiB] + Free uint64 + // Percentage Full + PercentFull float32 +} + +// @Summary Get Storage Utilization +// @Description **Get disk free information of aptly storage** +// @Tags Status +// @Produce json +// @Success 200 {object} diskFree "Storage information" +// @Failure 400 {object} Error "Internal Error" +// @Router /api/storage [get] +func apiDiskFree(c *gin.Context) { + var df diskFree + + fs := context.Config().GetRootDir() + + var stat syscall.Statfs_t + err := syscall.Statfs(fs, &stat) + if err != nil { + AbortWithJSONError(c, 400, fmt.Errorf("Error getting storage info on %s: %s", fs, err)) + return + } + + df.Total = uint64(stat.Blocks) * uint64(stat.Bsize) / 1048576 + df.Free = uint64(stat.Bavail) * uint64(stat.Bsize) / 1048576 + df.PercentFull = 100.0 - float32(stat.Bavail)/float32(stat.Blocks)*100.0 + + c.JSON(200, df) +} diff --git a/api/task.go b/api/task.go index 19cb0614..189d7931 100644 --- a/api/task.go +++ b/api/task.go @@ -1,7 +1,6 @@ package api import ( - "fmt" "net/http" "strconv" @@ -10,7 +9,12 @@ import ( "github.com/gin-gonic/gin" ) -// GET /tasks +// @Summary Get tasks +// @Description Get list of available tasks. Each task is returned as in “show” API. +// @Tags Tasks +// @Produce json +// @Success 200 {array} task.Task +// @Router /api/tasks [get] func apiTasksList(c *gin.Context) { list := context.TaskList() c.JSON(200, list.GetTasks()) @@ -35,13 +39,13 @@ func apiTasksWaitForTaskByID(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } task, err := list.WaitForTaskByID(int(id)) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -53,14 +57,14 @@ func apiTasksShow(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } var task task.Task task, err = list.GetTaskByID(int(id)) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -72,14 +76,14 @@ func apiTasksOutputShow(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } var output string output, err = list.GetTaskOutputByID(int(id)) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -91,14 +95,14 @@ func apiTasksDetailShow(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } var detail interface{} detail, err = list.GetTaskDetailByID(int(id)) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -110,13 +114,13 @@ func apiTasksReturnValueShow(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } output, err := list.GetTaskReturnValueByID(int(id)) if err != nil { - c.AbortWithError(404, err) + AbortWithJSONError(c, 404, err) return } @@ -128,14 +132,14 @@ func apiTasksDelete(c *gin.Context) { list := context.TaskList() id, err := strconv.ParseInt(c.Params.ByName("id"), 10, 0) if err != nil { - c.AbortWithError(500, err) + AbortWithJSONError(c, 500, err) return } var delTask task.Task delTask, err = list.DeleteTaskByID(int(id)) if err != nil { - c.AbortWithError(400, err) + AbortWithJSONError(c, 400, err) return } @@ -145,7 +149,7 @@ func apiTasksDelete(c *gin.Context) { // POST /tasks-dummy func apiTasksDummy(c *gin.Context) { resources := []string{"dummy"} - taskName := fmt.Sprintf("Dummy task") + taskName := "Dummy task" maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { out.Printf("Dummy task started\n") detail.Store([]int{1, 2, 3}) diff --git a/api/task_test.go b/api/task_test.go index 8cf05c34..59c981a0 100644 --- a/api/task_test.go +++ b/api/task_test.go @@ -71,5 +71,5 @@ func (s *TaskSuite) TestTasksClear(c *C) { c.Check(response.Code, Equals, 200) response, _ = s.HTTPRequest("GET", "/api/tasks", nil) c.Check(response.Code, Equals, 200) - c.Check(response.Body.String(), Equals, "null") + c.Check(response.Body.String(), Equals, "[]") } diff --git a/aptly-api.service b/aptly-api.service deleted file mode 100644 index 40fe7879..00000000 --- a/aptly-api.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=APT repository API -After=network.target -Documentation=man:aptly(1) -Documentation=https://www.aptly.info/doc/api/ - -[Service] -Type=simple -ExecStart=/usr/bin/aptly api serve -no-lock -listen=127.0.0.1:8081 - -[Install] -WantedBy=multi-user.target diff --git a/aptly.service b/aptly.service deleted file mode 100644 index a22e56ca..00000000 --- a/aptly.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=APT repository server -After=network.target -Documentation=man:aptly(1) -Documentation=https://www.aptly.info/doc/commands/ - -[Service] -Type=simple -ExecStart=/usr/bin/aptly serve -listen=127.0.0.1:8080 - -[Install] -WantedBy=multi-user.target diff --git a/aptly/const.go b/aptly/const.go new file mode 100644 index 00000000..9cca27ff --- /dev/null +++ b/aptly/const.go @@ -0,0 +1,3 @@ +package aptly + +var DistributionFocal = "focal" diff --git a/aptly/interfaces.go b/aptly/interfaces.go index e912daba..412daecd 100644 --- a/aptly/interfaces.go +++ b/aptly/interfaces.go @@ -35,8 +35,8 @@ type PackagePool interface { Import(srcPath, basename string, checksums *utils.ChecksumInfo, move bool, storage ChecksumStorage) (path string, err error) // LegacyPath returns legacy (pre 1.1) path to package file (relative to root) LegacyPath(filename string, checksums *utils.ChecksumInfo) (string, error) - // Stat returns Unix stat(2) info - Stat(path string) (os.FileInfo, error) + // Size returns the size of the given file in bytes. + Size(path string) (size int64, err error) // Open returns ReadSeekerCloser to access the file Open(path string) (ReadSeekerCloser, error) // FilepathList returns file paths of all the files in the pool @@ -47,6 +47,8 @@ type PackagePool interface { // LocalPackagePool is implemented by PackagePools residing on the same filesystem type LocalPackagePool interface { + // Stat returns Unix stat(2) info + Stat(path string) (os.FileInfo, error) // GenerateTempPath generates temporary path for download (which is fast to import into package pool later on) GenerateTempPath(filename string) (string, error) // Link generates hardlink to destination path @@ -70,7 +72,7 @@ type PublishedStorage interface { // Remove removes single file under public path Remove(path string) error // LinkFromPool links package file from pool to dist's pool location - LinkFromPool(publishedDirectory, fileName string, sourcePool PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error + LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error // Filelist returns list of files under prefix Filelist(prefix string) ([]string, error) // RenameFile renames (moves) file diff --git a/azure/azure.go b/azure/azure.go index 5f76b744..b313f904 100644 --- a/azure/azure.go +++ b/azure/azure.go @@ -1,2 +1,129 @@ -// Package azure handles publishing to Azure Storage package azure + +// Package azure handles publishing to Azure Storage + +import ( + "context" + "encoding/hex" + "fmt" + "io" + "net/url" + "path/filepath" + "time" + + "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/aptly-dev/aptly/aptly" +) + +func isBlobNotFound(err error) bool { + storageError, ok := err.(azblob.StorageError) + return ok && storageError.ServiceCode() == azblob.ServiceCodeBlobNotFound +} + +type azContext struct { + container azblob.ContainerURL + prefix string +} + +func newAzContext(accountName, accountKey, container, prefix, endpoint string) (*azContext, error) { + credential, err := azblob.NewSharedKeyCredential(accountName, accountKey) + if err != nil { + return nil, err + } + + if endpoint == "" { + endpoint = fmt.Sprintf("https://%s.blob.core.windows.net", accountName) + } + + url, err := url.Parse(fmt.Sprintf("%s/%s", endpoint, container)) + if err != nil { + return nil, err + } + + containerURL := azblob.NewContainerURL(*url, azblob.NewPipeline(credential, azblob.PipelineOptions{})) + + result := &azContext{ + container: containerURL, + prefix: prefix, + } + + return result, nil +} + +func (az *azContext) blobPath(path string) string { + return filepath.Join(az.prefix, path) +} + +func (az *azContext) blobURL(path string) azblob.BlobURL { + return az.container.NewBlobURL(az.blobPath(path)) +} + +func (az *azContext) internalFilelist(prefix string, progress aptly.Progress) (paths []string, md5s []string, err error) { + const delimiter = "/" + paths = make([]string, 0, 1024) + md5s = make([]string, 0, 1024) + prefix = filepath.Join(az.prefix, prefix) + if prefix != "" { + prefix += delimiter + } + + for marker := (azblob.Marker{}); marker.NotDone(); { + listBlob, err := az.container.ListBlobsFlatSegment( + context.Background(), marker, azblob.ListBlobsSegmentOptions{ + Prefix: prefix, + MaxResults: 1, + Details: azblob.BlobListingDetails{Metadata: true}}) + if err != nil { + return nil, nil, fmt.Errorf("error listing under prefix %s in %s: %s", prefix, az, err) + } + + marker = listBlob.NextMarker + + for _, blob := range listBlob.Segment.BlobItems { + if prefix == "" { + paths = append(paths, blob.Name) + } else { + paths = append(paths, blob.Name[len(prefix):]) + } + md5s = append(md5s, fmt.Sprintf("%x", blob.Properties.ContentMD5)) + } + + if progress != nil { + time.Sleep(time.Duration(500) * time.Millisecond) + progress.AddBar(1) + } + } + + return paths, md5s, nil +} + +func (az *azContext) putFile(blob azblob.BlobURL, source io.Reader, sourceMD5 string) error { + uploadOptions := azblob.UploadStreamToBlockBlobOptions{ + BufferSize: 4 * 1024 * 1024, + MaxBuffers: 8, + } + + if len(sourceMD5) > 0 { + decodedMD5, err := hex.DecodeString(sourceMD5) + if err != nil { + return err + } + uploadOptions.BlobHTTPHeaders = azblob.BlobHTTPHeaders{ + ContentMD5: decodedMD5, + } + } + + _, err := azblob.UploadStreamToBlockBlob( + context.Background(), + source, + blob.ToBlockBlobURL(), + uploadOptions, + ) + + return err +} + +// String +func (az *azContext) String() string { + return fmt.Sprintf("Azure: %s/%s", az.container, az.prefix) +} diff --git a/azure/package_pool.go b/azure/package_pool.go new file mode 100644 index 00000000..167ab6be --- /dev/null +++ b/azure/package_pool.go @@ -0,0 +1,218 @@ +package azure + +import ( + "context" + "os" + "path/filepath" + + "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/aptly-dev/aptly/aptly" + "github.com/aptly-dev/aptly/utils" + "github.com/pkg/errors" +) + +type PackagePool struct { + az *azContext +} + +// Check interface +var ( + _ aptly.PackagePool = (*PackagePool)(nil) +) + +// NewPackagePool creates published storage from Azure storage credentials +func NewPackagePool(accountName, accountKey, container, prefix, endpoint string) (*PackagePool, error) { + azctx, err := newAzContext(accountName, accountKey, container, prefix, endpoint) + if err != nil { + return nil, err + } + + return &PackagePool{az: azctx}, nil +} + +// String +func (pool *PackagePool) String() string { + return pool.az.String() +} + +func (pool *PackagePool) buildPoolPath(filename string, checksums *utils.ChecksumInfo) string { + hash := checksums.SHA256 + // Use the same path as the file pool, for compat reasons. + return filepath.Join(hash[0:2], hash[2:4], hash[4:32]+"_"+filename) +} + +func (pool *PackagePool) ensureChecksums( + poolPath string, + checksumStorage aptly.ChecksumStorage, +) (*utils.ChecksumInfo, error) { + targetChecksums, err := checksumStorage.Get(poolPath) + if err != nil { + return nil, err + } + + if targetChecksums == nil { + // we don't have checksums stored yet for this file + blob := pool.az.blobURL(poolPath) + download, err := blob.Download(context.Background(), 0, 0, azblob.BlobAccessConditions{}, false, azblob.ClientProvidedKeyOptions{}) + if err != nil { + if isBlobNotFound(err) { + return nil, nil + } + + return nil, errors.Wrapf(err, "error downloading blob at %s", poolPath) + } + + targetChecksums = &utils.ChecksumInfo{} + *targetChecksums, err = utils.ChecksumsForReader(download.Body(azblob.RetryReaderOptions{})) + if err != nil { + return nil, errors.Wrapf(err, "error checksumming blob at %s", poolPath) + } + + err = checksumStorage.Update(poolPath, targetChecksums) + if err != nil { + return nil, err + } + } + + return targetChecksums, nil +} + +func (pool *PackagePool) FilepathList(progress aptly.Progress) ([]string, error) { + if progress != nil { + progress.InitBar(0, false, aptly.BarGeneralBuildFileList) + defer progress.ShutdownBar() + } + + paths, _, err := pool.az.internalFilelist("", progress) + return paths, err +} + +func (pool *PackagePool) LegacyPath(_ string, _ *utils.ChecksumInfo) (string, error) { + return "", errors.New("Azure package pool does not support legacy paths") +} + +func (pool *PackagePool) Size(path string) (int64, error) { + blob := pool.az.blobURL(path) + props, err := blob.GetProperties(context.Background(), azblob.BlobAccessConditions{}, azblob.ClientProvidedKeyOptions{}) + if err != nil { + return 0, errors.Wrapf(err, "error examining %s from %s", path, pool) + } + + return props.ContentLength(), nil +} + +func (pool *PackagePool) Open(path string) (aptly.ReadSeekerCloser, error) { + blob := pool.az.blobURL(path) + + temp, err := os.CreateTemp("", "blob-download") + if err != nil { + return nil, errors.Wrap(err, "error creating temporary file for blob download") + } + + defer os.Remove(temp.Name()) + + err = azblob.DownloadBlobToFile(context.Background(), blob, 0, 0, temp, azblob.DownloadFromBlobOptions{}) + if err != nil { + return nil, errors.Wrapf(err, "error downloading blob at %s", path) + } + + return temp, nil +} + +func (pool *PackagePool) Remove(path string) (int64, error) { + blob := pool.az.blobURL(path) + props, err := blob.GetProperties(context.Background(), azblob.BlobAccessConditions{}, azblob.ClientProvidedKeyOptions{}) + if err != nil { + return 0, errors.Wrapf(err, "error getting props of %s from %s", path, pool) + } + + _, err = blob.Delete(context.Background(), azblob.DeleteSnapshotsOptionNone, azblob.BlobAccessConditions{}) + if err != nil { + return 0, errors.Wrapf(err, "error deleting %s from %s", path, pool) + } + + return props.ContentLength(), nil +} + +func (pool *PackagePool) Import(srcPath, basename string, checksums *utils.ChecksumInfo, _ bool, checksumStorage aptly.ChecksumStorage) (string, error) { + if checksums.MD5 == "" || checksums.SHA256 == "" || checksums.SHA512 == "" { + // need to update checksums, MD5 and SHA256 should be always defined + var err error + *checksums, err = utils.ChecksumsForFile(srcPath) + if err != nil { + return "", err + } + } + + path := pool.buildPoolPath(basename, checksums) + blob := pool.az.blobURL(path) + targetChecksums, err := pool.ensureChecksums(path, checksumStorage) + if err != nil { + return "", err + } else if targetChecksums != nil { + // target already exists + *checksums = *targetChecksums + return path, nil + } + + source, err := os.Open(srcPath) + if err != nil { + return "", err + } + defer source.Close() + + err = pool.az.putFile(blob, source, checksums.MD5) + if err != nil { + return "", err + } + + if !checksums.Complete() { + // need full checksums here + *checksums, err = utils.ChecksumsForFile(srcPath) + if err != nil { + return "", err + } + } + + err = checksumStorage.Update(path, checksums) + if err != nil { + return "", err + } + + return path, nil +} + +func (pool *PackagePool) Verify(poolPath, basename string, checksums *utils.ChecksumInfo, checksumStorage aptly.ChecksumStorage) (string, bool, error) { + if poolPath == "" { + if checksums.SHA256 != "" { + poolPath = pool.buildPoolPath(basename, checksums) + } else { + // No checksums or pool path, so no idea what file to look for. + return "", false, nil + } + } + + size, err := pool.Size(poolPath) + if err != nil { + return "", false, err + } else if size != checksums.Size { + return "", false, nil + } + + targetChecksums, err := pool.ensureChecksums(poolPath, checksumStorage) + if err != nil { + return "", false, err + } else if targetChecksums == nil { + return "", false, nil + } + + if checksums.MD5 != "" && targetChecksums.MD5 != checksums.MD5 || + checksums.SHA256 != "" && targetChecksums.SHA256 != checksums.SHA256 { + // wrong file? + return "", false, nil + } + + // fill back checksums + *checksums = *targetChecksums + return poolPath, true, nil +} diff --git a/azure/package_pool_test.go b/azure/package_pool_test.go new file mode 100644 index 00000000..58949ec6 --- /dev/null +++ b/azure/package_pool_test.go @@ -0,0 +1,255 @@ +package azure + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "runtime" + + "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/aptly-dev/aptly/aptly" + "github.com/aptly-dev/aptly/files" + "github.com/aptly-dev/aptly/utils" + + . "gopkg.in/check.v1" +) + +type PackagePoolSuite struct { + accountName, accountKey, endpoint string + pool, prefixedPool *PackagePool + debFile string + cs aptly.ChecksumStorage +} + +var _ = Suite(&PackagePoolSuite{}) + +func (s *PackagePoolSuite) SetUpSuite(c *C) { + s.accountName = os.Getenv("AZURE_STORAGE_ACCOUNT") + if s.accountName == "" { + println("Please set the the following two environment variables to run the Azure storage tests.") + println(" 1. AZURE_STORAGE_ACCOUNT") + println(" 2. AZURE_STORAGE_ACCESS_KEY") + c.Skip("AZURE_STORAGE_ACCOUNT not set.") + } + s.accountKey = os.Getenv("AZURE_STORAGE_ACCESS_KEY") + if s.accountKey == "" { + println("Please set the the following two environment variables to run the Azure storage tests.") + println(" 1. AZURE_STORAGE_ACCOUNT") + println(" 2. AZURE_STORAGE_ACCESS_KEY") + c.Skip("AZURE_STORAGE_ACCESS_KEY not set.") + } + s.endpoint = os.Getenv("AZURE_STORAGE_ENDPOINT") +} + +func (s *PackagePoolSuite) SetUpTest(c *C) { + container := randContainer() + prefix := "lala" + + var err error + + s.pool, err = NewPackagePool(s.accountName, s.accountKey, container, "", s.endpoint) + c.Assert(err, IsNil) + cnt := s.pool.az.container + _, err = cnt.Create(context.Background(), azblob.Metadata{}, azblob.PublicAccessContainer) + c.Assert(err, IsNil) + + s.prefixedPool, err = NewPackagePool(s.accountName, s.accountKey, container, prefix, s.endpoint) + c.Assert(err, IsNil) + + _, _File, _, _ := runtime.Caller(0) + s.debFile = filepath.Join(filepath.Dir(_File), "../system/files/libboost-program-options-dev_1.49.0.1_i386.deb") + s.cs = files.NewMockChecksumStorage() +} + +func (s *PackagePoolSuite) TestFilepathList(c *C) { + list, err := s.pool.FilepathList(nil) + c.Check(err, IsNil) + c.Check(list, DeepEquals, []string{}) + + s.pool.Import(s.debFile, "a.deb", &utils.ChecksumInfo{}, false, s.cs) + s.pool.Import(s.debFile, "b.deb", &utils.ChecksumInfo{}, false, s.cs) + + list, err = s.pool.FilepathList(nil) + c.Check(err, IsNil) + c.Check(list, DeepEquals, []string{ + "c7/6b/4bd12fd92e4dfe1b55b18a67a669_a.deb", + "c7/6b/4bd12fd92e4dfe1b55b18a67a669_b.deb", + }) +} + +func (s *PackagePoolSuite) TestRemove(c *C) { + s.pool.Import(s.debFile, "a.deb", &utils.ChecksumInfo{}, false, s.cs) + s.pool.Import(s.debFile, "b.deb", &utils.ChecksumInfo{}, false, s.cs) + + size, err := s.pool.Remove("c7/6b/4bd12fd92e4dfe1b55b18a67a669_a.deb") + c.Check(err, IsNil) + c.Check(size, Equals, int64(2738)) + + _, err = s.pool.Remove("c7/6b/4bd12fd92e4dfe1b55b18a67a669_a.deb") + c.Check(err, ErrorMatches, "(.|\n)*BlobNotFound(.|\n)*") + + list, err := s.pool.FilepathList(nil) + c.Check(err, IsNil) + c.Check(list, DeepEquals, []string{"c7/6b/4bd12fd92e4dfe1b55b18a67a669_b.deb"}) +} + +func (s *PackagePoolSuite) TestImportOk(c *C) { + var checksum utils.ChecksumInfo + path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_libboost-program-options-dev_1.49.0.1_i386.deb") + // SHA256 should be automatically calculated + c.Check(checksum.SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") + // checksum storage is filled with new checksum + c.Check(s.cs.(*files.MockChecksumStorage).Store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") + + size, err := s.pool.Size(path) + c.Assert(err, IsNil) + c.Check(size, Equals, int64(2738)) + + // import as different name + checksum = utils.ChecksumInfo{} + path, err = s.pool.Import(s.debFile, "some.deb", &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_some.deb") + // checksum storage is filled with new checksum + c.Check(s.cs.(*files.MockChecksumStorage).Store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") + + // double import, should be ok + checksum = utils.ChecksumInfo{} + path, err = s.pool.Import(s.debFile, filepath.Base(s.debFile), &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_libboost-program-options-dev_1.49.0.1_i386.deb") + // checksum is filled back based on checksum storage + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // clear checksum storage, and do double-import + delete(s.cs.(*files.MockChecksumStorage).Store, path) + checksum = utils.ChecksumInfo{} + path, err = s.pool.Import(s.debFile, filepath.Base(s.debFile), &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_libboost-program-options-dev_1.49.0.1_i386.deb") + // checksum is filled back based on re-calculation of file in the pool + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // import under new name, but with path-relevant checksums already filled in + checksum = utils.ChecksumInfo{SHA256: checksum.SHA256} + path, err = s.pool.Import(s.debFile, "other.deb", &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_other.deb") + // checksum is filled back based on re-calculation of source file + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") +} + +func (s *PackagePoolSuite) TestVerify(c *C) { + // file doesn't exist yet + ppath, exists, err := s.pool.Verify("", filepath.Base(s.debFile), &utils.ChecksumInfo{}, s.cs) + c.Check(ppath, Equals, "") + c.Check(err, IsNil) + c.Check(exists, Equals, false) + + // import file + checksum := utils.ChecksumInfo{} + path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &checksum, false, s.cs) + c.Check(err, IsNil) + c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_libboost-program-options-dev_1.49.0.1_i386.deb") + + // check existence + ppath, exists, err = s.pool.Verify("", filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, ppath) + c.Check(err, IsNil) + c.Check(exists, Equals, true) + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // check existence with fixed path + checksum = utils.ChecksumInfo{Size: checksum.Size} + ppath, exists, err = s.pool.Verify(path, filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, path) + c.Check(err, IsNil) + c.Check(exists, Equals, true) + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // check existence, but with checksums missing (that aren't needed to find the path) + checksum.SHA512 = "" + ppath, exists, err = s.pool.Verify("", filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, path) + c.Check(err, IsNil) + c.Check(exists, Equals, true) + // checksum is filled back based on checksum storage + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // check existence, with missing checksum info but correct path and size available + checksum = utils.ChecksumInfo{Size: checksum.Size} + ppath, exists, err = s.pool.Verify(path, filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, path) + c.Check(err, IsNil) + c.Check(exists, Equals, true) + // checksum is filled back based on checksum storage + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // check existence, with wrong checksum info but correct path and size available + ppath, exists, err = s.pool.Verify(path, filepath.Base(s.debFile), &utils.ChecksumInfo{ + SHA256: "abc", + Size: checksum.Size, + }, s.cs) + c.Check(ppath, Equals, "") + c.Check(err, IsNil) + c.Check(exists, Equals, false) + + // check existence, with missing checksums (that aren't needed to find the path) + // and no info in checksum storage + delete(s.cs.(*files.MockChecksumStorage).Store, path) + checksum.SHA512 = "" + ppath, exists, err = s.pool.Verify("", filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, path) + c.Check(err, IsNil) + c.Check(exists, Equals, true) + // checksum is filled back based on re-calculation + c.Check(checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") + + // check existence, with wrong size + checksum = utils.ChecksumInfo{Size: 13455} + ppath, exists, err = s.pool.Verify(path, filepath.Base(s.debFile), &checksum, s.cs) + c.Check(ppath, Equals, "") + c.Check(err, IsNil) + c.Check(exists, Equals, false) + + // check existence, with empty checksum info + ppath, exists, err = s.pool.Verify("", filepath.Base(s.debFile), &utils.ChecksumInfo{}, s.cs) + c.Check(ppath, Equals, "") + c.Check(err, IsNil) + c.Check(exists, Equals, false) +} + +func (s *PackagePoolSuite) TestImportNotExist(c *C) { + _, err := s.pool.Import("no-such-file", "a.deb", &utils.ChecksumInfo{}, false, s.cs) + c.Check(err, ErrorMatches, ".*no such file or directory") +} + +func (s *PackagePoolSuite) TestSize(c *C) { + path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &utils.ChecksumInfo{}, false, s.cs) + c.Check(err, IsNil) + + size, err := s.pool.Size(path) + c.Assert(err, IsNil) + c.Check(size, Equals, int64(2738)) + + _, err = s.pool.Size("do/es/ntexist") + c.Check(err, ErrorMatches, "(.|\n)*BlobNotFound(.|\n)*") +} + +func (s *PackagePoolSuite) TestOpen(c *C) { + path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &utils.ChecksumInfo{}, false, s.cs) + c.Check(err, IsNil) + + f, err := s.pool.Open(path) + c.Assert(err, IsNil) + contents, err := ioutil.ReadAll(f) + c.Assert(err, IsNil) + c.Check(len(contents), Equals, 2738) + c.Check(f.Close(), IsNil) + + _, err = s.pool.Open("do/es/ntexist") + c.Check(err, ErrorMatches, "(.|\n)*BlobNotFound(.|\n)*") +} diff --git a/azure/public.go b/azure/public.go index cf1a7b20..50a82029 100644 --- a/azure/public.go +++ b/azure/public.go @@ -2,12 +2,8 @@ package azure import ( "context" - "encoding/hex" "fmt" - "io" - "net" "net/http" - "net/url" "os" "path/filepath" "time" @@ -22,7 +18,8 @@ import ( type PublishedStorage struct { container azblob.ContainerURL prefix string - pathCache map[string]string + az *azContext + pathCache map[string]map[string]string } // Check interface @@ -30,60 +27,23 @@ var ( _ aptly.PublishedStorage = (*PublishedStorage)(nil) ) -func isEmulatorEndpoint(endpoint string) bool { - if h, _, err := net.SplitHostPort(endpoint); err == nil { - endpoint = h - } - if endpoint == "localhost" { - return true - } - // For IPv6, there could be case where SplitHostPort fails for cannot finding port. - // In this case, eliminate the '[' and ']' in the URL. - // For details about IPv6 URL, please refer to https://tools.ietf.org/html/rfc2732 - if endpoint[0] == '[' && endpoint[len(endpoint)-1] == ']' { - endpoint = endpoint[1 : len(endpoint)-1] - } - return net.ParseIP(endpoint) != nil -} - // NewPublishedStorage creates published storage from Azure storage credentials func NewPublishedStorage(accountName, accountKey, container, prefix, endpoint string) (*PublishedStorage, error) { - credential, err := azblob.NewSharedKeyCredential(accountName, accountKey) + azctx, err := newAzContext(accountName, accountKey, container, prefix, endpoint) if err != nil { return nil, err } - if endpoint == "" { - endpoint = "blob.core.windows.net" - } - - var url *url.URL - if isEmulatorEndpoint(endpoint) { - url, err = url.Parse(fmt.Sprintf("http://%s/%s/%s", endpoint, accountName, container)) - } else { - url, err = url.Parse(fmt.Sprintf("https://%s.%s/%s", accountName, endpoint, container)) - } - if err != nil { - return nil, err - } - - containerURL := azblob.NewContainerURL(*url, azblob.NewPipeline(credential, azblob.PipelineOptions{})) - - result := &PublishedStorage{ - container: containerURL, - prefix: prefix, - } - - return result, nil + return &PublishedStorage{az: azctx}, nil } // String func (storage *PublishedStorage) String() string { - return fmt.Sprintf("Azure: %s/%s", storage.container, storage.prefix) + return storage.az.String() } // MkDir creates directory recursively under public path -func (storage *PublishedStorage) MkDir(path string) error { +func (storage *PublishedStorage) MkDir(_ string) error { // no op for Azure return nil } @@ -106,7 +66,7 @@ func (storage *PublishedStorage) PutFile(path string, sourceFilename string) err } defer source.Close() - err = storage.putFile(path, source, sourceMD5) + err = storage.az.putFile(storage.az.blobURL(path), source, sourceMD5) if err != nil { err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s", sourceFilename, storage)) } @@ -114,45 +74,15 @@ func (storage *PublishedStorage) PutFile(path string, sourceFilename string) err return err } -// putFile uploads file-like object to -func (storage *PublishedStorage) putFile(path string, source io.Reader, sourceMD5 string) error { - path = filepath.Join(storage.prefix, path) - - blob := storage.container.NewBlockBlobURL(path) - - uploadOptions := azblob.UploadStreamToBlockBlobOptions{ - BufferSize: 4 * 1024 * 1024, - MaxBuffers: 8, - } - if len(sourceMD5) > 0 { - decodedMD5, err := hex.DecodeString(sourceMD5) - if err != nil { - return err - } - uploadOptions.BlobHTTPHeaders = azblob.BlobHTTPHeaders{ - ContentMD5: decodedMD5, - } - } - - _, err := azblob.UploadStreamToBlockBlob( - context.Background(), - source, - blob, - uploadOptions, - ) - - return err -} - // RemoveDirs removes directory structure under public path -func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error { +func (storage *PublishedStorage) RemoveDirs(path string, _ aptly.Progress) error { filelist, err := storage.Filelist(path) if err != nil { return err } for _, filename := range filelist { - blob := storage.container.NewBlobURL(filepath.Join(storage.prefix, path, filename)) + blob := storage.az.blobURL(filepath.Join(path, filename)) _, err := blob.Delete(context.Background(), azblob.DeleteSnapshotsOptionNone, azblob.BlobAccessConditions{}) if err != nil { return fmt.Errorf("error deleting path %s from %s: %s", filename, storage, err) @@ -164,7 +94,7 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress // Remove removes single file under public path func (storage *PublishedStorage) Remove(path string) error { - blob := storage.container.NewBlobURL(filepath.Join(storage.prefix, path)) + blob := storage.az.blobURL(path) _, err := blob.Delete(context.Background(), azblob.DeleteSnapshotsOptionNone, azblob.BlobAccessConditions{}) if err != nil { err = errors.Wrap(err, fmt.Sprintf("error deleting %s from %s: %s", path, storage, err)) @@ -174,31 +104,39 @@ func (storage *PublishedStorage) Remove(path string) error { // LinkFromPool links package file from pool to dist's pool location // -// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/) +// publishedPrefix is desired prefix for the location in the pool. +// publishedRelPath is desired location in pool (like pool/component/liba/libav/) // sourcePool is instance of aptly.PackagePool // sourcePath is filepath to package file in package pool // // LinkFromPool returns relative path for the published file to be included in package index -func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName string, sourcePool aptly.PackagePool, +func (storage *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error { - relPath := filepath.Join(publishedDirectory, fileName) - poolPath := filepath.Join(storage.prefix, relPath) + relFilePath := filepath.Join(publishedRelPath, fileName) + // prefixRelFilePath := filepath.Join(publishedPrefix, relFilePath) + // FIXME: check how to integrate publishedPrefix: + poolPath := storage.az.blobPath(fileName) if storage.pathCache == nil { - paths, md5s, err := storage.internalFilelist("") + storage.pathCache = make(map[string]map[string]string) + } + pathCache := storage.pathCache[publishedPrefix] + if pathCache == nil { + paths, md5s, err := storage.az.internalFilelist(publishedPrefix, nil) if err != nil { return fmt.Errorf("error caching paths under prefix: %s", err) } - storage.pathCache = make(map[string]string, len(paths)) + pathCache = make(map[string]string, len(paths)) for i := range paths { - storage.pathCache[paths[i]] = md5s[i] + pathCache[paths[i]] = md5s[i] } + storage.pathCache[publishedPrefix] = pathCache } - destinationMD5, exists := storage.pathCache[relPath] + destinationMD5, exists := pathCache[relFilePath] sourceMD5 := sourceChecksums.MD5 if exists { @@ -221,9 +159,9 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin } defer source.Close() - err = storage.putFile(relPath, source, sourceMD5) + err = storage.az.putFile(storage.az.blobURL(relFilePath), source, sourceMD5) if err == nil { - storage.pathCache[relPath] = sourceMD5 + pathCache[relFilePath] = sourceMD5 } else { err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s: %s", sourcePath, storage, poolPath)) } @@ -231,43 +169,9 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin return err } -func (storage *PublishedStorage) internalFilelist(prefix string) (paths []string, md5s []string, err error) { - const delimiter = "/" - paths = make([]string, 0, 1024) - md5s = make([]string, 0, 1024) - prefix = filepath.Join(storage.prefix, prefix) - if prefix != "" { - prefix += delimiter - } - - for marker := (azblob.Marker{}); marker.NotDone(); { - listBlob, err := storage.container.ListBlobsFlatSegment( - context.Background(), marker, azblob.ListBlobsSegmentOptions{ - Prefix: prefix, - MaxResults: 1000, - Details: azblob.BlobListingDetails{Metadata: true}}) - if err != nil { - return nil, nil, fmt.Errorf("error listing under prefix %s in %s: %s", prefix, storage, err) - } - - marker = listBlob.NextMarker - - for _, blob := range listBlob.Segment.BlobItems { - if prefix == "" { - paths = append(paths, blob.Name) - } else { - paths = append(paths, blob.Name[len(prefix):]) - } - md5s = append(md5s, fmt.Sprintf("%x", blob.Properties.ContentMD5)) - } - } - - return paths, md5s, nil -} - // Filelist returns list of files under prefix func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) { - paths, _, err := storage.internalFilelist(prefix) + paths, _, err := storage.az.internalFilelist(prefix, nil) return paths, err } @@ -275,8 +179,8 @@ func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) { func (storage *PublishedStorage) internalCopyOrMoveBlob(src, dst string, metadata azblob.Metadata, move bool) error { const leaseDuration = 30 - dstBlobURL := storage.container.NewBlobURL(filepath.Join(storage.prefix, dst)) - srcBlobURL := storage.container.NewBlobURL(filepath.Join(storage.prefix, src)) + dstBlobURL := storage.az.blobURL(dst) + srcBlobURL := storage.az.blobURL(src) leaseResp, err := srcBlobURL.AcquireLease(context.Background(), "", leaseDuration, azblob.ModifiedAccessConditions{}) if err != nil || leaseResp.StatusCode() != http.StatusCreated { return fmt.Errorf("error acquiring lease on source blob %s", srcBlobURL) @@ -347,11 +251,10 @@ func (storage *PublishedStorage) HardLink(src string, dst string) error { // FileExists returns true if path exists func (storage *PublishedStorage) FileExists(path string) (bool, error) { - blob := storage.container.NewBlobURL(filepath.Join(storage.prefix, path)) + blob := storage.az.blobURL(path) resp, err := blob.GetProperties(context.Background(), azblob.BlobAccessConditions{}, azblob.ClientProvidedKeyOptions{}) if err != nil { - storageError, ok := err.(azblob.StorageError) - if ok && string(storageError.ServiceCode()) == string(azblob.StorageErrorCodeBlobNotFound) { + if isBlobNotFound(err) { return false, nil } return false, err @@ -364,7 +267,7 @@ func (storage *PublishedStorage) FileExists(path string) (bool, error) { // ReadLink returns the symbolic link pointed to by path. // This simply reads text file created with SymLink func (storage *PublishedStorage) ReadLink(path string) (string, error) { - blob := storage.container.NewBlobURL(filepath.Join(storage.prefix, path)) + blob := storage.az.blobURL(path) resp, err := blob.GetProperties(context.Background(), azblob.BlobAccessConditions{}, azblob.ClientProvidedKeyOptions{}) if err != nil { return "", err diff --git a/azure/public_test.go b/azure/public_test.go index 79abfed2..767f2495 100644 --- a/azure/public_test.go +++ b/azure/public_test.go @@ -43,14 +43,14 @@ func randString(n int) string { func (s *PublishedStorageSuite) SetUpSuite(c *C) { s.accountName = os.Getenv("AZURE_STORAGE_ACCOUNT") if s.accountName == "" { - println("Please set the the following two environment variables to run the Azure storage tests.") + println("Please set the following two environment variables to run the Azure storage tests.") println(" 1. AZURE_STORAGE_ACCOUNT") println(" 2. AZURE_STORAGE_ACCESS_KEY") c.Skip("AZURE_STORAGE_ACCOUNT not set.") } s.accountKey = os.Getenv("AZURE_STORAGE_ACCESS_KEY") if s.accountKey == "" { - println("Please set the the following two environment variables to run the Azure storage tests.") + println("Please set the following two environment variables to run the Azure storage tests.") println(" 1. AZURE_STORAGE_ACCOUNT") println(" 2. AZURE_STORAGE_ACCESS_KEY") c.Skip("AZURE_STORAGE_ACCESS_KEY not set.") @@ -66,7 +66,7 @@ func (s *PublishedStorageSuite) SetUpTest(c *C) { s.storage, err = NewPublishedStorage(s.accountName, s.accountKey, container, "", s.endpoint) c.Assert(err, IsNil) - cnt := s.storage.container + cnt := s.storage.az.container _, err = cnt.Create(context.Background(), azblob.Metadata{}, azblob.PublicAccessContainer) c.Assert(err, IsNil) @@ -75,13 +75,13 @@ func (s *PublishedStorageSuite) SetUpTest(c *C) { } func (s *PublishedStorageSuite) TearDownTest(c *C) { - cnt := s.storage.container + cnt := s.storage.az.container _, err := cnt.Delete(context.Background(), azblob.ContainerAccessConditions{}) c.Assert(err, IsNil) } func (s *PublishedStorageSuite) GetFile(c *C, path string) []byte { - blob := s.storage.container.NewBlobURL(path) + blob := s.storage.az.container.NewBlobURL(path) resp, err := blob.Download(context.Background(), 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false, azblob.ClientProvidedKeyOptions{}) c.Assert(err, IsNil) body := resp.Body(azblob.RetryReaderOptions{MaxRetryRequests: 3}) @@ -91,7 +91,7 @@ func (s *PublishedStorageSuite) GetFile(c *C, path string) []byte { } func (s *PublishedStorageSuite) AssertNoFile(c *C, path string) { - _, err := s.storage.container.NewBlobURL(path).GetProperties( + _, err := s.storage.az.container.NewBlobURL(path).GetProperties( context.Background(), azblob.BlobAccessConditions{}, azblob.ClientProvidedKeyOptions{}) c.Assert(err, NotNil) storageError, ok := err.(azblob.StorageError) @@ -104,7 +104,7 @@ func (s *PublishedStorageSuite) PutFile(c *C, path string, data []byte) { _, err := azblob.UploadBufferToBlockBlob( context.Background(), data, - s.storage.container.NewBlockBlobURL(path), + s.storage.az.container.NewBlockBlobURL(path), azblob.UploadToBlockBlobOptions{ BlobHTTPHeaders: azblob.BlobHTTPHeaders{ ContentMD5: hash[:], @@ -129,7 +129,7 @@ func (s *PublishedStorageSuite) TestPutFile(c *C) { err = s.prefixedStorage.PutFile(filename, filepath.Join(dir, "a")) c.Check(err, IsNil) - c.Check(s.GetFile(c, filepath.Join(s.prefixedStorage.prefix, filename)), DeepEquals, content) + c.Check(s.GetFile(c, filepath.Join(s.prefixedStorage.az.prefix, filename)), DeepEquals, content) } func (s *PublishedStorageSuite) TestPutFilePlus(c *C) { @@ -300,45 +300,45 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Assert(err, IsNil) // first link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // duplicate link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with conflict - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) c.Check(err, ErrorMatches, ".*file already exists and is different.*") c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with conflict and force - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Spam")) // for prefixed storage: // first link from pool - err = s.prefixedStorage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) // 2nd link from pool, providing wrong path for source file // // this test should check that file already exists in S3 and skip upload (which would fail if not skipped) s.prefixedStorage.pathCache = nil - err = s.prefixedStorage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, "wrong-looks-like-pathcache-doesnt-work", cksum1, false) + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, "wrong-looks-like-pathcache-doesnt-work", cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "lala/pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with nested file name - err = s.storage.LinkFromPool("dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) + err = s.storage.LinkFromPool("", "dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "dists/jessie/non-free/installer-i386/current/images/netboot/boot.img.gz"), DeepEquals, []byte("Contents")) diff --git a/cmd/api_serve.go b/cmd/api_serve.go index 7c19d2ef..22af04a8 100644 --- a/cmd/api_serve.go +++ b/cmd/api_serve.go @@ -1,11 +1,15 @@ package cmd import ( + stdcontext "context" + "errors" "fmt" "net" "net/http" "net/url" "os" + "os/signal" + "syscall" "github.com/aptly-dev/aptly/api" "github.com/aptly-dev/aptly/systemd/activation" @@ -30,7 +34,7 @@ func aptlyAPIServe(cmd *commander.Command, args []string) error { // anything else must fail. // E.g.: Running the service under a different user may lead to a rootDir // that exists but is not usable due to access permissions. - err = utils.DirIsAccessible(context.Config().RootDir) + err = utils.DirIsAccessible(context.Config().GetRootDir()) if err != nil { return err } @@ -55,6 +59,17 @@ func aptlyAPIServe(cmd *commander.Command, args []string) error { listen := context.Flags().Lookup("listen").Value.String() fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen) + server := http.Server{Handler: api.Router(context)} + + sigchan := make(chan os.Signal, 1) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + go (func() { + if _, ok := <-sigchan; ok { + server.Shutdown(stdcontext.Background()) + } + })() + defer close(sigchan) + listenURL, err := url.Parse(listen) if err == nil && listenURL.Scheme == "unix" { file := listenURL.Path @@ -67,19 +82,17 @@ func aptlyAPIServe(cmd *commander.Command, args []string) error { } defer listener.Close() - err = http.Serve(listener, api.Router(context)) - if err != nil { - return fmt.Errorf("unable to serve: %s", err) - } - return nil + err = server.Serve(listener) + } else { + server.Addr = listen + err = server.ListenAndServe() } - err = http.ListenAndServe(listen, api.Router(context)) - if err != nil { + if err != nil && !errors.Is(err, http.ErrServerClosed) { return fmt.Errorf("unable to serve: %s", err) } - return err + return nil } func makeCmdAPIServe() *commander.Command { diff --git a/cmd/cmd.go b/cmd/cmd.go index 14a0efd1..d5bdff25 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -118,7 +118,7 @@ package environment to new version.`, cmd.Flag.Bool("dep-follow-all-variants", false, "when processing dependencies, follow a & b if dependency is 'a|b'") cmd.Flag.Bool("dep-verbose-resolve", false, "when processing dependencies, print detailed logs") cmd.Flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available") - cmd.Flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)") + cmd.Flag.String("config", "", "location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf)") cmd.Flag.String("gpg-provider", "", "PGP implementation (\"gpg\", \"gpg1\", \"gpg2\" for external gpg or \"internal\" for Go internal implementation)") if aptly.EnableDebug { diff --git a/cmd/config_show.go b/cmd/config_show.go index 119fd37f..66adc8f0 100644 --- a/cmd/config_show.go +++ b/cmd/config_show.go @@ -7,7 +7,7 @@ import ( "github.com/smira/commander" ) -func aptlyConfigShow(cmd *commander.Command, args []string) error { +func aptlyConfigShow(_ *commander.Command, _ []string) error { config := context.Config() prettyJSON, err := json.MarshalIndent(config, "", " ") diff --git a/cmd/graph.go b/cmd/graph.go index 868e5874..4425d087 100644 --- a/cmd/graph.go +++ b/cmd/graph.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -36,7 +35,7 @@ func aptlyGraph(cmd *commander.Command, args []string) error { buf := bytes.NewBufferString(graph.String()) - tempfile, err := ioutil.TempFile("", "aptly-graph") + tempfile, err := os.CreateTemp("", "aptly-graph") if err != nil { return err } diff --git a/cmd/mirror.go b/cmd/mirror.go index 8681173e..89b19a6c 100644 --- a/cmd/mirror.go +++ b/cmd/mirror.go @@ -9,18 +9,18 @@ import ( ) func getVerifier(flags *flag.FlagSet) (pgp.Verifier, error) { - if LookupOption(context.Config().GpgDisableVerify, flags, "ignore-signatures") { - return nil, nil - } - keyRings := flags.Lookup("keyring").Value.Get().([]string) + ignoreSignatures := context.Config().GpgDisableVerify + if context.Flags().IsSet("ignore-signatures") { + ignoreSignatures = context.Flags().Lookup("ignore-signatures").Value.Get().(bool) + } verifier := context.GetVerifier() for _, keyRing := range keyRings { verifier.AddKeyring(keyRing) } - err := verifier.InitKeyring() + err := verifier.InitKeyring(ignoreSignatures == false) // be verbose only if verifying signatures is requested if err != nil { return nil, err } diff --git a/cmd/mirror_create.go b/cmd/mirror_create.go index 78d91b58..022a5cf2 100644 --- a/cmd/mirror_create.go +++ b/cmd/mirror_create.go @@ -20,6 +20,10 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error { downloadSources := LookupOption(context.Config().DownloadSourcePackages, context.Flags(), "with-sources") downloadUdebs := context.Flags().Lookup("with-udebs").Value.Get().(bool) downloadInstaller := context.Flags().Lookup("with-installer").Value.Get().(bool) + ignoreSignatures := context.Config().GpgDisableVerify + if context.Flags().IsSet("ignore-signatures") { + ignoreSignatures = context.Flags().Lookup("ignore-signatures").Value.Get().(bool) + } var ( mirrorName, archiveURL, distribution string @@ -59,7 +63,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to initialize GPG verifier: %s", err) } - err = repo.Fetch(context.Downloader(), verifier) + err = repo.Fetch(context.Downloader(), verifier, ignoreSignatures) if err != nil { return fmt.Errorf("unable to fetch mirror: %s", err) } diff --git a/cmd/mirror_edit.go b/cmd/mirror_edit.go index 86462c4c..5adf504b 100644 --- a/cmd/mirror_edit.go +++ b/cmd/mirror_edit.go @@ -28,6 +28,7 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error { } fetchMirror := false + ignoreSignatures := context.Config().GpgDisableVerify context.Flags().Visit(func(flag *flag.Flag) { switch flag.Name { case "filter": @@ -43,6 +44,8 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error { case "archive-url": repo.SetArchiveRoot(flag.Value.String()) fetchMirror = true + case "ignore-signatures": + ignoreSignatures = true } }) @@ -69,7 +72,7 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to initialize GPG verifier: %s", err) } - err = repo.Fetch(context.Downloader(), verifier) + err = repo.Fetch(context.Downloader(), verifier, ignoreSignatures) if err != nil { return fmt.Errorf("unable to edit: %s", err) } diff --git a/cmd/mirror_list.go b/cmd/mirror_list.go index 1a54f433..42b802cf 100644 --- a/cmd/mirror_list.go +++ b/cmd/mirror_list.go @@ -24,7 +24,7 @@ func aptlyMirrorList(cmd *commander.Command, args []string) error { return aptlyMirrorListTxt(cmd, args) } -func aptlyMirrorListTxt(cmd *commander.Command, args []string) error { +func aptlyMirrorListTxt(cmd *commander.Command, _ []string) error { var err error raw := cmd.Flag.Lookup("raw").Value.Get().(bool) @@ -65,7 +65,7 @@ func aptlyMirrorListTxt(cmd *commander.Command, args []string) error { return err } -func aptlyMirrorListJSON(cmd *commander.Command, args []string) error { +func aptlyMirrorListJSON(_ *commander.Command, _ []string) error { var err error repos := make([]*deb.RemoteRepo, context.NewCollectionFactory().RemoteRepoCollection().Len()) diff --git a/cmd/mirror_show.go b/cmd/mirror_show.go index 7491b355..03179161 100644 --- a/cmd/mirror_show.go +++ b/cmd/mirror_show.go @@ -27,7 +27,7 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error { return aptlyMirrorShowTxt(cmd, args) } -func aptlyMirrorShowTxt(cmd *commander.Command, args []string) error { +func aptlyMirrorShowTxt(_ *commander.Command, args []string) error { var err error name := args[0] @@ -93,7 +93,7 @@ func aptlyMirrorShowTxt(cmd *commander.Command, args []string) error { return err } -func aptlyMirrorShowJSON(cmd *commander.Command, args []string) error { +func aptlyMirrorShowJSON(_ *commander.Command, args []string) error { var err error name := args[0] diff --git a/cmd/mirror_update.go b/cmd/mirror_update.go index 111590bb..2e6df439 100644 --- a/cmd/mirror_update.go +++ b/cmd/mirror_update.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "os" "strings" "sync" @@ -41,20 +42,24 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { } } - ignoreMismatch := context.Flags().Lookup("ignore-checksums").Value.Get().(bool) + ignoreSignatures := context.Config().GpgDisableVerify + if context.Flags().IsSet("ignore-signatures") { + ignoreSignatures = context.Flags().Lookup("ignore-signatures").Value.Get().(bool) + } + ignoreChecksums := context.Flags().Lookup("ignore-checksums").Value.Get().(bool) verifier, err := getVerifier(context.Flags()) if err != nil { return fmt.Errorf("unable to initialize GPG verifier: %s", err) } - err = repo.Fetch(context.Downloader(), verifier) + err = repo.Fetch(context.Downloader(), verifier, ignoreSignatures) if err != nil { return fmt.Errorf("unable to update: %s", err) } context.Progress().Printf("Downloading & parsing package files...\n") - err = repo.DownloadPackageIndexes(context.Progress(), context.Downloader(), verifier, collectionFactory, ignoreMismatch) + err = repo.DownloadPackageIndexes(context.Progress(), context.Downloader(), verifier, collectionFactory, ignoreSignatures, ignoreChecksums) if err != nil { return fmt.Errorf("unable to update: %s", err) } @@ -161,7 +166,16 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { var e error // provision download location - task.TempDownPath, e = context.PackagePool().(aptly.LocalPackagePool).GenerateTempPath(task.File.Filename) + if pp, ok := context.PackagePool().(aptly.LocalPackagePool); ok { + task.TempDownPath, e = pp.GenerateTempPath(task.File.Filename) + } else { + var file *os.File + file, e = os.CreateTemp("", task.File.Filename) + if e == nil { + task.TempDownPath = file.Name() + file.Close() + } + } if e != nil { pushError(e) continue @@ -173,7 +187,7 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { repo.PackageURL(task.File.DownloadURL()).String(), task.TempDownPath, &task.File.Checksums, - ignoreMismatch) + ignoreChecksums) if e != nil { pushError(e) continue @@ -197,6 +211,18 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to update: %s", err) } + defer func() { + for _, task := range queue { + if task.TempDownPath == "" { + continue + } + + if err := os.Remove(task.TempDownPath); err != nil && !os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, "Failed to delete %s: %v\n", task.TempDownPath, err) + } + } + }() + // Import downloaded files context.Progress().InitBar(int64(len(queue)), false, aptly.BarMirrorUpdateImportFiles) diff --git a/cmd/publish_list.go b/cmd/publish_list.go index a4e0281f..e3a1d1a8 100644 --- a/cmd/publish_list.go +++ b/cmd/publish_list.go @@ -25,7 +25,7 @@ func aptlyPublishList(cmd *commander.Command, args []string) error { return aptlyPublishListTxt(cmd, args) } -func aptlyPublishListTxt(cmd *commander.Command, args []string) error { +func aptlyPublishListTxt(cmd *commander.Command, _ []string) error { var err error raw := cmd.Flag.Lookup("raw").Value.Get().(bool) @@ -34,7 +34,7 @@ func aptlyPublishListTxt(cmd *commander.Command, args []string) error { published := make([]string, 0, collectionFactory.PublishedRepoCollection().Len()) err = collectionFactory.PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error { - e := collectionFactory.PublishedRepoCollection().LoadComplete(repo, collectionFactory) + e := collectionFactory.PublishedRepoCollection().LoadShallow(repo, collectionFactory) if e != nil { fmt.Fprintf(os.Stderr, "Error found on one publish (prefix:%s / distribution:%s / component:%s\n)", repo.StoragePrefix(), repo.Distribution, repo.Components()) @@ -77,7 +77,7 @@ func aptlyPublishListTxt(cmd *commander.Command, args []string) error { return err } -func aptlyPublishListJSON(cmd *commander.Command, args []string) error { +func aptlyPublishListJSON(_ *commander.Command, _ []string) error { var err error repos := make([]*deb.PublishedRepo, 0, context.NewCollectionFactory().PublishedRepoCollection().Len()) diff --git a/cmd/publish_repo.go b/cmd/publish_repo.go index 3e357cb8..91971022 100644 --- a/cmd/publish_repo.go +++ b/cmd/publish_repo.go @@ -48,8 +48,10 @@ Example: cmd.Flag.String("butautomaticupgrades", "", "set value for ButAutomaticUpgrades field") cmd.Flag.String("label", "", "label to publish") cmd.Flag.String("suite", "", "suite to publish (defaults to distribution)") + cmd.Flag.String("codename", "", "codename to publish (defaults to distribution)") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash") + cmd.Flag.Bool("multi-dist", false, "enable multiple packages with the same filename in different distributions") return cmd } diff --git a/cmd/publish_show.go b/cmd/publish_show.go index 3b9ec4e3..d943df3f 100644 --- a/cmd/publish_show.go +++ b/cmd/publish_show.go @@ -24,7 +24,7 @@ func aptlyPublishShow(cmd *commander.Command, args []string) error { return aptlyPublishShowTxt(cmd, args) } -func aptlyPublishShowTxt(cmd *commander.Command, args []string) error { +func aptlyPublishShowTxt(_ *commander.Command, args []string) error { var err error distribution := args[0] @@ -76,7 +76,7 @@ func aptlyPublishShowTxt(cmd *commander.Command, args []string) error { return err } -func aptlyPublishShowJSON(cmd *commander.Command, args []string) error { +func aptlyPublishShowJSON(_ *commander.Command, args []string) error { var err error distribution := args[0] diff --git a/cmd/publish_snapshot.go b/cmd/publish_snapshot.go index 5b02a6be..3d2e43e6 100644 --- a/cmd/publish_snapshot.go +++ b/cmd/publish_snapshot.go @@ -116,8 +116,9 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { origin := context.Flags().Lookup("origin").Value.String() notAutomatic := context.Flags().Lookup("notautomatic").Value.String() butAutomaticUpgrades := context.Flags().Lookup("butautomaticupgrades").Value.String() + multiDist := context.Flags().Lookup("multi-dist").Value.Get().(bool) - published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, collectionFactory) + published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, collectionFactory, multiDist) if err != nil { return fmt.Errorf("unable to publish: %s", err) } @@ -132,6 +133,7 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { } published.Label = context.Flags().Lookup("label").Value.String() published.Suite = context.Flags().Lookup("suite").Value.String() + published.Codename = context.Flags().Lookup("codename").Value.String() published.SkipContents = context.Config().SkipContentsPublishing @@ -161,8 +163,7 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { forceOverwrite := context.Flags().Lookup("force-overwrite").Value.Get().(bool) if forceOverwrite { - context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing " + - "the same package pool.\n") + context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing the same package pool.\n") } err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) @@ -239,8 +240,10 @@ Example: cmd.Flag.String("butautomaticupgrades", "", "overwrite value for ButAutomaticUpgrades field") cmd.Flag.String("label", "", "label to publish") cmd.Flag.String("suite", "", "suite to publish (defaults to distribution)") + cmd.Flag.String("codename", "", "codename to publish (defaults to distribution)") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash") + cmd.Flag.Bool("multi-dist", false, "enable multiple packages with the same filename in different distributions") return cmd } diff --git a/cmd/publish_switch.go b/cmd/publish_switch.go index 0784fba3..0f1a620b 100644 --- a/cmd/publish_switch.go +++ b/cmd/publish_switch.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/aptly-dev/aptly/deb" - "github.com/aptly-dev/aptly/utils" "github.com/smira/commander" "github.com/smira/flag" ) @@ -64,10 +63,6 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { } for i, component := range components { - if !utils.StrSliceHasItem(publishedComponents, component) { - return fmt.Errorf("unable to switch: component %s is not in published repository", component) - } - snapshot, err = collectionFactory.SnapshotCollection().ByName(names[i]) if err != nil { return fmt.Errorf("unable to switch: %s", err) @@ -100,6 +95,10 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { published.SkipBz2 = context.Flags().Lookup("skip-bz2").Value.Get().(bool) } + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) if err != nil { return fmt.Errorf("unable to publish: %s", err) @@ -161,6 +160,7 @@ This command would switch published repository (with one component) named ppa/wh cmd.Flag.String("component", "", "component names to update (for multi-component publishing, separate components with commas)") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("skip-cleanup", false, "don't remove unreferenced files in prefix/component") + cmd.Flag.Bool("multi-dist", false, "enable multiple packages with the same filename in different distributions") return cmd } diff --git a/cmd/publish_update.go b/cmd/publish_update.go index fcdea8ed..28de8c67 100644 --- a/cmd/publish_update.go +++ b/cmd/publish_update.go @@ -64,6 +64,10 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error { published.SkipBz2 = context.Flags().Lookup("skip-bz2").Value.Get().(bool) } + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) if err != nil { return fmt.Errorf("unable to publish: %s", err) @@ -119,6 +123,7 @@ Example: cmd.Flag.Bool("skip-bz2", false, "don't generate bzipped indexes") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("skip-cleanup", false, "don't remove unreferenced files in prefix/component") + cmd.Flag.Bool("multi-dist", false, "enable multiple packages with the same filename in different distributions") return cmd } diff --git a/cmd/repo_include.go b/cmd/repo_include.go index b84b96a3..72e24c6d 100644 --- a/cmd/repo_include.go +++ b/cmd/repo_include.go @@ -29,7 +29,10 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error { forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool) acceptUnsigned := context.Flags().Lookup("accept-unsigned").Value.Get().(bool) - ignoreSignatures := context.Flags().Lookup("ignore-signatures").Value.Get().(bool) + ignoreSignatures := context.Config().GpgDisableVerify + if context.Flags().IsSet("ignore-signatures") { + ignoreSignatures = context.Flags().Lookup("ignore-signatures").Value.Get().(bool) + } noRemoveFiles := context.Flags().Lookup("no-remove-files").Value.Get().(bool) repoTemplateString := context.Flags().Lookup("repo").Value.Get().(string) collectionFactory := context.NewCollectionFactory() diff --git a/cmd/repo_list.go b/cmd/repo_list.go index 40dec6d4..9c4b0d47 100644 --- a/cmd/repo_list.go +++ b/cmd/repo_list.go @@ -24,7 +24,7 @@ func aptlyRepoList(cmd *commander.Command, args []string) error { return aptlyRepoListTxt(cmd, args) } -func aptlyRepoListTxt(cmd *commander.Command, args []string) error { +func aptlyRepoListTxt(cmd *commander.Command, _ []string) error { var err error raw := cmd.Flag.Lookup("raw").Value.Get().(bool) @@ -71,7 +71,7 @@ func aptlyRepoListTxt(cmd *commander.Command, args []string) error { return err } -func aptlyRepoListJSON(cmd *commander.Command, args []string) error { +func aptlyRepoListJSON(_ *commander.Command, _ []string) error { var err error repos := make([]*deb.LocalRepo, context.NewCollectionFactory().LocalRepoCollection().Len()) diff --git a/cmd/repo_show.go b/cmd/repo_show.go index 6a0be42d..a61a5f1f 100644 --- a/cmd/repo_show.go +++ b/cmd/repo_show.go @@ -25,7 +25,7 @@ func aptlyRepoShow(cmd *commander.Command, args []string) error { return aptlyRepoShowTxt(cmd, args) } -func aptlyRepoShowTxt(cmd *commander.Command, args []string) error { +func aptlyRepoShowTxt(_ *commander.Command, args []string) error { var err error name := args[0] @@ -58,7 +58,7 @@ func aptlyRepoShowTxt(cmd *commander.Command, args []string) error { return err } -func aptlyRepoShowJSON(cmd *commander.Command, args []string) error { +func aptlyRepoShowJSON(_ *commander.Command, args []string) error { var err error name := args[0] diff --git a/cmd/serve.go b/cmd/serve.go index 9efaa772..be974b00 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -29,7 +29,7 @@ func aptlyServe(cmd *commander.Command, args []string) error { // anything else must fail. // E.g.: Running the service under a different user may lead to a rootDir // that exists but is not usable due to access permissions. - err = utils.DirIsAccessible(context.Config().RootDir) + err = utils.DirIsAccessible(context.Config().GetRootDir()) if err != nil { return err } diff --git a/cmd/snapshot_list.go b/cmd/snapshot_list.go index b7836630..7435b187 100644 --- a/cmd/snapshot_list.go +++ b/cmd/snapshot_list.go @@ -23,7 +23,7 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error { return aptlySnapshotListTxt(cmd, args) } -func aptlySnapshotListTxt(cmd *commander.Command, args []string) error { +func aptlySnapshotListTxt(cmd *commander.Command, _ []string) error { var err error raw := cmd.Flag.Lookup("raw").Value.Get().(bool) @@ -59,7 +59,7 @@ func aptlySnapshotListTxt(cmd *commander.Command, args []string) error { return err } -func aptlySnapshotListJSON(cmd *commander.Command, args []string) error { +func aptlySnapshotListJSON(cmd *commander.Command, _ []string) error { var err error sortMethodString := cmd.Flag.Lookup("sort").Value.Get().(string) diff --git a/cmd/snapshot_show.go b/cmd/snapshot_show.go index 98f15a9f..e03a49e5 100644 --- a/cmd/snapshot_show.go +++ b/cmd/snapshot_show.go @@ -25,7 +25,7 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error { return aptlySnapshotShowTxt(cmd, args) } -func aptlySnapshotShowTxt(cmd *commander.Command, args []string) error { +func aptlySnapshotShowTxt(_ *commander.Command, args []string) error { var err error name := args[0] collectionFactory := context.NewCollectionFactory() @@ -85,7 +85,7 @@ func aptlySnapshotShowTxt(cmd *commander.Command, args []string) error { return err } -func aptlySnapshotShowJSON(cmd *commander.Command, args []string) error { +func aptlySnapshotShowJSON(_ *commander.Command, args []string) error { var err error name := args[0] diff --git a/cmd/task_run.go b/cmd/task_run.go index 8e18d94c..ff0e1dd6 100644 --- a/cmd/task_run.go +++ b/cmd/task_run.go @@ -62,11 +62,10 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error { text, _ = reader.ReadString('\n') if text == "\n" { break - } else { - text = strings.TrimSpace(text) + "," - parsedArgs, _ := shellwords.Parse(text) - cmdArgs = append(cmdArgs, parsedArgs...) } + text = strings.TrimSpace(text) + "," + parsedArgs, _ := shellwords.Parse(text) + cmdArgs = append(cmdArgs, parsedArgs...) } if len(cmdArgs) == 0 { diff --git a/codecov.yml b/codecov.yml index ec78c1ee..754a5cea 100644 --- a/codecov.yml +++ b/codecov.yml @@ -3,5 +3,5 @@ coverage: project: default: target: auto - threshold: 0% + threshold: 2% if_ci_failed: error diff --git a/completion.d/_aptly b/completion.d/_aptly index 505c0609..8e8d2bbd 100644 --- a/completion.d/_aptly +++ b/completion.d/_aptly @@ -457,6 +457,7 @@ local keyring="*-keyring=[gpg keyring to use when verifying Release file (could "-distribution=[distribution name to publish]:distribution:($dists)" "-label=[label to publish]:label: " "-suite=[suite to publish]:suite: " + "-codename=[codename to publish]:codename: " "-notautomatic=[set value for NotAutomatic field]:notautomatic: " "-origin=[origin name to publish]:origin: " ${components_options[@]} diff --git a/completion.d/aptly b/completion.d/aptly index afddd63d..8caf47f8 100644 --- a/completion.d/aptly +++ b/completion.d/aptly @@ -1,5 +1,3 @@ -#!/bin/bash - # (The MIT License) # # Copyright (c) 2014 Andrey Smirnov @@ -503,7 +501,7 @@ _aptly() "snapshot"|"repo") if [[ $numargs -eq 0 ]]; then if [[ "$cur" == -* ]]; then - COMPREPLY=($(compgen -W "-acquire-by-hash -batch -butautomaticupgrades= -component= -distribution= -force-overwrite -gpg-key= -keyring= -label= -suite= -notautomatic= -origin= -passphrase= -passphrase-file= -secret-keyring= -skip-contents -skip-bz2 -skip-signing" -- ${cur})) + COMPREPLY=($(compgen -W "-acquire-by-hash -batch -butautomaticupgrades= -component= -distribution= -force-overwrite -gpg-key= -keyring= -label= -suite= -codename= -notautomatic= -origin= -passphrase= -passphrase-file= -secret-keyring= -skip-contents -skip-bz2 -skip-signing -multi-dist" -- ${cur})) else if [[ "$subcmd" == "snapshot" ]]; then COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur})) diff --git a/console/progress.go b/console/progress.go index 3671fc3a..16191857 100644 --- a/console/progress.go +++ b/console/progress.go @@ -7,6 +7,7 @@ import ( "github.com/aptly-dev/aptly/aptly" "github.com/cheggaaa/pb" + "github.com/rs/zerolog/log" "github.com/wsxiaoys/terminal/color" ) @@ -34,6 +35,7 @@ type Progress struct { queue chan printTask bar *pb.ProgressBar barShown bool + worker ProgressWorker } // Check interface @@ -42,16 +44,19 @@ var ( ) // NewProgress creates new progress instance -func NewProgress() *Progress { - return &Progress{ +func NewProgress(structuredLogging bool) *Progress { + p := &Progress{ stopped: make(chan bool), queue: make(chan printTask, 100), } + + p.worker = progressWorkerFactroy(structuredLogging, p) + return p } // Start makes progress start its work func (p *Progress) Start() { - go p.worker() + go p.worker.run() } // Shutdown shuts down progress display @@ -69,7 +74,7 @@ func (p *Progress) Flush() { } // InitBar starts progressbar for count bytes or count items -func (p *Progress) InitBar(count int64, isBytes bool, barType aptly.BarType) { +func (p *Progress) InitBar(count int64, isBytes bool, _ aptly.BarType) { if p.bar != nil { panic("bar already initialized") } @@ -173,42 +178,94 @@ func (p *Progress) ColoredPrintf(msg string, a ...interface{}) { } } -func (p *Progress) worker() { +type ProgressWorker interface { + run() +} + +func progressWorkerFactroy(structuredLogging bool, progress *Progress) ProgressWorker { + if structuredLogging { + worker := loggerProgressWorker{progress: progress} + return &worker + } + + worker := standardProgressWorker{progress: progress} + return &worker +} + +type standardProgressWorker struct { + progress *Progress +} + +func (w *standardProgressWorker) run() { hasBar := false for { - task := <-p.queue + task := <-w.progress.queue switch task.code { case codeBarEnabled: hasBar = true case codeBarDisabled: hasBar = false case codePrint: - if p.barShown { + if w.progress.barShown { fmt.Print("\r\033[2K") - p.barShown = false + w.progress.barShown = false } fmt.Print(task.message) case codePrintStdErr: - if p.barShown { + if w.progress.barShown { fmt.Print("\r\033[2K") - p.barShown = false + w.progress.barShown = false } fmt.Fprint(os.Stderr, task.message) case codeProgress: if hasBar { fmt.Print("\r" + task.message) - p.barShown = true + w.progress.barShown = true } case codeHideProgress: - if p.barShown { + if w.progress.barShown { fmt.Print("\r\033[2K") - p.barShown = false + w.progress.barShown = false } case codeFlush: task.reply <- true case codeStop: - p.stopped <- true + w.progress.stopped <- true + return + } + } +} + +type loggerProgressWorker struct { + progress *Progress +} + +func (w *loggerProgressWorker) run() { + hasBar := false + + for { + task := <-w.progress.queue + switch task.code { + case codeBarEnabled: + hasBar = true + case codeBarDisabled: + hasBar = false + case codePrint, codePrintStdErr: + log.Info().Msg(strings.TrimSuffix(task.message, "\n")) + case codeProgress: + if hasBar { + log.Info().Msg(strings.TrimSuffix(task.message, "\n")) + w.progress.barShown = true + } + case codeHideProgress: + if w.progress.barShown { + w.progress.barShown = false + } + case codeFlush: + task.reply <- true + case codeStop: + w.progress.stopped <- true return } } diff --git a/console/progress_test.go b/console/progress_test.go new file mode 100644 index 00000000..2b412eca --- /dev/null +++ b/console/progress_test.go @@ -0,0 +1,24 @@ +package console + +import ( + "fmt" + "testing" + + . "gopkg.in/check.v1" +) + +func Test(t *testing.T) { + TestingT(t) +} + +type ProgressSuite struct {} + +var _ = Suite(&ProgressSuite{}) + +func (s *ProgressSuite) TestNewProgress(c *C) { + p := NewProgress(false) + c.Check(fmt.Sprintf("%T", p.worker), Equals, fmt.Sprintf("%T", &standardProgressWorker{})) + + p = NewProgress(true) + c.Check(fmt.Sprintf("%T", p.worker), Equals, fmt.Sprintf("%T", &loggerProgressWorker{})) +} diff --git a/context/context.go b/context/context.go index 8ee3ebf9..30e84d42 100644 --- a/context/context.go +++ b/context/context.go @@ -3,6 +3,7 @@ package context import ( gocontext "context" + "errors" "fmt" "math/rand" "os" @@ -18,6 +19,7 @@ import ( "github.com/aptly-dev/aptly/azure" "github.com/aptly-dev/aptly/console" "github.com/aptly-dev/aptly/database" + "github.com/aptly-dev/aptly/database/etcddb" "github.com/aptly-dev/aptly/database/goleveldb" "github.com/aptly-dev/aptly/deb" "github.com/aptly-dev/aptly/files" @@ -48,6 +50,7 @@ type AptlyContext struct { publishedStorages map[string]aptly.PublishedStorage dependencyOptions int architecturesList []string + structuredLogging bool // Debug features fileCPUProfile *os.File fileMemProfile *os.File @@ -93,13 +96,15 @@ func (context *AptlyContext) config() *utils.ConfigStructure { Fatal(err) } } else { - configLocations := []string{ - filepath.Join(os.Getenv("HOME"), ".aptly.conf"), - "/etc/aptly.conf", - } + homeLocation := filepath.Join(os.Getenv("HOME"), ".aptly.conf") + configLocations := []string{homeLocation, "/usr/local/etc/aptly.conf", "/etc/aptly.conf"} for _, configLocation := range configLocations { + // FIXME: check if exists, check if readable err = utils.LoadConfig(configLocation, &utils.Config) + if os.IsPermission(err) || os.IsNotExist(err) { + continue + } if err == nil { break } @@ -109,7 +114,7 @@ func (context *AptlyContext) config() *utils.ConfigStructure { } if err != nil { - fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", configLocations[0]) + fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", homeLocation) // as this is fresh aptly installation, we don't need to support legacy pool locations utils.Config.SkipLegacyPool = true @@ -195,7 +200,7 @@ func (context *AptlyContext) Progress() aptly.Progress { func (context *AptlyContext) _progress() aptly.Progress { if context.progress == nil { - context.progress = console.NewProgress() + context.progress = console.NewProgress(context.structuredLogging) context.progress.Start() } @@ -272,7 +277,7 @@ func (context *AptlyContext) DBPath() string { // DBPath builds path to database func (context *AptlyContext) dbPath() string { - return filepath.Join(context.config().RootDir, "db") + return filepath.Join(context.config().GetRootDir(), "db") } // Database opens and returns current instance of database @@ -286,8 +291,18 @@ func (context *AptlyContext) Database() (database.Storage, error) { func (context *AptlyContext) _database() (database.Storage, error) { if context.database == nil { var err error - - context.database, err = goleveldb.NewDB(context.dbPath()) + switch context.config().DatabaseBackend.Type { + case "leveldb": + if len(context.config().DatabaseBackend.DbPath) == 0 { + return nil, errors.New("leveldb databaseBackend config invalid") + } + dbPath := filepath.Join(context.config().RootDir, context.config().DatabaseBackend.DbPath) + context.database, err = goleveldb.NewDB(dbPath) + case "etcd": + context.database, err = etcddb.NewDB(context.config().DatabaseBackend.URL) + default: + context.database, err = goleveldb.NewDB(context.dbPath()) + } if err != nil { return nil, fmt.Errorf("can't instantiate database: %s", err) } @@ -360,7 +375,26 @@ func (context *AptlyContext) PackagePool() aptly.PackagePool { defer context.Unlock() if context.packagePool == nil { - context.packagePool = files.NewPackagePool(context.config().RootDir, !context.config().SkipLegacyPool) + storageConfig := context.config().PackagePoolStorage + if storageConfig.Azure != nil { + var err error + context.packagePool, err = azure.NewPackagePool( + storageConfig.Azure.AccountName, + storageConfig.Azure.AccountKey, + storageConfig.Azure.Container, + storageConfig.Azure.Prefix, + storageConfig.Azure.Endpoint) + if err != nil { + Fatal(err) + } + } else { + poolRoot := context.config().PackagePoolStorage.Local.Path + if poolRoot == "" { + poolRoot = filepath.Join(context.config().RootDir, "pool") + } + + context.packagePool = files.NewPackagePool(poolRoot, !context.config().SkipLegacyPool) + } } return context.packagePool @@ -374,7 +408,7 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto publishedStorage, ok := context.publishedStorages[name] if !ok { if name == "" { - publishedStorage = files.NewPublishedStorage(filepath.Join(context.config().RootDir, "public"), "hardlink", "") + publishedStorage = files.NewPublishedStorage(filepath.Join(context.config().GetRootDir(), "public"), "hardlink", "") } else if strings.HasPrefix(name, "filesystem:") { params, ok := context.config().FileSystemPublishRoots[name[11:]] if !ok { @@ -393,7 +427,7 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto params.AccessKeyID, params.SecretAccessKey, params.SessionToken, params.Region, params.Endpoint, params.Bucket, params.ACL, params.Prefix, params.StorageClass, params.EncryptionMethod, params.PlusWorkaround, params.DisableMultiDel, - params.ForceSigV2, params.Debug) + params.ForceSigV2, params.ForceVirtualHostedStyle, params.Debug) if err != nil { Fatal(err) } @@ -432,7 +466,7 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto // UploadPath builds path to upload storage func (context *AptlyContext) UploadPath() string { - return filepath.Join(context.Config().RootDir, "upload") + return filepath.Join(context.Config().GetRootDir(), "upload") } func (context *AptlyContext) pgpProvider() string { @@ -456,7 +490,7 @@ func (context *AptlyContext) pgpProvider() string { return provider } -func (context *AptlyContext) getGPGFinder(provider string) pgp.GPGFinder { +func (context *AptlyContext) getGPGFinder() pgp.GPGFinder { switch context.pgpProvider() { case "gpg1": return pgp.GPG1Finder() @@ -479,7 +513,7 @@ func (context *AptlyContext) GetSigner() pgp.Signer { return &pgp.GoSigner{} } - return pgp.NewGpgSigner(context.getGPGFinder(provider)) + return pgp.NewGpgSigner(context.getGPGFinder()) } // GetVerifier returns Verifier with respect to provider @@ -492,7 +526,7 @@ func (context *AptlyContext) GetVerifier() pgp.Verifier { return &pgp.GoVerifier{} } - return pgp.NewGpgVerifier(context.getGPGFinder(provider)) + return pgp.NewGpgVerifier(context.getGPGFinder()) } // UpdateFlags sets internal copy of flags in the context @@ -540,6 +574,11 @@ func (context *AptlyContext) GoContextHandleSignals() { }() } +// StructuredLogging allows to set the structuredLogging flag +func (context *AptlyContext) StructuredLogging(structuredLogging bool) { + context.structuredLogging = structuredLogging +} + // Shutdown shuts context down func (context *AptlyContext) Shutdown() { context.Lock() @@ -561,6 +600,9 @@ func (context *AptlyContext) Shutdown() { context.fileMemProfile = nil } } + if context.taskList != nil { + context.taskList.Stop() + } if context.database != nil { context.database.Close() context.database = nil diff --git a/database/etcddb/batch.go b/database/etcddb/batch.go new file mode 100644 index 00000000..24b83de9 --- /dev/null +++ b/database/etcddb/batch.go @@ -0,0 +1,53 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +type EtcDBatch struct { + s *EtcDStorage + ops []clientv3.Op +} + +type WriteOptions struct { + NoWriteMerge bool + Sync bool +} + +func (b *EtcDBatch) Put(key []byte, value []byte) (err error) { + b.ops = append(b.ops, clientv3.OpPut(string(key), string(value))) + return +} + +func (b *EtcDBatch) Delete(key []byte) (err error) { + b.ops = append(b.ops, clientv3.OpDelete(string(key))) + return +} + +func (b *EtcDBatch) Write() (err error) { + kv := clientv3.NewKV(b.s.db) + + batchSize := 128 + for i := 0; i < len(b.ops); i += batchSize { + txn := kv.Txn(Ctx) + end := i + batchSize + if end > len(b.ops) { + end = len(b.ops) + } + + batch := b.ops[i:end] + txn.Then(batch...) + _, err = txn.Commit() + if err != nil { + panic(err) + } + } + + return +} + +// batch should implement database.Batch +var ( + _ database.Batch = &EtcDBatch{} +) diff --git a/database/etcddb/database.go b/database/etcddb/database.go new file mode 100644 index 00000000..37a222e6 --- /dev/null +++ b/database/etcddb/database.go @@ -0,0 +1,32 @@ +package etcddb + +import ( + "context" + "time" + + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +var Ctx = context.TODO() + +func internalOpen(url string) (cli *clientv3.Client, err error) { + cfg := clientv3.Config{ + Endpoints: []string{url}, + DialTimeout: 30 * time.Second, + MaxCallSendMsgSize: 2147483647, // (2048 * 1024 * 1024) - 1 + MaxCallRecvMsgSize: 2147483647, + DialKeepAliveTimeout: 7200 * time.Second, + } + + cli, err = clientv3.New(cfg) + return +} + +func NewDB(url string) (database.Storage, error) { + cli, err := internalOpen(url) + if err != nil { + return nil, err + } + return &EtcDStorage{url, cli, ""}, nil +} diff --git a/database/etcddb/database_test.go b/database/etcddb/database_test.go new file mode 100644 index 00000000..b31e5599 --- /dev/null +++ b/database/etcddb/database_test.go @@ -0,0 +1,158 @@ +package etcddb_test + +import ( + "testing" + + "github.com/aptly-dev/aptly/database" + "github.com/aptly-dev/aptly/database/etcddb" + . "gopkg.in/check.v1" +) + +// Launch gocheck tests +func Test(t *testing.T) { + TestingT(t) +} + +type EtcDDBSuite struct { + url string + db database.Storage +} + +var _ = Suite(&EtcDDBSuite{}) + +func (s *EtcDDBSuite) SetUpTest(c *C) { + var err error + s.db, err = etcddb.NewDB("127.0.0.1:2379") + c.Assert(err, IsNil) +} + +func (s *EtcDDBSuite) TestSetUpTest(c *C) { + var err error + s.db, err = etcddb.NewDB("127.0.0.1:2379") + c.Assert(err, IsNil) +} + +func (s *EtcDDBSuite) TestGetPut(c *C) { + var ( + key = []byte("key") + value = []byte("value") + ) + var err error + + err = s.db.Put(key, value) + c.Assert(err, IsNil) + + result, err := s.db.Get(key) + c.Assert(err, IsNil) + c.Assert(result, DeepEquals, value) +} + +func (s *EtcDDBSuite) TestDelete(c *C) { + var ( + key = []byte("key") + value = []byte("value") + ) + + err := s.db.Put(key, value) + c.Assert(err, IsNil) + + _, err = s.db.Get(key) + c.Assert(err, IsNil) + + err = s.db.Delete(key) + c.Assert(err, IsNil) + +} + +func (s *EtcDDBSuite) TestByPrefix(c *C) { + //c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{}) + + s.db.Put([]byte{0x80, 0x01}, []byte{0x01}) + s.db.Put([]byte{0x80, 0x03}, []byte{0x03}) + s.db.Put([]byte{0x80, 0x02}, []byte{0x02}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + s.db.Put([]byte{0x90, 0x01}, []byte{0x04}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + s.db.Put([]byte{0x00, 0x01}, []byte{0x05}) + c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(s.db.KeysByPrefix([]byte{0x80}), DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + keys := [][]byte{} + values := [][]byte{} + + c.Check(s.db.ProcessByPrefix([]byte{0x80}, func(k, v []byte) error { + keys = append(keys, append([]byte(nil), k...)) + values = append(values, append([]byte(nil), v...)) + return nil + }), IsNil) + + c.Check(values, DeepEquals, [][]byte{{0x01}, {0x02}, {0x03}}) + c.Check(keys, DeepEquals, [][]byte{{0x80, 0x01}, {0x80, 0x02}, {0x80, 0x03}}) + + c.Check(s.db.ProcessByPrefix([]byte{0x80}, func(k, v []byte) error { + return database.ErrNotFound + }), Equals, database.ErrNotFound) + + c.Check(s.db.ProcessByPrefix([]byte{0xa0}, func(k, v []byte) error { + return database.ErrNotFound + }), IsNil) + + c.Check(s.db.FetchByPrefix([]byte{0xa0}), DeepEquals, [][]byte{}) + c.Check(s.db.KeysByPrefix([]byte{0xa0}), DeepEquals, [][]byte{}) +} + +func (s *EtcDDBSuite) TestHasPrefix(c *C) { + //c.Check(s.db.HasPrefix([]byte(nil)), Equals, false) + //c.Check(s.db.HasPrefix([]byte{0x80}), Equals, false) + + s.db.Put([]byte{0x80, 0x01}, []byte{0x01}) + + c.Check(s.db.HasPrefix([]byte(nil)), Equals, true) + c.Check(s.db.HasPrefix([]byte{0x80}), Equals, true) + c.Check(s.db.HasPrefix([]byte{0x79}), Equals, false) +} + +func (s *EtcDDBSuite) TestTransactionCommit(c *C) { + var ( + key = []byte("key") + key2 = []byte("key2") + value = []byte("value") + value2 = []byte("value2") + ) + transaction, err := s.db.OpenTransaction() + + err = s.db.Put(key, value) + c.Assert(err, IsNil) + + c.Assert(err, IsNil) + transaction.Put(key2, value2) + v, err := s.db.Get(key) + c.Check(v, DeepEquals, value) + err = transaction.Delete(key) + c.Assert(err, IsNil) + + _, err = transaction.Get(key2) + c.Assert(err, IsNil) + + v2, err := transaction.Get(key2) + c.Check(err, IsNil) + c.Check(v2, DeepEquals, value2) + + _, err = transaction.Get(key) + c.Assert(err, IsNil) + + err = transaction.Commit() + c.Check(err, IsNil) + + v2, err = transaction.Get(key2) + c.Check(err, IsNil) + c.Check(v2, DeepEquals, value2) + + _, err = transaction.Get(key) + c.Assert(err, NotNil) +} + diff --git a/database/etcddb/storage.go b/database/etcddb/storage.go new file mode 100644 index 00000000..efc4cf64 --- /dev/null +++ b/database/etcddb/storage.go @@ -0,0 +1,202 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + "github.com/pborman/uuid" + clientv3 "go.etcd.io/etcd/client/v3" + + "fmt" +) + +type EtcDStorage struct { + url string + db *clientv3.Client + tmpPrefix string // prefix for temporary DBs +} + +// CreateTemporary creates new DB of the same type in temp dir +func (s *EtcDStorage) CreateTemporary() (database.Storage, error) { + tmp := uuid.NewRandom().String() + return &EtcDStorage{ + url: s.url, + db: s.db, + tmpPrefix: tmp, + }, nil +} + +func (s *EtcDStorage) applyPrefix(key []byte) []byte { + if len(s.tmpPrefix) != 0 { + return append([]byte(s.tmpPrefix+"/"), key...) + } + return key +} + +// Get key value from etcd +func (s *EtcDStorage) Get(key []byte) (value []byte, err error) { + realKey := s.applyPrefix(key) + getResp, err := s.db.Get(Ctx, string(realKey)) + if err != nil { + return + } + for _, kv := range getResp.Kvs { + value = kv.Value + break + } + if len(value) == 0 { + err = database.ErrNotFound + return + } + return +} + +// Put saves key to etcd, if key has the same value in DB already, it is not saved +func (s *EtcDStorage) Put(key []byte, value []byte) (err error) { + realKey := s.applyPrefix(key) + _, err = s.db.Put(Ctx, string(realKey), string(value)) + if err != nil { + return + } + return +} + +// Delete removes key from etcd +func (s *EtcDStorage) Delete(key []byte) (err error) { + realKey := s.applyPrefix(key) + _, err = s.db.Delete(Ctx, string(realKey)) + if err != nil { + return + } + return +} + +// KeysByPrefix returns all keys that start with prefix +func (s *EtcDStorage) KeysByPrefix(prefix []byte) [][]byte { + realPrefix := s.applyPrefix(prefix) + result := make([][]byte, 0, 20) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, ev := range getResp.Kvs { + key := ev.Key + keyc := make([]byte, len(key)) + copy(keyc, key) + result = append(result, key) + } + return result +} + +// FetchByPrefix returns all values with keys that start with prefix +func (s *EtcDStorage) FetchByPrefix(prefix []byte) [][]byte { + realPrefix := s.applyPrefix(prefix) + result := make([][]byte, 0, 20) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, kv := range getResp.Kvs { + valc := make([]byte, len(kv.Value)) + copy(valc, kv.Value) + result = append(result, kv.Value) + } + + return result +} + +// HasPrefix checks whether it can find any key with given prefix and returns true if one exists +func (s *EtcDStorage) HasPrefix(prefix []byte) bool { + realPrefix := s.applyPrefix(prefix) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) + if err != nil { + return false + } + return getResp.Count > 0 +} + +// ProcessByPrefix iterates through all entries where key starts with prefix and calls +// StorageProcessor on key value pair +func (s *EtcDStorage) ProcessByPrefix(prefix []byte, proc database.StorageProcessor) error { + realPrefix := s.applyPrefix(prefix) + getResp, err := s.db.Get(Ctx, string(realPrefix), clientv3.WithPrefix()) + if err != nil { + return err + } + + for _, kv := range getResp.Kvs { + err := proc(kv.Key, kv.Value) + if err != nil { + return err + } + } + return nil +} + +// Close finishes etcd connect +func (s *EtcDStorage) Close() error { + // do not close temporary db + if len(s.tmpPrefix) != 0 { + return nil + } + if s.db == nil { + return nil + } + err := s.db.Close() + s.db = nil + return err +} + +// Reopen tries to open (re-open) the database +func (s *EtcDStorage) Open() error { + if s.db != nil { + return nil + } + var err error + s.db, err = internalOpen(s.url) + return err +} + +// CreateBatch creates a Batch object +func (s *EtcDStorage) CreateBatch() database.Batch { + if s.db == nil { + return nil + } + return &EtcDBatch{ + s: s, + } +} + +// OpenTransaction creates new transaction. +func (s *EtcDStorage) OpenTransaction() (database.Transaction, error) { + tmpdb, err := s.CreateTemporary() + if err != nil { + return nil, err + } + return &transaction{s: s, tmpdb: tmpdb}, nil +} + +// CompactDB does nothing for etcd +func (s *EtcDStorage) CompactDB() error { + return nil +} + +// Drop removes only temporary DBs with etcd (i.e. remove all prefixed keys) +func (s *EtcDStorage) Drop() error { + if len(s.tmpPrefix) != 0 { + getResp, err := s.db.Get(Ctx, s.tmpPrefix, clientv3.WithPrefix()) + if err != nil { + return nil + } + for _, kv := range getResp.Kvs { + _, err = s.db.Delete(Ctx, string(kv.Key)) + if err != nil { + return fmt.Errorf("cannot delete tempdb entry: %s", kv.Key) + } + } + } + return nil +} + +// Check interface +var ( + _ database.Storage = &EtcDStorage{} +) diff --git a/database/etcddb/transaction.go b/database/etcddb/transaction.go new file mode 100644 index 00000000..01f54dad --- /dev/null +++ b/database/etcddb/transaction.go @@ -0,0 +1,75 @@ +package etcddb + +import ( + "github.com/aptly-dev/aptly/database" + clientv3 "go.etcd.io/etcd/client/v3" +) + +type transaction struct { + s *EtcDStorage + tmpdb database.Storage + ops []clientv3.Op +} + +// Get implements database.Reader interface. +func (t *transaction) Get(key []byte) (value []byte, err error) { + value, err = t.tmpdb.Get(key) + // if not found, search main db + if err != nil { + value, err = t.s.Get(key) + } + return +} + +// Put implements database.Writer interface. +func (t *transaction) Put(key, value []byte) (err error) { + err = t.tmpdb.Put(key, value) + if err != nil { + return + } + t.ops = append(t.ops, clientv3.OpPut(string(key), string(value))) + return +} + +// Delete implements database.Writer interface. +func (t *transaction) Delete(key []byte) (err error) { + err = t.tmpdb.Delete(key) + if err != nil { + return + } + t.ops = append(t.ops, clientv3.OpDelete(string(key))) + return +} + +func (t *transaction) Commit() (err error) { + kv := clientv3.NewKV(t.s.db) + + batchSize := 128 + for i := 0; i < len(t.ops); i += batchSize { + txn := kv.Txn(Ctx) + end := i + batchSize + if end > len(t.ops) { + end = len(t.ops) + } + + batch := t.ops[i:end] + txn.Then(batch...) + _, err = txn.Commit() + if err != nil { + panic(err) + } + } + t.ops = []clientv3.Op{} + + return +} + +// Discard is safe to call after Commit(), it would be no-op +func (t *transaction) Discard() { + t.ops = []clientv3.Op{} + t.tmpdb.Drop() + return +} + +// transaction should implement database.Transaction +var _ database.Transaction = &transaction{} diff --git a/database/goleveldb/storage.go b/database/goleveldb/storage.go index a95c5680..37acf3d8 100644 --- a/database/goleveldb/storage.go +++ b/database/goleveldb/storage.go @@ -3,7 +3,6 @@ package goleveldb import ( "bytes" "errors" - "io/ioutil" "os" "github.com/syndtr/goleveldb/leveldb" @@ -19,7 +18,7 @@ type storage struct { // CreateTemporary creates new DB of the same type in temp dir func (s *storage) CreateTemporary() (database.Storage, error) { - tempdir, err := ioutil.TempDir("", "aptly") + tempdir, err := os.MkdirTemp("", "aptly") if err != nil { return nil, err } diff --git a/deb/changes.go b/deb/changes.go index 3e2c6914..c264986a 100644 --- a/deb/changes.go +++ b/deb/changes.go @@ -4,16 +4,17 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "path/filepath" "sort" "strings" + "sync" "text/template" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/pgp" "github.com/aptly-dev/aptly/utils" + "github.com/saracen/walker" ) // Changes is a result of .changes file parsing @@ -39,7 +40,7 @@ func NewChanges(path string) (*Changes, error) { ChangesName: filepath.Base(path), } - c.TempDir, err = ioutil.TempDir(os.TempDir(), "aptly") + c.TempDir, err = os.MkdirTemp(os.TempDir(), "aptly") if err != nil { return nil, err } @@ -221,12 +222,12 @@ func (c *Changes) GetField(field string) string { } // MatchesDependency implements PackageLike interface -func (c *Changes) MatchesDependency(d Dependency) bool { +func (c *Changes) MatchesDependency(_ Dependency) bool { return false } // MatchesArchitecture implements PackageLike interface -func (c *Changes) MatchesArchitecture(arch string) bool { +func (c *Changes) MatchesArchitecture(_ string) bool { return false } @@ -248,6 +249,8 @@ func (c *Changes) GetArchitecture() string { // CollectChangesFiles walks filesystem collecting all .changes files func CollectChangesFiles(locations []string, reporter aptly.ResultReporter) (changesFiles, failedFiles []string) { + changesFilesLock := &sync.Mutex{} + for _, location := range locations { info, err2 := os.Stat(location) if err2 != nil { @@ -256,15 +259,14 @@ func CollectChangesFiles(locations []string, reporter aptly.ResultReporter) (cha continue } if info.IsDir() { - err2 = filepath.Walk(location, func(path string, info os.FileInfo, err3 error) error { - if err3 != nil { - return err3 - } + err2 = walker.Walk(location, func(path string, info os.FileInfo) error { if info.IsDir() { return nil } if strings.HasSuffix(info.Name(), ".changes") { + changesFilesLock.Lock() + defer changesFilesLock.Unlock() changesFiles = append(changesFiles, path) } diff --git a/deb/changes_test.go b/deb/changes_test.go index 64b962b7..b7dc4d95 100644 --- a/deb/changes_test.go +++ b/deb/changes_test.go @@ -45,7 +45,7 @@ func (s *ChangesSuite) SetUpTest(c *C) { s.checksumStorage = files.NewMockChecksumStorage() s.packagePool = files.NewPackagePool(s.Dir, false) - s.progress = console.NewProgress() + s.progress = console.NewProgress(false) s.progress.Start() } diff --git a/deb/contents.go b/deb/contents.go index 9f694354..cc8f8cef 100644 --- a/deb/contents.go +++ b/deb/contents.go @@ -64,7 +64,7 @@ func (index *ContentsIndex) WriteTo(w io.Writer) (int64, error) { currentPkgs [][]byte ) - err = index.db.ProcessByPrefix(index.prefix, func(key []byte, value []byte) error { + err = index.db.ProcessByPrefix(index.prefix, func(key []byte, _ []byte) error { // cut prefix key = key[prefixLen:] diff --git a/deb/format.go b/deb/format.go index 47ea776e..95febe35 100644 --- a/deb/format.go +++ b/deb/format.go @@ -136,7 +136,7 @@ func isMultilineField(field string, isRelease bool) bool { // Write single field from Stanza to writer. // -//nolint: interfacer +// nolint: interfacer func writeField(w *bufio.Writer, field, value string, isRelease bool) (err error) { if !isMultilineField(field, isRelease) { _, err = w.WriteString(field + ": " + value + "\n") diff --git a/deb/graph.go b/deb/graph.go index 4c45ca9f..16a7ce85 100644 --- a/deb/graph.go +++ b/deb/graph.go @@ -119,8 +119,8 @@ func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz "shape": "Mrecord", "style": "filled", "fillcolor": "darkolivegreen1", - "label": fmt.Sprintf("%sPublished %s/%s|comp: %s|arch: %s%s", labelStart, - repo.Prefix, repo.Distribution, strings.Join(repo.Components(), " "), + "label": fmt.Sprintf("%sPublished %s|comp: %s|arch: %s%s", labelStart, + repo.GetPath(), strings.Join(repo.Components(), " "), strings.Join(repo.Architectures, ", "), labelEnd), }) diff --git a/deb/import.go b/deb/import.go index 53322f8d..d0f65479 100644 --- a/deb/import.go +++ b/deb/import.go @@ -5,14 +5,19 @@ import ( "path/filepath" "sort" "strings" + "sync" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/pgp" "github.com/aptly-dev/aptly/utils" + "github.com/saracen/walker" ) // CollectPackageFiles walks filesystem collecting all candidates for package files func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (packageFiles, otherFiles, failedFiles []string) { + packageFilesLock := &sync.Mutex{} + otherFilesLock := &sync.Mutex{} + for _, location := range locations { info, err2 := os.Stat(location) if err2 != nil { @@ -21,18 +26,19 @@ func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (pac continue } if info.IsDir() { - err2 = filepath.Walk(location, func(path string, info os.FileInfo, err3 error) error { - if err3 != nil { - return err3 - } + err2 = walker.Walk(location, func(path string, info os.FileInfo) error { if info.IsDir() { return nil } if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".udeb") || strings.HasSuffix(info.Name(), ".dsc") || strings.HasSuffix(info.Name(), ".ddeb") { + packageFilesLock.Lock() + defer packageFilesLock.Unlock() packageFiles = append(packageFiles, path) } else if strings.HasSuffix(info.Name(), ".buildinfo") { + otherFilesLock.Lock() + defer otherFilesLock.Unlock() otherFiles = append(otherFiles, path) } @@ -71,13 +77,7 @@ func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace b list.PrepareIndex() } - transaction, err := collection.db.OpenTransaction() - if err != nil { - return nil, nil, err - } - defer transaction.Discard() - - checksumStorage := checksumStorageProvider(transaction) + checksumStorage := checksumStorageProvider(collection.db) for _, file := range packageFiles { var ( @@ -201,7 +201,7 @@ func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace b continue } - err = collection.UpdateInTransaction(p, transaction) + err = collection.Update(p) if err != nil { reporter.Warning("Unable to save package %s: %s", p, err) failedFiles = append(failedFiles, file) @@ -227,6 +227,6 @@ func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace b processedFiles = append(processedFiles, candidateProcessedFiles...) } - err = transaction.Commit() + err = nil // reset error as only failed files are reported return } diff --git a/deb/index_files.go b/deb/index_files.go index d8fb7dc5..01de3dd5 100644 --- a/deb/index_files.go +++ b/deb/index_files.go @@ -143,19 +143,20 @@ func (file *indexFile) Finalize(signer pgp.Signer) error { } if signer != nil { + gpgExt := ".gpg" if file.detachedSign { - err = signer.DetachedSign(file.tempFilename, file.tempFilename+".gpg") + err = signer.DetachedSign(file.tempFilename, file.tempFilename+gpgExt) if err != nil { return fmt.Errorf("unable to detached sign file: %s", err) } if file.parent.suffix != "" { - file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+".gpg")] = - filepath.Join(file.parent.basePath, file.relativePath+".gpg") + file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+gpgExt)] = + filepath.Join(file.parent.basePath, file.relativePath+gpgExt) } - err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+".gpg"), - file.tempFilename+".gpg") + err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+gpgExt), + file.tempFilename+gpgExt) if err != nil { return fmt.Errorf("unable to publish file: %s", err) } @@ -248,7 +249,7 @@ func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, s } } -func (files *indexFiles) PackageIndex(component, arch string, udeb, installer bool) *indexFile { +func (files *indexFiles) PackageIndex(component, arch string, udeb bool, installer bool, distribution string) *indexFile { if arch == ArchitectureSource { udeb = false } @@ -263,7 +264,11 @@ func (files *indexFiles) PackageIndex(component, arch string, udeb, installer bo if udeb { relativePath = filepath.Join(component, "debian-installer", fmt.Sprintf("binary-%s", arch), "Packages") } else if installer { - relativePath = filepath.Join(component, fmt.Sprintf("installer-%s", arch), "current", "images", "SHA256SUMS") + if distribution == aptly.DistributionFocal { + relativePath = filepath.Join(component, fmt.Sprintf("installer-%s", arch), "current", "legacy-images", "SHA256SUMS") + } else { + relativePath = filepath.Join(component, fmt.Sprintf("installer-%s", arch), "current", "images", "SHA256SUMS") + } } else { relativePath = filepath.Join(component, fmt.Sprintf("binary-%s", arch), "Packages") } diff --git a/deb/list.go b/deb/list.go index ec14bb98..51c9ba7e 100644 --- a/deb/list.go +++ b/deb/list.go @@ -145,7 +145,7 @@ func (l *PackageList) Add(p *Package) error { l.packages[key] = p if l.indexed { - for _, provides := range p.Provides { + for _, provides := range p.ProvidedPackages() { l.providesIndex[provides] = append(l.providesIndex[provides], p) } @@ -215,7 +215,7 @@ func (l *PackageList) Append(pl *PackageList) error { func (l *PackageList) Remove(p *Package) { delete(l.packages, l.keyFunc(p)) if l.indexed { - for _, provides := range p.Provides { + for _, provides := range p.ProvidedPackages() { for i, pkg := range l.providesIndex[provides] { if pkg.Equals(p) { // remove l.ProvidesIndex[provides][i] w/o preserving order @@ -351,7 +351,7 @@ func (l *PackageList) VerifyDependencies(options int, architectures []string, so cache[hash] = satisfied } - if !satisfied && !ok { + if !satisfied { variantsMissing = append(variantsMissing, dep) } @@ -366,6 +366,8 @@ func (l *PackageList) VerifyDependencies(options int, architectures []string, so } } + missing = depSliceDeduplicate(missing) + if progress != nil { progress.ShutdownBar() } @@ -417,7 +419,7 @@ func (l *PackageList) PrepareIndex() { l.packagesIndex[i] = p i++ - for _, provides := range p.Provides { + for _, provides := range p.ProvidedPackages() { l.providesIndex[provides] = append(l.providesIndex[provides], p) } } @@ -470,21 +472,25 @@ func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []* searchResults = append(searchResults, p) if !allMatches { - break + return } } i++ } - if dep.Relation == VersionDontCare { - for _, p := range l.providesIndex[dep.Pkg] { - if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) { + providers, ok := l.providesIndex[dep.Pkg] + if !ok { + return + } + for _, p := range providers { + if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) { + if p.MatchesDependency(dep) { searchResults = append(searchResults, p) + } - if !allMatches { - break - } + if !allMatches { + return } } } diff --git a/deb/list_test.go b/deb/list_test.go index 91769179..03cca348 100644 --- a/deb/list_test.go +++ b/deb/list_test.go @@ -300,6 +300,14 @@ func (s *PackageListSuite) TestSearch(c *C) { c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.2"}, true), Contains, []*Package{s.packages2[4], s.packages2[5]}) c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.1~bp1"}, true), Contains, []*Package{s.packages2[2], s.packages2[3], s.packages2[4], s.packages2[5]}) c.Check(s.il2.Search(Dependency{Architecture: "amd64", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "5.0"}, true), IsNil) + + // Provides with version number + python3CFFIBackend := &Package{Name: "python3-cffi-backend", Version: "1.15.1-5+b1", Architecture: "amd64", Provides: []string{"python3-cffi-backend-api-9729", "python3-cffi-backend-api-max (= 10495)", "python3-cffi-backend-api-min (= 9729)"}} + err := s.il2.Add(python3CFFIBackend) + c.Check(err, IsNil) + c.Check(s.il2.Search(Dependency{Pkg: "python3-cffi-backend-api-max", Relation: VersionGreaterOrEqual, Version: "9729"}, false), DeepEquals, []*Package{python3CFFIBackend}) + c.Check(s.il2.Search(Dependency{Pkg: "python3-cffi-backend-api-max", Relation: VersionLess, Version: "9729"}, false), IsNil) + c.Check(s.il2.Search(Dependency{Pkg: "python3-cffi-backend-api-max", Relation: VersionDontCare}, false), DeepEquals, []*Package{python3CFFIBackend}) } func (s *PackageListSuite) TestFilter(c *C) { diff --git a/deb/local.go b/deb/local.go index 2a15c734..1b09fdbd 100644 --- a/deb/local.go +++ b/deb/local.go @@ -116,7 +116,7 @@ func (collection *LocalRepoCollection) search(filter func(*LocalRepo) bool, uniq return result } - collection.db.ProcessByPrefix([]byte("L"), func(key, blob []byte) error { + collection.db.ProcessByPrefix([]byte("L"), func(_, blob []byte) error { r := &LocalRepo{} if err := r.Decode(blob); err != nil { log.Printf("Error decoding local repo: %s\n", err) @@ -219,7 +219,7 @@ func (collection *LocalRepoCollection) ByUUID(uuid string) (*LocalRepo, error) { // ForEach runs method for each repository func (collection *LocalRepoCollection) ForEach(handler func(*LocalRepo) error) error { - return collection.db.ProcessByPrefix([]byte("L"), func(key, blob []byte) error { + return collection.db.ProcessByPrefix([]byte("L"), func(_, blob []byte) error { r := &LocalRepo{} if err := r.Decode(blob); err != nil { log.Printf("Error decoding repo: %s\n", err) diff --git a/deb/package.go b/deb/package.go index ce16adf2..82ac7885 100644 --- a/deb/package.go +++ b/deb/package.go @@ -10,6 +10,7 @@ import ( "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/utils" + "github.com/rs/zerolog/log" ) // Package is single instance of Debian package @@ -189,7 +190,12 @@ func NewInstallerPackageFromControlFile(input Stanza, repo *RemoteRepo, componen return nil, err } - relPath := filepath.Join("dists", repo.Distribution, component, fmt.Sprintf("%s-%s", p.Name, architecture), "current", "images") + var relPath string + if repo.Distribution == aptly.DistributionFocal { + relPath = filepath.Join("dists", repo.Distribution, component, fmt.Sprintf("%s-%s", p.Name, architecture), "current", "legacy-images") + } else { + relPath = filepath.Join("dists", repo.Distribution, component, fmt.Sprintf("%s-%s", p.Name, architecture), "current", "images") + } for i := range files { files[i].downloadPath = relPath @@ -307,6 +313,23 @@ func (p *Package) GetField(name string) string { } } +// ProvidedPackages returns just the package names of the provided packages (without version numbers such as +// `(= 1.2.3)`). +func (p *Package) ProvidedPackages() []string { + result := make([]string, len(p.Provides)) + for i, provided := range p.Provides { + providedDep, err := ParseDependency(provided) + if err != nil { + // Should never happen, but I included this, so it definitely has the old behavior in case there is no + // special syntax. + result[i] = provided + } else { + result[i] = providedDep.Pkg + } + } + return result +} + // MatchesArchitecture checks whether packages matches specified architecture func (p *Package) MatchesArchitecture(arch string) bool { if p.Architecture == ArchitectureAll && arch != ArchitectureSource { @@ -316,24 +339,75 @@ func (p *Package) MatchesArchitecture(arch string) bool { return p.Architecture == arch } +func JoinErrors(errs ...error) error { + var combinedErr error + for _, err := range errs { + if err != nil { + if combinedErr == nil { + combinedErr = err + } else { + combinedErr = fmt.Errorf("%w\n%v", combinedErr, err) + } + } + } + return combinedErr +} + +// providesDependency checks if the package `Provide:`s the dependency, assuming that the architecture matches. +// If the `Provides:` entry includes a version number, it will be considered when checking the dependency. +func (p *Package) providesDependency(dep Dependency) (bool, error) { + var errs []error // won't cause an allocation in case of no errors + for _, provided := range p.Provides { + providedDep, err := ParseDependency(provided) + if err != nil { + errs = append(errs, err) + } + // The only relation allowed here is `=`. + // > The relations allowed are [...]. The exception is the Provides field, for which only = is allowed. + // > [...] + // > A Provides field may contain version numbers, and such a version number will be considered when + // > considering a dependency on or conflict with the virtual package name. + // -- https://www.debian.org/doc/debian-policy/ch-relationships.html + switch providedDep.Relation { + case VersionDontCare: + if providedDep.Pkg == dep.Pkg { + return true, nil + } + case VersionEqual: + providedVersion := providedDep.Version + if providedDep.Pkg == dep.Pkg && versionSatisfiesDependency(providedVersion, dep) { + return true, nil + } + default: + errs = append(errs, fmt.Errorf("unsupported relation in Provides: %s", providedDep.String())) + } + } + return false, JoinErrors(errs...) +} + // MatchesDependency checks whether package matches specified dependency func (p *Package) MatchesDependency(dep Dependency) bool { if dep.Architecture != "" && !p.MatchesArchitecture(dep.Architecture) { return false } - if dep.Relation == VersionDontCare { - if utils.StrSliceHasItem(p.Provides, dep.Pkg) { - return true - } - return dep.Pkg == p.Name + providesDep, err := p.providesDependency(dep) + if err != nil { + log.Warn().Err(err).Msg("Error while checking if package provides dependency") + } + if providesDep { + return true } if dep.Pkg != p.Name { return false } - r := CompareVersions(p.Version, dep.Version) + return versionSatisfiesDependency(p.Version, dep) +} + +func versionSatisfiesDependency(version string, dep Dependency) bool { + r := CompareVersions(version, dep.Version) switch dep.Relation { case VersionEqual: @@ -347,13 +421,15 @@ func (p *Package) MatchesDependency(dep Dependency) bool { case VersionGreaterOrEqual: return r >= 0 case VersionPatternMatch: - matched, err := filepath.Match(dep.Version, p.Version) + matched, err := filepath.Match(dep.Version, version) return err == nil && matched case VersionRegexp: - return dep.Regexp.FindStringIndex(p.Version) != nil + return dep.Regexp.FindStringIndex(version) != nil + case VersionDontCare: + return true + default: + panic(fmt.Sprintf("unknown relation: %d", dep.Relation)) } - - panic("unknown relation") } // GetName returns package name @@ -621,9 +697,7 @@ func (p *Package) LinkFromPool(publishedStorage aptly.PublishedStorage, packageP return err } - publishedDirectory := filepath.Join(prefix, relPath) - - err = publishedStorage.LinkFromPool(publishedDirectory, f.Filename, packagePool, sourcePoolPath, f.Checksums, force) + err = publishedStorage.LinkFromPool(prefix, relPath, f.Filename, packagePool, sourcePoolPath, f.Checksums, force) if err != nil { return err } diff --git a/deb/package_collection.go b/deb/package_collection.go index 2da7fe67..c7e6a300 100644 --- a/deb/package_collection.go +++ b/deb/package_collection.go @@ -317,7 +317,7 @@ func (collection *PackageCollection) Scan(q PackageQuery) (result *PackageList) } // Search is not implemented -func (collection *PackageCollection) Search(dep Dependency, allMatches bool) (searchResults []*Package) { +func (collection *PackageCollection) Search(_ Dependency, _ bool) (searchResults []*Package) { panic("Not implemented") } diff --git a/deb/package_test.go b/deb/package_test.go index b3817d14..18f8040d 100644 --- a/deb/package_test.go +++ b/deb/package_test.go @@ -333,9 +333,12 @@ func (s *PackageSuite) TestMatchesDependency(c *C) { // Provides c.Check(p.MatchesDependency(Dependency{Pkg: "game", Relation: VersionDontCare}), Equals, false) - p.Provides = []string{"fun", "game"} + p.Provides = []string{"fun (= 42)", "game"} c.Check(p.MatchesDependency(Dependency{Pkg: "game", Relation: VersionDontCare}), Equals, true) c.Check(p.MatchesDependency(Dependency{Pkg: "game", Architecture: "amd64", Relation: VersionDontCare}), Equals, false) + c.Check(p.MatchesDependency(Dependency{Pkg: "fun", Relation: VersionDontCare}), Equals, true) + c.Check(p.MatchesDependency(Dependency{Pkg: "fun", Relation: VersionGreaterOrEqual, Version: "42"}), Equals, true) + c.Check(p.MatchesDependency(Dependency{Pkg: "fun", Relation: VersionLess, Version: "42"}), Equals, false) } func (s *PackageSuite) TestGetDependencies(c *C) { diff --git a/deb/publish.go b/deb/publish.go index 7a7bab88..79c47cb8 100644 --- a/deb/publish.go +++ b/deb/publish.go @@ -5,7 +5,6 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" "log" "os" "path/filepath" @@ -44,6 +43,7 @@ type PublishedRepo struct { ButAutomaticUpgrades string Label string Suite string + Codename string // Architectures is a list of all architectures published Architectures []string // SourceKind is "local"/"repo" @@ -70,6 +70,9 @@ type PublishedRepo struct { // Provide index files per hash also AcquireByHash bool + + // Support multiple distributions + MultiDist bool } // ParsePrefix splits [storage:]prefix into components @@ -153,13 +156,14 @@ func walkUpTree(source interface{}, collectionFactory *CollectionFactory) (rootD // distribution and architectures are user-defined properties // components & sources are lists of component to source mapping (*Snapshot or *LocalRepo) func NewPublishedRepo(storage, prefix, distribution string, architectures []string, - components []string, sources []interface{}, collectionFactory *CollectionFactory) (*PublishedRepo, error) { + components []string, sources []interface{}, collectionFactory *CollectionFactory, multiDist bool) (*PublishedRepo, error) { result := &PublishedRepo{ UUID: uuid.New(), Storage: storage, Architectures: architectures, Sources: make(map[string]string), sourceItems: make(map[string]repoSourceItem), + MultiDist: multiDist, } if len(sources) == 0 { @@ -197,9 +201,6 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri if distribution == "" || component == "" { rootDistributions, rootComponents := walkUpTree(source, collectionFactory) if distribution == "" { - for i := range rootDistributions { - rootDistributions[i] = strings.Replace(rootDistributions[i], "/", "-", -1) - } discoveredDistributions = append(discoveredDistributions, rootDistributions...) } if component == "" { @@ -264,10 +265,6 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri } } - if strings.Contains(distribution, "/") { - return nil, fmt.Errorf("invalid distribution %s, '/' is not allowed", distribution) - } - result.Distribution = distribution // only fields which are unique by all given snapshots are set on published @@ -284,7 +281,7 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri return result, nil } -// MarshalJSON requires object to be "loaded completely" +// MarshalJSON requires object to filled by "LoadShallow" or "LoadComplete" func (p *PublishedRepo) MarshalJSON() ([]byte, error) { type sourceInfo struct { Component, Name string @@ -312,6 +309,7 @@ func (p *PublishedRepo) MarshalJSON() ([]byte, error) { "Label": p.Label, "Origin": p.Origin, "Suite": p.Suite, + "Codename": p.Codename, "NotAutomatic": p.NotAutomatic, "ButAutomaticUpgrades": p.ButAutomaticUpgrades, "Prefix": p.Prefix, @@ -321,6 +319,7 @@ func (p *PublishedRepo) MarshalJSON() ([]byte, error) { "Storage": p.Storage, "SkipContents": p.SkipContents, "AcquireByHash": p.AcquireByHash, + "MultiDist": p.MultiDist, }) } @@ -366,6 +365,10 @@ func (p *PublishedRepo) String() string { extras = append(extras, fmt.Sprintf("suite: %s", p.Suite)) } + if p.Codename != "" { + extras = append(extras, fmt.Sprintf("codename: %s", p.Codename)) + } + extra = strings.Join(extras, ", ") if extra != "" { @@ -418,6 +421,29 @@ func (p *PublishedRepo) Components() []string { return result } +// Components returns sorted list of published repo source names +func (p *PublishedRepo) SourceNames() []string { + var sources = []string{} + + for _, component := range p.Components() { + var source string + + item := p.sourceItems[component] + if item.snapshot != nil { + source = item.snapshot.Name + } else if item.localRepo != nil { + source = item.localRepo.Name + } else { + panic("no snapshot/localRepo") + } + + sources = append(sources, fmt.Sprintf("%s:%s", source, component)) + } + + sort.Strings(sources) + return sources +} + // UpdateLocalRepo updates content from local repo in component func (p *PublishedRepo) UpdateLocalRepo(component string) { if p.SourceKind != SourceLocalRepo { @@ -437,7 +463,10 @@ func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) { panic("not snapshot publish") } - item := p.sourceItems[component] + item, exists := p.sourceItems[component] + if !exists { + item = repoSourceItem{} + } item.snapshot = snapshot p.sourceItems[component] = item @@ -513,6 +542,14 @@ func (p *PublishedRepo) GetSuite() string { return p.Suite } +// GetCodename returns default or manual Codename: +func (p *PublishedRepo) GetCodename() string { + if p.Codename == "" { + return p.Distribution + } + return p.Codename +} + // Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider, collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool) error { @@ -582,7 +619,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP } var tempDir string - tempDir, err = ioutil.TempDir(os.TempDir(), "aptly") + tempDir, err = os.MkdirTemp(os.TempDir(), "aptly") if err != nil { return err } @@ -605,7 +642,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP // For all architectures, pregenerate packages/sources files for _, arch := range p.Architectures { - indexes.PackageIndex(component, arch, false, false) + indexes.PackageIndex(component, arch, false, false, p.Distribution) } list.PrepareIndex() @@ -627,9 +664,18 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP if err2 != nil { return err2 } - relPath = filepath.Join("pool", component, poolDir) + if p.MultiDist { + relPath = filepath.Join("pool", p.Distribution, component, poolDir) + } else { + relPath = filepath.Join("pool", component, poolDir) + } + } else { - relPath = filepath.Join("dists", p.Distribution, component, fmt.Sprintf("%s-%s", pkg.Name, arch), "current", "images") + if p.Distribution == aptly.DistributionFocal { + relPath = filepath.Join("dists", p.Distribution, component, fmt.Sprintf("%s-%s", pkg.Name, arch), "current", "legacy-images") + } else { + relPath = filepath.Join("dists", p.Distribution, component, fmt.Sprintf("%s-%s", pkg.Name, arch), "current", "images") + } } err = pkg.LinkFromPool(publishedStorage, packagePool, p.Prefix, relPath, forceOverwrite) @@ -667,7 +713,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP } } - bufWriter, err = indexes.PackageIndex(component, arch, pkg.IsUdeb, pkg.IsInstaller).BufWriter() + bufWriter, err = indexes.PackageIndex(component, arch, pkg.IsUdeb, pkg.IsInstaller, p.Distribution).BufWriter() if err != nil { return err } @@ -721,7 +767,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP // For all architectures, pregenerate .udeb indexes for _, arch := range p.Architectures { - indexes.PackageIndex(component, arch, true, false) + indexes.PackageIndex(component, arch, true, false, p.Distribution) } } @@ -735,6 +781,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP release["Origin"] = p.GetOrigin() release["Label"] = p.GetLabel() release["Suite"] = p.GetSuite() + release["Codename"] = p.GetCodename() if p.AcquireByHash { release["Acquire-By-Hash"] = "yes" } @@ -793,7 +840,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP } release["Label"] = p.GetLabel() release["Suite"] = p.GetSuite() - release["Codename"] = p.Distribution + release["Codename"] = p.GetCodename() release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST") release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{ArchitectureSource}), " ") if p.AcquireByHash { @@ -953,8 +1000,11 @@ func (collection *PublishedRepoCollection) Update(repo *PublishedRepo) error { return batch.Write() } -// LoadComplete loads additional information for remote repo -func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) { +// LoadShallow loads basic information on the repo's sources +// +// This does not *fully* load in the sources themselves and their packages. +// It's useful if you just want to use JSON serialization without loading in unnecessary things. +func (collection *PublishedRepoCollection) LoadShallow(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) { repo.sourceItems = make(map[string]repoSourceItem) if repo.SourceKind == SourceSnapshot { @@ -965,10 +1015,6 @@ func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, col if err != nil { return } - err = collectionFactory.SnapshotCollection().LoadComplete(item.snapshot) - if err != nil { - return - } repo.sourceItems[component] = item } @@ -980,6 +1026,30 @@ func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, col if err != nil { return } + + item.packageRefs = &PackageRefList{} + repo.sourceItems[component] = item + } + } else { + panic("unknown SourceKind") + } + + return +} + +// LoadComplete loads complete information on the sources of the repo *and* their packages +func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) { + collection.LoadShallow(repo, collectionFactory) + + if repo.SourceKind == SourceSnapshot { + for _, item := range repo.sourceItems { + err = collectionFactory.SnapshotCollection().LoadComplete(item.snapshot) + if err != nil { + return + } + } + } else if repo.SourceKind == SourceLocalRepo { + for component, item := range repo.sourceItems { err = collectionFactory.LocalRepoCollection().LoadComplete(item.localRepo) if err != nil { return @@ -998,13 +1068,10 @@ func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, col } } - item.packageRefs = &PackageRefList{} err = item.packageRefs.Decode(encoded) if err != nil { return } - - repo.sourceItems[component] = item } } else { panic("unknown SourceKind") @@ -1086,7 +1153,7 @@ func (collection *PublishedRepoCollection) ByLocalRepo(repo *LocalRepo) []*Publi // ForEach runs method for each repository func (collection *PublishedRepoCollection) ForEach(handler func(*PublishedRepo) error) error { - return collection.db.ProcessByPrefix([]byte("U"), func(key, blob []byte) error { + return collection.db.ProcessByPrefix([]byte("U"), func(_, blob []byte) error { r := &PublishedRepo{} if err := r.Decode(blob); err != nil { log.Printf("Error decoding published repo: %s\n", err) @@ -1104,18 +1171,10 @@ func (collection *PublishedRepoCollection) Len() int { return len(collection.list) } -// CleanupPrefixComponentFiles removes all unreferenced files in published storage under prefix/component pair -func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix string, components []string, - publishedStorage aptly.PublishedStorage, collectionFactory *CollectionFactory, progress aptly.Progress) error { - - collection.loadList() - - var err error +func (collection *PublishedRepoCollection) listReferencedFilesByComponent(prefix string, components []string, + collectionFactory *CollectionFactory, progress aptly.Progress) (map[string][]string, error) { referencedFiles := map[string][]string{} - - if progress != nil { - progress.Printf("Cleaning up prefix %#v components %s...\n", prefix, strings.Join(components, ", ")) - } + processedComponentRefs := map[string]*PackageRefList{} for _, r := range collection.list { if r.Prefix == prefix { @@ -1134,16 +1193,28 @@ func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix st continue } - err = collection.LoadComplete(r, collectionFactory) - if err != nil { - return err + if err := collection.LoadComplete(r, collectionFactory); err != nil { + return nil, err } for _, component := range components { if utils.StrSliceHasItem(repoComponents, component) { - packageList, err := NewPackageListFromRefList(r.RefList(component), collectionFactory.PackageCollection(), progress) + unseenRefs := r.RefList(component) + processedRefs := processedComponentRefs[component] + if processedRefs != nil { + unseenRefs = unseenRefs.Subtract(processedRefs) + } else { + processedRefs = NewPackageRefList() + } + + if unseenRefs.Len() == 0 { + continue + } + processedComponentRefs[component] = processedRefs.Merge(unseenRefs, false, true) + + packageList, err := NewPackageListFromRefList(unseenRefs, collectionFactory.PackageCollection(), progress) if err != nil { - return err + return nil, err } packageList.ForEach(func(p *Package) error { @@ -1163,6 +1234,24 @@ func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix st } } + return referencedFiles, nil +} + +// CleanupPrefixComponentFiles removes all unreferenced files in published storage under prefix/component pair +func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix string, components []string, + publishedStorage aptly.PublishedStorage, collectionFactory *CollectionFactory, progress aptly.Progress) error { + + collection.loadList() + + if progress != nil { + progress.Printf("Cleaning up prefix %#v components %s...\n", prefix, strings.Join(components, ", ")) + } + + referencedFiles, err := collection.listReferencedFilesByComponent(prefix, components, collectionFactory, progress) + if err != nil { + return err + } + for _, component := range components { sort.Strings(referencedFiles[component]) diff --git a/deb/publish_bench_test.go b/deb/publish_bench_test.go new file mode 100644 index 00000000..86f18c30 --- /dev/null +++ b/deb/publish_bench_test.go @@ -0,0 +1,113 @@ +package deb + +import ( + "fmt" + "os" + "sort" + "testing" + + "github.com/aptly-dev/aptly/database/goleveldb" +) + +func BenchmarkListReferencedFiles(b *testing.B) { + const defaultComponent = "main" + const repoCount = 16 + const repoPackagesCount = 1024 + const uniqPackagesCount = 64 + + tmpDir, err := os.MkdirTemp("", "aptly-bench") + if err != nil { + b.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + db, err := goleveldb.NewOpenDB(tmpDir) + if err != nil { + b.Fatal(err) + } + defer db.Close() + + factory := NewCollectionFactory(db) + packageCollection := factory.PackageCollection() + repoCollection := factory.LocalRepoCollection() + publishCollection := factory.PublishedRepoCollection() + + sharedRefs := NewPackageRefList() + { + transaction, err := db.OpenTransaction() + if err != nil { + b.Fatal(err) + } + + for pkgIndex := 0; pkgIndex < repoPackagesCount-uniqPackagesCount; pkgIndex++ { + p := &Package{ + Name: fmt.Sprintf("pkg-shared_%d", pkgIndex), + Version: "1", + Architecture: "amd64", + } + p.UpdateFiles(PackageFiles{PackageFile{ + Filename: fmt.Sprintf("pkg-shared_%d.deb", pkgIndex), + }}) + + packageCollection.UpdateInTransaction(p, transaction) + sharedRefs.Refs = append(sharedRefs.Refs, p.Key("")) + } + + sort.Sort(sharedRefs) + + if err := transaction.Commit(); err != nil { + b.Fatal(err) + } + } + + for repoIndex := 0; repoIndex < repoCount; repoIndex++ { + refs := NewPackageRefList() + + transaction, err := db.OpenTransaction() + if err != nil { + b.Fatal(err) + } + + for pkgIndex := 0; pkgIndex < uniqPackagesCount; pkgIndex++ { + p := &Package{ + Name: fmt.Sprintf("pkg%d_%d", repoIndex, pkgIndex), + Version: "1", + Architecture: "amd64", + } + p.UpdateFiles(PackageFiles{PackageFile{ + Filename: fmt.Sprintf("pkg%d_%d.deb", repoIndex, pkgIndex), + }}) + + packageCollection.UpdateInTransaction(p, transaction) + refs.Refs = append(refs.Refs, p.Key("")) + } + + if err := transaction.Commit(); err != nil { + b.Fatal(err) + } + + sort.Sort(refs) + + repo := NewLocalRepo(fmt.Sprintf("repo%d", repoIndex), "comment") + repo.DefaultDistribution = fmt.Sprintf("dist%d", repoIndex) + repo.DefaultComponent = defaultComponent + repo.UpdateRefList(refs.Merge(sharedRefs, false, true)) + repoCollection.Add(repo) + + publish, err := NewPublishedRepo("", "test", "", nil, []string{defaultComponent}, []interface{}{repo}, factory, false) + if err != nil { + b.Fatal(err) + } + publishCollection.Add(publish) + } + + db.CompactDB() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := publishCollection.listReferencedFilesByComponent("test", []string{defaultComponent}, factory, nil) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/deb/publish_test.go b/deb/publish_test.go index 4850720f..5243a41a 100644 --- a/deb/publish_test.go +++ b/deb/publish_test.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/database" @@ -133,19 +134,19 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) { s.packageCollection.Update(s.p2) s.packageCollection.Update(s.p3) - s.repo, _ = NewPublishedRepo("", "ppa", "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory) + s.repo, _ = NewPublishedRepo("", "ppa", "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory, false) s.repo.SkipContents = true - s.repo2, _ = NewPublishedRepo("", "ppa", "maverick", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory) + s.repo2, _ = NewPublishedRepo("", "ppa", "maverick", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) s.repo2.SkipContents = true - s.repo3, _ = NewPublishedRepo("", "linux", "natty", nil, []string{"main", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory) + s.repo3, _ = NewPublishedRepo("", "linux", "natty", nil, []string{"main", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory, false) s.repo3.SkipContents = true - s.repo4, _ = NewPublishedRepo("", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory) + s.repo4, _ = NewPublishedRepo("", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) s.repo4.SkipContents = true - s.repo5, _ = NewPublishedRepo("files:other", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory) + s.repo5, _ = NewPublishedRepo("files:other", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) s.repo5.SkipContents = true } @@ -177,19 +178,71 @@ func (s *PublishedRepoSuite) TestNewPublishedRepo(c *C) { c.Check(s.repo3.RefList("main").Len(), Equals, 3) c.Check(s.repo3.RefList("contrib").Len(), Equals, 3) - c.Check(func() { NewPublishedRepo("", ".", "a", nil, nil, nil, s.factory) }, PanicMatches, "publish with empty sources") + c.Check(func() { NewPublishedRepo("", ".", "a", nil, nil, nil, s.factory, false) }, PanicMatches, "publish with empty sources") c.Check(func() { - NewPublishedRepo("", ".", "a", nil, []string{"main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory) + NewPublishedRepo("", ".", "a", nil, []string{"main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory, false) }, PanicMatches, "sources and components should be equal in size") c.Check(func() { - NewPublishedRepo("", ".", "a", nil, []string{"main", "contrib"}, []interface{}{s.localRepo, s.snapshot2}, s.factory) + NewPublishedRepo("", ".", "a", nil, []string{"main", "contrib"}, []interface{}{s.localRepo, s.snapshot2}, s.factory, false) }, PanicMatches, "interface conversion:.*") - _, err := NewPublishedRepo("", ".", "a", nil, []string{"main", "main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory) + _, err := NewPublishedRepo("", ".", "a", nil, []string{"main", "main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory, false) c.Check(err, ErrorMatches, "duplicate component name: main") - _, err = NewPublishedRepo("", ".", "wheezy/updates", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory) - c.Check(err, ErrorMatches, "invalid distribution wheezy/updates, '/' is not allowed") + _, err = NewPublishedRepo("", ".", "wheezy/updates", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory, false) + c.Check(err, IsNil) +} + +func (s *PublishedRepoSuite) TestMultiDistPool(c *C) { + repo, err := NewPublishedRepo("", "ppa", "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory, true) + c.Assert(err, IsNil) + err = repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false) + c.Assert(err, IsNil) + + publishedStorage := files.NewPublishedStorage(s.root, "", "") + + c.Check(repo.Architectures, DeepEquals, []string{"i386"}) + + rf, err := os.Open(filepath.Join(publishedStorage.PublicPath(), "ppa/dists/squeeze/Release")) + c.Assert(err, IsNil) + + cfr := NewControlFileReader(rf, true, false) + st, err := cfr.ReadStanza() + c.Assert(err, IsNil) + + c.Check(st["Origin"], Equals, "ppa squeeze") + c.Check(st["Components"], Equals, "main") + c.Check(st["Architectures"], Equals, "i386") + + pf, err := os.Open(filepath.Join(publishedStorage.PublicPath(), "ppa/dists/squeeze/main/binary-i386/Packages")) + c.Assert(err, IsNil) + + cfr = NewControlFileReader(pf, false, false) + + for i := 0; i < 3; i++ { + st, err = cfr.ReadStanza() + c.Assert(err, IsNil) + + c.Check(st["Filename"], Equals, "pool/squeeze/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb") + } + + st, err = cfr.ReadStanza() + c.Assert(err, IsNil) + c.Assert(st, IsNil) + + drf, err := os.Open(filepath.Join(publishedStorage.PublicPath(), "ppa/dists/squeeze/main/binary-i386/Release")) + c.Assert(err, IsNil) + + cfr = NewControlFileReader(drf, true, false) + st, err = cfr.ReadStanza() + c.Assert(err, IsNil) + + c.Check(st["Archive"], Equals, "squeeze") + c.Check(st["Architecture"], Equals, "i386") + + _, err = os.Stat(filepath.Join(publishedStorage.PublicPath(), "ppa/pool/squeeze/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb")) + c.Assert(err, IsNil) + } func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) { @@ -248,7 +301,7 @@ func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) { errorExpected: "invalid prefix .*", }, } { - repo, err := NewPublishedRepo("", t.prefix, "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory) + repo, err := NewPublishedRepo("", t.prefix, "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory, false) if t.errorExpected != "" { c.Check(err, ErrorMatches, t.errorExpected) } else { @@ -258,51 +311,51 @@ func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) { } func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) { - repo, err := NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.snapshot}, s.factory) + repo, err := NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.snapshot}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Components(), DeepEquals, []string{"main"}) - repo, err = NewPublishedRepo("", "ppa", "wheezy", nil, []string{""}, []interface{}{s.snapshot}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "wheezy", nil, []string{""}, []interface{}{s.snapshot}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "wheezy") c.Check(repo.Components(), DeepEquals, []string{"main"}) - repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"non-free"}, []interface{}{s.snapshot}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"non-free"}, []interface{}{s.snapshot}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Components(), DeepEquals, []string{"non-free"}) - repo, err = NewPublishedRepo("", "ppa", "squeeze", nil, []string{""}, []interface{}{s.localRepo}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "squeeze", nil, []string{""}, []interface{}{s.localRepo}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Components(), DeepEquals, []string{"main"}) - _, err = NewPublishedRepo("", "ppa", "", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory) + _, err = NewPublishedRepo("", "ppa", "", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) c.Check(err, ErrorMatches, "unable to guess distribution name, please specify explicitly") s.localRepo.DefaultDistribution = "precise" s.localRepo.DefaultComponent = "contrib" s.factory.LocalRepoCollection().Update(s.localRepo) - repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "precise") c.Check(repo.Components(), DeepEquals, []string{"contrib"}) s.localRepo.DefaultDistribution = "precise/updates" - repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory, false) c.Check(err, IsNil) - c.Check(repo.Distribution, Equals, "precise-updates") + c.Check(repo.Distribution, Equals, "precise/updates") c.Check(repo.Components(), DeepEquals, []string{"contrib"}) - repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory) + repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory, false) c.Check(err, IsNil) c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Components(), DeepEquals, []string{"contrib", "main"}) - _, err = NewPublishedRepo("", "ppa", "", nil, []string{"", ""}, []interface{}{s.snapshot, s.snapshot2}, s.factory) + _, err = NewPublishedRepo("", "ppa", "", nil, []string{"", ""}, []interface{}{s.snapshot, s.snapshot2}, s.factory, false) c.Check(err, ErrorMatches, "duplicate component name: main") } @@ -390,10 +443,10 @@ func (s *PublishedRepoSuite) TestString(c *C) { "ppa/squeeze [] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}") c.Check(s.repo2.String(), Equals, "ppa/maverick [] publishes {main: [local1]: comment1}") - repo, _ := NewPublishedRepo("", "", "squeeze", []string{"s390"}, []string{"main"}, []interface{}{s.snapshot}, s.factory) + repo, _ := NewPublishedRepo("", "", "squeeze", []string{"s390"}, []string{"main"}, []interface{}{s.snapshot}, s.factory, false) c.Check(repo.String(), Equals, "./squeeze [s390] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}") - repo, _ = NewPublishedRepo("", "", "squeeze", []string{"i386", "amd64"}, []string{"main"}, []interface{}{s.snapshot}, s.factory) + repo, _ = NewPublishedRepo("", "", "squeeze", []string{"i386", "amd64"}, []string{"main"}, []interface{}{s.snapshot}, s.factory, false) c.Check(repo.String(), Equals, "./squeeze [i386, amd64] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}") repo.Origin = "myorigin" @@ -450,13 +503,22 @@ type PublishedRepoCollectionSuite struct { var _ = Suite(&PublishedRepoCollectionSuite{}) func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) { + s.SetUpPackages() + s.db, _ = goleveldb.NewOpenDB(c.MkDir()) s.factory = NewCollectionFactory(s.db) s.snapshotCollection = s.factory.SnapshotCollection() - s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1") - s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2") + snap1Refs := NewPackageRefList() + snap1Refs.Refs = [][]byte{s.p1.Key(""), s.p2.Key("")} + sort.Sort(snap1Refs) + s.snap1 = NewSnapshotFromRefList("snap1", []*Snapshot{}, snap1Refs, "desc1") + + snap2Refs := NewPackageRefList() + snap2Refs.Refs = [][]byte{s.p3.Key("")} + sort.Sort(snap2Refs) + s.snap2 = NewSnapshotFromRefList("snap2", []*Snapshot{}, snap2Refs, "desc2") s.snapshotCollection.Add(s.snap1) s.snapshotCollection.Add(s.snap2) @@ -464,11 +526,11 @@ func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) { s.localRepo = NewLocalRepo("local1", "comment1") s.factory.LocalRepoCollection().Add(s.localRepo) - s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory) - s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main", "contrib"}, []interface{}{s.snap2, s.snap1}, s.factory) - s.repo3, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap2}, s.factory) - s.repo4, _ = NewPublishedRepo("", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory) - s.repo5, _ = NewPublishedRepo("files:other", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory) + s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory, false) + s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main", "contrib"}, []interface{}{s.snap2, s.snap1}, s.factory, false) + s.repo3, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap2}, s.factory, false) + s.repo4, _ = NewPublishedRepo("", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) + s.repo5, _ = NewPublishedRepo("files:other", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory, false) s.collection = s.factory.PublishedRepoCollection() } @@ -534,7 +596,7 @@ func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) { c.Assert(r.sourceItems["main"].snapshot, IsNil) c.Assert(s.collection.LoadComplete(r, s.factory), IsNil) c.Assert(r.Sources["main"], Equals, s.repo1.sourceItems["main"].snapshot.UUID) - c.Assert(r.RefList("main").Len(), Equals, 0) + c.Assert(r.RefList("main").Len(), Equals, 2) r, err = collection.ByStoragePrefixDistribution("", "ppa", "precise") c.Assert(err, IsNil) @@ -625,6 +687,51 @@ func (s *PublishedRepoCollectionSuite) TestByLocalRepo(c *C) { c.Check(s.collection.ByLocalRepo(s.localRepo), DeepEquals, []*PublishedRepo{s.repo4, s.repo5}) } +func (s *PublishedRepoCollectionSuite) TestListReferencedFiles(c *C) { + c.Check(s.factory.PackageCollection().Update(s.p1), IsNil) + c.Check(s.factory.PackageCollection().Update(s.p2), IsNil) + c.Check(s.factory.PackageCollection().Update(s.p3), IsNil) + + c.Check(s.collection.Add(s.repo1), IsNil) + c.Check(s.collection.Add(s.repo2), IsNil) + c.Check(s.collection.Add(s.repo4), IsNil) + c.Check(s.collection.Add(s.repo5), IsNil) + + files, err := s.collection.listReferencedFilesByComponent(".", []string{"main", "contrib"}, s.factory, nil) + c.Assert(err, IsNil) + for _, v := range files { + sort.Strings(v) + } + c.Check(files, DeepEquals, map[string][]string{ + "contrib": { + "a/alien-arena/alien-arena-common_7.40-2_i386.deb", + "a/alien-arena/mars-invaders_7.40-2_i386.deb", + }, + "main": {"a/alien-arena/lonely-strangers_7.40-2_i386.deb"}, + }) + + snap3 := NewSnapshotFromRefList("snap3", []*Snapshot{}, s.snap2.RefList(), "desc3") + s.snapshotCollection.Add(snap3) + + // Ensure that adding a second publish point with matching files doesn't give duplicate results. + repo3, err := NewPublishedRepo("", "", "anaconda-2", []string{}, []string{"main"}, []interface{}{snap3}, s.factory, false) + c.Check(err, IsNil) + c.Check(s.collection.Add(repo3), IsNil) + + files, err = s.collection.listReferencedFilesByComponent(".", []string{"main", "contrib"}, s.factory, nil) + c.Assert(err, IsNil) + for _, v := range files { + sort.Strings(v) + } + c.Check(files, DeepEquals, map[string][]string{ + "contrib": { + "a/alien-arena/alien-arena-common_7.40-2_i386.deb", + "a/alien-arena/mars-invaders_7.40-2_i386.deb", + }, + "main": {"a/alien-arena/lonely-strangers_7.40-2_i386.deb"}, + }) +} + type PublishedRepoRemoveSuite struct { PackageListMixinSuite db database.Storage @@ -650,11 +757,11 @@ func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) { s.snapshotCollection.Add(s.snap1) - s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory) - s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory) - s.repo3, _ = NewPublishedRepo("", "ppa", "meduza", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory) - s.repo4, _ = NewPublishedRepo("", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory) - s.repo5, _ = NewPublishedRepo("files:other", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory) + s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory, false) + s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory, false) + s.repo3, _ = NewPublishedRepo("", "ppa", "meduza", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory, false) + s.repo4, _ = NewPublishedRepo("", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory, false) + s.repo5, _ = NewPublishedRepo("files:other", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory, false) s.collection = s.factory.PublishedRepoCollection() s.collection.Add(s.repo1) diff --git a/deb/query.go b/deb/query.go index 19a1cdc9..1de9e95b 100644 --- a/deb/query.go +++ b/deb/query.go @@ -138,7 +138,7 @@ func (q *NotQuery) Matches(pkg PackageLike) bool { } // Fast is false -func (q *NotQuery) Fast(list PackageCatalog) bool { +func (q *NotQuery) Fast(_ PackageCatalog) bool { return false } @@ -197,7 +197,7 @@ func (q *FieldQuery) Query(list PackageCatalog) (result *PackageList) { } // Fast depends on the query -func (q *FieldQuery) Fast(list PackageCatalog) bool { +func (q *FieldQuery) Fast(_ PackageCatalog) bool { return false } @@ -265,7 +265,7 @@ func (q *PkgQuery) Matches(pkg PackageLike) bool { } // Fast is always true for package query -func (q *PkgQuery) Fast(list PackageCatalog) bool { +func (q *PkgQuery) Fast(_ PackageCatalog) bool { return true } @@ -280,12 +280,12 @@ func (q *PkgQuery) String() string { } // Matches on specific properties -func (q *MatchAllQuery) Matches(pkg PackageLike) bool { +func (q *MatchAllQuery) Matches(_ PackageLike) bool { return true } // Fast is always true for match all query -func (q *MatchAllQuery) Fast(list PackageCatalog) bool { +func (q *MatchAllQuery) Fast(_ PackageCatalog) bool { return true } diff --git a/deb/reflist.go b/deb/reflist.go index 187475dd..30396548 100644 --- a/deb/reflist.go +++ b/deb/reflist.go @@ -71,7 +71,9 @@ func (l *PackageRefList) Encode() []byte { // Decode decodes msgpack representation into PackageRefLit func (l *PackageRefList) Decode(input []byte) error { - decoder := codec.NewDecoderBytes(input, &codec.MsgpackHandle{}) + handle := &codec.MsgpackHandle{} + handle.ZeroCopy = true + decoder := codec.NewDecoderBytes(input, handle) return decoder.Decode(l) } @@ -194,31 +196,21 @@ func (l *PackageRefList) Diff(r *PackageRefList, packageCollection *PackageColle // until we reached end of both lists for il < ll || ir < lr { - // if we've exhausted left list, pull the rest from the right - if il == ll { - pr, err = packageCollection.ByKey(r.Refs[ir]) - if err != nil { - return nil, err - } - result = append(result, PackageDiff{Left: nil, Right: pr}) - ir++ - continue + var rl, rr []byte + if il < ll { + rl = l.Refs[il] } - // if we've exhausted right list, pull the rest from the left - if ir == lr { - pl, err = packageCollection.ByKey(l.Refs[il]) - if err != nil { - return nil, err - } - result = append(result, PackageDiff{Left: pl, Right: nil}) - il++ - continue + if ir < lr { + rr = r.Refs[ir] } - // refs on both sides are present, load them - rl, rr := l.Refs[il], r.Refs[ir] // compare refs rel := bytes.Compare(rl, rr) + // an unset ref is less than all others, but since it represents the end + // of a reflist, it should be *greater*, so flip the comparison result + if rl == nil || rr == nil { + rel = -rel + } if rel == 0 { // refs are identical, so are packages, advance pointer @@ -227,14 +219,14 @@ func (l *PackageRefList) Diff(r *PackageRefList, packageCollection *PackageColle pl, pr = nil, nil } else { // load pl & pr if they haven't been loaded before - if pl == nil { + if pl == nil && rl != nil { pl, err = packageCollection.ByKey(rl) if err != nil { return nil, err } } - if pr == nil { + if pr == nil && rr != nil { pr, err = packageCollection.ByKey(rr) if err != nil { return nil, err @@ -310,38 +302,41 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching, ignoreConfli overridenName = nil overriddenArch = nil } else { - partsL := bytes.Split(rl, []byte(" ")) - archL, nameL, versionL := partsL[0][1:], partsL[1], partsL[2] + if !ignoreConflicting || overrideMatching { + partsL := bytes.Split(rl, []byte(" ")) + archL, nameL, versionL := partsL[0][1:], partsL[1], partsL[2] - partsR := bytes.Split(rr, []byte(" ")) - archR, nameR, versionR := partsR[0][1:], partsR[1], partsR[2] + partsR := bytes.Split(rr, []byte(" ")) + archR, nameR, versionR := partsR[0][1:], partsR[1], partsR[2] - if !ignoreConflicting && bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) && bytes.Equal(versionL, versionR) { - // conflicting duplicates with same arch, name, version, but different file hash - result.Refs = append(result.Refs, r.Refs[ir]) - il++ - ir++ - overridenName = nil - overriddenArch = nil - continue - } - - if overrideMatching { - if bytes.Equal(archL, overriddenArch) && bytes.Equal(nameL, overridenName) { - // this package has already been overridden on the right - il++ - continue - } - - if bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) { - // override with package from the right + if !ignoreConflicting && bytes.Equal(archL, archR) && + bytes.Equal(nameL, nameR) && bytes.Equal(versionL, versionR) { + // conflicting duplicates with same arch, name, version, but different file hash result.Refs = append(result.Refs, r.Refs[ir]) il++ ir++ - overriddenArch = archL - overridenName = nameL + overridenName = nil + overriddenArch = nil continue } + + if overrideMatching { + if bytes.Equal(archL, overriddenArch) && bytes.Equal(nameL, overridenName) { + // this package has already been overridden on the right + il++ + continue + } + + if bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) { + // override with package from the right + result.Refs = append(result.Refs, r.Refs[ir]) + il++ + ir++ + overriddenArch = archL + overridenName = nameL + continue + } + } } // otherwise append smallest of two diff --git a/deb/reflist_bench_test.go b/deb/reflist_bench_test.go new file mode 100644 index 00000000..b377574c --- /dev/null +++ b/deb/reflist_bench_test.go @@ -0,0 +1,47 @@ +package deb + +import ( + "fmt" + "sort" + "testing" +) + +func BenchmarkReflistSimpleMerge(b *testing.B) { + const count = 4096 + + l := NewPackageRefList() + r := NewPackageRefList() + + for i := 0; i < count; i++ { + if i%2 == 0 { + l.Refs = append(l.Refs, []byte(fmt.Sprintf("Pamd64 pkg%d %d", i, i))) + } else { + r.Refs = append(r.Refs, []byte(fmt.Sprintf("Pamd64 pkg%d %d", i, i))) + } + } + + sort.Sort(l) + sort.Sort(r) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + l.Merge(r, false, true) + } +} + +func BenchmarkReflistDecode(b *testing.B) { + const count = 4096 + + r := NewPackageRefList() + for i := 0; i < count; i++ { + r.Refs = append(r.Refs, []byte(fmt.Sprintf("Pamd64 pkg%d %d", i, i))) + } + + sort.Sort(r) + data := r.Encode() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + (&PackageRefList{}).Decode(data) + } +} diff --git a/deb/reflist_test.go b/deb/reflist_test.go index d0ce21f5..ec7ed09f 100644 --- a/deb/reflist_test.go +++ b/deb/reflist_test.go @@ -237,6 +237,41 @@ func (s *PackageRefListSuite) TestDiff(c *C) { } +func (s *PackageRefListSuite) TestDiffCompactsAtEnd(c *C) { + db, _ := goleveldb.NewOpenDB(c.MkDir()) + coll := NewPackageCollection(db) + + packages := []*Package{ + {Name: "app", Version: "1.1~bp1", Architecture: "i386"}, //0 + {Name: "app", Version: "1.1~bp2", Architecture: "i386"}, //1 + {Name: "app", Version: "1.1~bp2", Architecture: "amd64"}, //2 + } + + for _, p := range packages { + coll.Update(p) + } + + listA := NewPackageList() + listA.Add(packages[0]) + + listB := NewPackageList() + listB.Add(packages[1]) + listB.Add(packages[2]) + + reflistA := NewPackageRefListFromPackageList(listA) + reflistB := NewPackageRefListFromPackageList(listB) + + diffAB, err := reflistA.Diff(reflistB, coll) + c.Check(err, IsNil) + c.Check(diffAB, HasLen, 2) + + c.Check(diffAB[0].Left, IsNil) + c.Check(diffAB[0].Right.String(), Equals, "app_1.1~bp2_amd64") + + c.Check(diffAB[1].Left.String(), Equals, "app_1.1~bp1_i386") + c.Check(diffAB[1].Right.String(), Equals, "app_1.1~bp2_i386") +} + func (s *PackageRefListSuite) TestMerge(c *C) { db, _ := goleveldb.NewOpenDB(c.MkDir()) coll := NewPackageCollection(db) diff --git a/deb/remote.go b/deb/remote.go index 6d30e999..6ecb7e80 100644 --- a/deb/remote.go +++ b/deb/remote.go @@ -259,6 +259,9 @@ func (repo *RemoteRepo) UdebPath(component string, architecture string) string { // InstallerPath returns path of Packages files for given component and // architecture func (repo *RemoteRepo) InstallerPath(component string, architecture string) string { + if repo.Distribution == aptly.DistributionFocal { + return fmt.Sprintf("%s/installer-%s/current/legacy-images/SHA256SUMS", component, architecture) + } return fmt.Sprintf("%s/installer-%s/current/images/SHA256SUMS", component, architecture) } @@ -270,17 +273,29 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL { } // Fetch updates information about repository -func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier pgp.Verifier) error { +func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier pgp.Verifier, ignoreSignatures bool) error { var ( release, inrelease, releasesig *os.File err error ) - if verifier == nil { + if ignoreSignatures { // 0. Just download release file to temporary URL release, err = http.DownloadTemp(gocontext.TODO(), d, repo.ReleaseURL("Release").String()) if err != nil { - return err + // 0.1 try downloading InRelease, ignore and strip signature + inrelease, err = http.DownloadTemp(gocontext.TODO(), d, repo.ReleaseURL("InRelease").String()) + if err != nil { + return err + } + if verifier == nil { + return fmt.Errorf("no verifier specified") + } + release, err = verifier.ExtractClearsigned(inrelease) + if err != nil { + return err + } + goto ok } } else { // 1. try InRelease file @@ -428,8 +443,7 @@ ok: } // DownloadPackageIndexes downloads & parses package index files -func (repo *RemoteRepo) DownloadPackageIndexes(progress aptly.Progress, d aptly.Downloader, verifier pgp.Verifier, collectionFactory *CollectionFactory, - ignoreMismatch bool) error { +func (repo *RemoteRepo) DownloadPackageIndexes(progress aptly.Progress, d aptly.Downloader, verifier pgp.Verifier, _ *CollectionFactory, ignoreSignatures bool, ignoreChecksums bool) error { if repo.packageList != nil { panic("packageList != nil") } @@ -462,14 +476,14 @@ func (repo *RemoteRepo) DownloadPackageIndexes(progress aptly.Progress, d aptly. for _, info := range packagesPaths { path, kind, component, architecture := info[0], info[1], info[2], info[3] - packagesReader, packagesFile, err := http.DownloadTryCompression(gocontext.TODO(), d, repo.IndexesRootURL(), path, repo.ReleaseFiles, ignoreMismatch) + packagesReader, packagesFile, err := http.DownloadTryCompression(gocontext.TODO(), d, repo.IndexesRootURL(), path, repo.ReleaseFiles, ignoreChecksums) isInstaller := kind == PackageTypeInstaller if err != nil { if _, ok := err.(*http.NoCandidateFoundError); isInstaller && ok { // checking if gpg file is only needed when checksums matches are required. // otherwise there actually has been no candidate found and we can continue - if ignoreMismatch { + if ignoreChecksums { continue } @@ -486,7 +500,7 @@ func (repo *RemoteRepo) DownloadPackageIndexes(progress aptly.Progress, d aptly. return err } - if verifier != nil { + if verifier != nil && !ignoreSignatures { hashsumGpgPath := repo.IndexesRootURL().ResolveReference(&url.URL{Path: path + ".gpg"}).String() var filesig *os.File filesig, err = http.DownloadTemp(gocontext.TODO(), d, hashsumGpgPath) @@ -777,7 +791,7 @@ func (collection *RemoteRepoCollection) search(filter func(*RemoteRepo) bool, un return result } - collection.db.ProcessByPrefix([]byte("R"), func(key, blob []byte) error { + collection.db.ProcessByPrefix([]byte("R"), func(_, blob []byte) error { r := &RemoteRepo{} if err := r.Decode(blob); err != nil { log.Printf("Error decoding remote repo: %s\n", err) @@ -880,7 +894,7 @@ func (collection *RemoteRepoCollection) ByUUID(uuid string) (*RemoteRepo, error) // ForEach runs method for each repository func (collection *RemoteRepoCollection) ForEach(handler func(*RemoteRepo) error) error { - return collection.db.ProcessByPrefix([]byte("R"), func(key, blob []byte) error { + return collection.db.ProcessByPrefix([]byte("R"), func(_, blob []byte) error { r := &RemoteRepo{} if err := r.Decode(blob); err != nil { log.Printf("Error decoding mirror: %s\n", err) diff --git a/deb/remote_test.go b/deb/remote_test.go index 1ea1d558..2cda7d5e 100644 --- a/deb/remote_test.go +++ b/deb/remote_test.go @@ -3,7 +3,6 @@ package deb import ( "errors" "io" - "io/ioutil" "os" "sort" @@ -22,7 +21,7 @@ import ( type NullVerifier struct { } -func (n *NullVerifier) InitKeyring() error { +func (n *NullVerifier) InitKeyring(_ bool) error { return nil } @@ -38,7 +37,7 @@ func (n *NullVerifier) VerifyClearsigned(clearsigned io.Reader, hint bool) (*pgp } func (n *NullVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, err error) { - text, _ = ioutil.TempFile("", "aptly-test") + text, _ = os.CreateTemp("", "aptly-test") io.Copy(text, clearsigned) text.Seek(0, 0) os.Remove(text.Name()) @@ -62,9 +61,11 @@ func (s *PackageListMixinSuite) SetUpPackages() { s.p1 = NewPackageFromControlFile(packageStanza.Copy()) stanza := packageStanza.Copy() stanza["Package"] = "mars-invaders" + stanza["Filename"] = "pool/contrib/m/mars-invaders/mars-invaders_7.40-2_i386.deb" s.p2 = NewPackageFromControlFile(stanza) stanza = packageStanza.Copy() stanza["Package"] = "lonely-strangers" + stanza["Filename"] = "pool/contrib/l/lonely-strangers/lonely-strangers_7.40-2_i386.deb" s.p3 = NewPackageFromControlFile(stanza) s.list.Add(s.p1) @@ -92,7 +93,7 @@ func (s *RemoteRepoSuite) SetUpTest(c *C) { s.repo, _ = NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian", "squeeze", []string{"main"}, []string{}, false, false, false) s.flat, _ = NewRemoteRepo("exp42", "http://repos.express42.com/virool/precise/", "./", []string{}, []string{}, false, false, false) s.downloader = http.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) - s.progress = console.NewProgress() + s.progress = console.NewProgress(false) s.db, _ = goleveldb.NewOpenDB(c.MkDir()) s.collectionFactory = NewCollectionFactory(s.db) s.packagePool = files.NewPackagePool(c.MkDir(), false) @@ -196,7 +197,7 @@ func (s *RemoteRepoSuite) TestPackageURL(c *C) { } func (s *RemoteRepoSuite) TestFetch(c *C) { - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"}) c.Assert(s.repo.Components, DeepEquals, []string{"main"}) @@ -217,7 +218,7 @@ func (s *RemoteRepoSuite) TestFetchNullVerifier1(c *C) { downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release.gpg", "GPG") - err := s.repo.Fetch(downloader, &NullVerifier{}) + err := s.repo.Fetch(downloader, &NullVerifier{}, false) c.Assert(err, IsNil) c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"}) c.Assert(s.repo.Components, DeepEquals, []string{"main"}) @@ -228,7 +229,7 @@ func (s *RemoteRepoSuite) TestFetchNullVerifier2(c *C) { downloader := http.NewFakeDownloader() downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/InRelease", exampleReleaseFile) - err := s.repo.Fetch(downloader, &NullVerifier{}) + err := s.repo.Fetch(downloader, &NullVerifier{}, false) c.Assert(err, IsNil) c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"}) c.Assert(s.repo.Components, DeepEquals, []string{"main"}) @@ -237,13 +238,13 @@ func (s *RemoteRepoSuite) TestFetchNullVerifier2(c *C) { func (s *RemoteRepoSuite) TestFetchWrongArchitecture(c *C) { s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"}, false, false, false) - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*") } func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) { s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"}, false, false, false) - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, ErrorMatches, "component xyz not available in repo.*") } @@ -270,14 +271,14 @@ func (s *RemoteRepoSuite) TestRefKey(c *C) { func (s *RemoteRepoSuite) TestDownload(c *C) { s.repo.Architectures = []string{"i386"} - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages", examplePackagesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -297,14 +298,14 @@ func (s *RemoteRepoSuite) TestDownload(c *C) { // Next call must return an empty download list with option "skip-existing-packages" s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) - err = s.repo.Fetch(s.downloader, nil) + err = s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages", examplePackagesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -318,14 +319,14 @@ func (s *RemoteRepoSuite) TestDownload(c *C) { // Next call must return the download list without option "skip-existing-packages" s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) - err = s.repo.Fetch(s.downloader, nil) + err = s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages", examplePackagesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -343,7 +344,7 @@ func (s *RemoteRepoSuite) TestDownloadWithInstaller(c *C) { s.repo.Architectures = []string{"i386"} s.repo.DownloadInstaller = true - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) @@ -352,7 +353,7 @@ func (s *RemoteRepoSuite) TestDownloadWithInstaller(c *C) { s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/installer-i386/current/images/SHA256SUMS", exampleInstallerHashSumFile) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/installer-i386/current/images/MANIFEST", exampleInstallerManifestFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -386,7 +387,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { s.repo.Architectures = []string{"i386"} s.repo.DownloadSources = true - err := s.repo.Fetch(s.downloader, nil) + err := s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) @@ -396,7 +397,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources", exampleSourcesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -430,7 +431,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { // Next call must return an empty download list with option "skip-existing-packages" s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) - err = s.repo.Fetch(s.downloader, nil) + err = s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) @@ -440,7 +441,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources", exampleSourcesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -455,7 +456,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { // Next call must return the download list without option "skip-existing-packages" s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile) - err = s.repo.Fetch(s.downloader, nil) + err = s.repo.Fetch(s.downloader, nil, true) c.Assert(err, IsNil) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", &http.Error{Code: 404}) @@ -465,7 +466,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) { s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources.gz", &http.Error{Code: 404}) s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/source/Sources", exampleSourcesFile) - err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, false) + err = s.repo.DownloadPackageIndexes(s.progress, s.downloader, nil, s.collectionFactory, true, false) c.Assert(err, IsNil) c.Assert(s.downloader.Empty(), Equals, true) @@ -486,10 +487,10 @@ func (s *RemoteRepoSuite) TestDownloadFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Packages.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Packages", examplePackagesFile) - err := s.flat.Fetch(downloader, nil) + err := s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) @@ -514,10 +515,10 @@ func (s *RemoteRepoSuite) TestDownloadFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Packages.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Packages", examplePackagesFile) - err = s.flat.Fetch(downloader, nil) + err = s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) @@ -536,10 +537,10 @@ func (s *RemoteRepoSuite) TestDownloadFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Packages.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Packages", examplePackagesFile) - err = s.flat.Fetch(downloader, nil) + err = s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) @@ -567,10 +568,10 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Sources.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Sources", exampleSourcesFile) - err := s.flat.Fetch(downloader, nil) + err := s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) @@ -613,10 +614,10 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Sources.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Sources", exampleSourcesFile) - err = s.flat.Fetch(downloader, nil) + err = s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) @@ -639,10 +640,10 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) { downloader.ExpectError("http://repos.express42.com/virool/precise/Sources.xz", &http.Error{Code: 404}) downloader.ExpectResponse("http://repos.express42.com/virool/precise/Sources", exampleSourcesFile) - err = s.flat.Fetch(downloader, nil) + err = s.flat.Fetch(downloader, nil, true) c.Assert(err, IsNil) - err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true) + err = s.flat.DownloadPackageIndexes(s.progress, downloader, nil, s.collectionFactory, true, true) c.Assert(err, IsNil) c.Assert(downloader.Empty(), Equals, true) diff --git a/deb/snapshot.go b/deb/snapshot.go index f351b87f..f2a0d387 100644 --- a/deb/snapshot.go +++ b/deb/snapshot.go @@ -45,7 +45,7 @@ type Snapshot struct { // NewSnapshotFromRepository creates snapshot from current state of repository func NewSnapshotFromRepository(name string, repo *RemoteRepo) (*Snapshot, error) { - if repo.packageRefs == nil { + if repo.packageRefs == nil || repo.packageRefs.Len() == 0 { return nil, errors.New("mirror not updated") } @@ -259,7 +259,7 @@ func (collection *SnapshotCollection) search(filter func(*Snapshot) bool, unique return result } - collection.db.ProcessByPrefix([]byte("S"), func(key, blob []byte) error { + collection.db.ProcessByPrefix([]byte("S"), func(_, blob []byte) error { s := &Snapshot{} if err := s.Decode(blob); err != nil { log.Printf("Error decoding snapshot: %s\n", err) @@ -341,7 +341,7 @@ func (collection *SnapshotCollection) BySnapshotSource(snapshot *Snapshot) []*Sn // ForEach runs method for each snapshot func (collection *SnapshotCollection) ForEach(handler func(*Snapshot) error) error { - return collection.db.ProcessByPrefix([]byte("S"), func(key, blob []byte) error { + return collection.db.ProcessByPrefix([]byte("S"), func(_, blob []byte) error { s := &Snapshot{} if err := s.Decode(blob); err != nil { log.Printf("Error decoding snapshot: %s\n", err) diff --git a/debian/aptly-api.install b/debian/aptly-api.install index e1d67361..05655571 100644 --- a/debian/aptly-api.install +++ b/debian/aptly-api.install @@ -1 +1 @@ -debian/aptly-api.conf etc +debian/aptly.conf etc/ diff --git a/debian/aptly-api.preinst b/debian/aptly-api.preinst new file mode 100644 index 00000000..e2543af1 --- /dev/null +++ b/debian/aptly-api.preinst @@ -0,0 +1,38 @@ +#!/bin/sh +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + if [ -f /etc/aptly-api.conf ]; then + echo "migrating /etc/aptly-api.conf ..." + mv /etc/aptly-api.conf /etc/aptly-api.conf.migrate + fi + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/aptly-api.service b/debian/aptly-api.service index 7a67ed2a..1d1c0c2e 100644 --- a/debian/aptly-api.service +++ b/debian/aptly-api.service @@ -1,16 +1,15 @@ [Unit] -Description=Aptly API +Description=Aptly REST API After=network.target Documentation=man:aptly(1) [Service] User=aptly-api Group=aptly-api -WorkingDirectory=/var/lib/aptly-api +Environment=TERM=dumb +WorkingDirectory=~ EnvironmentFile=/etc/default/aptly-api -ExecStart=/usr/bin/aptly api serve \ - -config=/etc/aptly-api.conf \ - -listen=${LISTEN_ADDRESS} +ExecStart=/usr/bin/aptly api serve -config=/etc/aptly.conf -listen=${LISTEN_ADDRESS} [Install] WantedBy=multi-user.target diff --git a/debian/aptly.conf b/debian/aptly.conf new file mode 100644 index 00000000..d091e474 --- /dev/null +++ b/debian/aptly.conf @@ -0,0 +1,38 @@ +{ + "rootDir": "~/.aptly", + "downloadConcurrency": 4, + "downloadSpeedLimit": 0, + "downloadRetries": 0, + "downloader": "default", + "databaseOpenAttempts": -1, + "architectures": [], + "dependencyFollowSuggests": false, + "dependencyFollowRecommends": false, + "dependencyFollowAllVariants": false, + "dependencyFollowSource": false, + "dependencyVerboseResolve": false, + "gpgDisableSign": false, + "gpgDisableVerify": false, + "gpgProvider": "gpg", + "downloadSourcePackages": false, + "skipLegacyPool": true, + "ppaDistributorID": "ubuntu", + "ppaCodename": "", + "skipContentsPublishing": false, + "skipBz2Publishing": false, + "FileSystemPublishEndpoints": {}, + "S3PublishEndpoints": {}, + "SwiftPublishEndpoints": {}, + "AzurePublishEndpoints": {}, + "AsyncAPI": false, + "enableMetricsEndpoint": false, + "logLevel": "info", + "logFormat": "default", + "serveInAPIMode": false, + "databaseBackend": { + "type": "", + "url": "", + "dbPath": "" + }, + "enableSwaggerEndpoint": false +} diff --git a/debian/control b/debian/control index 4e528483..9655f50e 100644 --- a/debian/control +++ b/debian/control @@ -5,38 +5,79 @@ Maintainer: Sebastien Delafond Build-Depends: bash-completion, debhelper-compat (= 13), dh-golang, - golang-any, + golang-go, golang-github-aleksi-pointer-dev, golang-github-awalterschulze-gographviz-dev, - golang-github-aws-aws-sdk-go-dev, + golang-github-aws-aws-sdk-go-v2-dev, + golang-github-aws-smithy-go-dev, + golang-github-azure-azure-pipeline-go-dev, golang-github-azure-azure-storage-blob-go-dev, + golang-github-beorn7-perks-dev, golang-github-cavaliergopher-grab-dev, - golang-github-cheggaaa-pb-dev, + golang-github-cespare-xxhash-dev, + golang-github-cheggaaa-pb.v3-dev, + golang-github-cloudflare-circl-dev, + golang-github-coreos-go-semver-dev, + golang-github-coreos-go-systemd-dev, golang-github-disposaboy-jsonconfigreader-dev, + golang-github-gin-contrib-sse-dev, golang-github-gin-gonic-gin-dev, + golang-github-gogo-protobuf-dev, + golang-snappy-go-dev, + golang-github-google-uuid-dev, + golang-github-go-playground-locales-dev, + golang-github-go-playground-universal-translator-dev, + golang-github-go-playground-validator-v10-dev, + golang-gopkg-h2non-filetype.v1-dev, + golang-github-hashicorp-errwrap-dev, + golang-github-hashicorp-go-multierror-dev, + golang-github-jlaffaye-ftp-dev, golang-github-kjk-lzma-dev, golang-github-klauspost-compress-dev, golang-github-klauspost-pgzip-dev, + golang-github-leodido-go-urn-dev, + golang-github-mattn-go-colorable-dev, + golang-github-mattn-go-ieproxy-dev, + golang-github-mattn-go-isatty-dev, + golang-github-mattn-go-runewidth-dev, golang-github-mattn-go-shellwords-dev, golang-github-mkrautz-goar-dev, + golang-github-munnerz-goautoneg-dev, golang-github-mxk-go-flowrate-dev, golang-github-ncw-swift-dev, golang-github-pborman-uuid-dev, + golang-github-pelletier-go-toml, golang-github-pkg-errors-dev, golang-github-prometheus-client-golang-dev, + golang-github-prometheus-client-model-dev, + golang-github-prometheus-common-dev, + golang-github-prometheus-procfs-dev, + golang-github-protonmail-go-crypto-dev, + golang-github-rivo-uniseg-dev, + golang-github-rs-zerolog-dev, + golang-github-saracen-walker-dev, golang-github-smira-commander-dev, golang-github-smira-flag-dev, - golang-github-smira-go-aws-auth-dev, golang-github-smira-go-ftp-protocol-dev, golang-github-smira-go-xz-dev, golang-github-syndtr-goleveldb-dev, - golang-github-ugorji-go-codec-dev, + golang-github-ugorji-go-codec, golang-github-wsxiaoys-terminal-dev, golang-golang-x-crypto-dev, + golang-golang-x-net-dev, + golang-golang-x-sync-dev, golang-golang-x-sys-dev, + golang-golang-x-term-dev, + golang-golang-x-text-dev, golang-golang-x-time-dev, - golang-golang-x-tools-dev, - golang-gopkg-h2non-filetype.v1-dev + golang-google-genproto-dev, + golang-google-grpc-dev, + golang-google-protobuf-dev, + golang-gopkg-yaml.v2-dev, + golang-go.uber-multierr-dev, + golang-go.uber-zap-dev, + golang-etcd-server-dev (>= 3.5.15-7), + git Standards-Version: 4.6.1 Homepage: https://www.aptly.info Vcs-Git: https://salsa.debian.org/debian/aptly.git @@ -49,7 +90,7 @@ Architecture: any Depends: bzip2, xz-utils, gnupg, gpgv, ${shlibs:Depends}, ${misc:Depends} Suggests: graphviz Conflicts: gnupg1, gpgv1 -Built-Using: ${misc:Built-Using} +Built-Using: ${misc:Static-Built-Using}, ${misc:Built-Using} Description: Swiss army knife for Debian repository management - main package It offers several features making it easy to manage Debian package repositories: @@ -66,7 +107,7 @@ Description: Swiss army knife for Debian repository management - main package This is the main package, it contains the aptly command-line utility. Package: aptly-api -Architecture: any +Architecture: all Depends: ${misc:Depends}, aptly, adduser Built-Using: ${misc:Built-Using} Description: Swiss army knife for Debian repository management - API diff --git a/docs/index.go b/docs/index.go new file mode 100644 index 00000000..5604656f --- /dev/null +++ b/docs/index.go @@ -0,0 +1 @@ +package docs diff --git a/files/mocks.go b/files/mocks.go index 572ece28..411e73a9 100644 --- a/files/mocks.go +++ b/files/mocks.go @@ -5,19 +5,19 @@ import ( "github.com/aptly-dev/aptly/utils" ) -type mockChecksumStorage struct { - store map[string]utils.ChecksumInfo +type MockChecksumStorage struct { + Store map[string]utils.ChecksumInfo } // NewMockChecksumStorage creates aptly.ChecksumStorage for tests func NewMockChecksumStorage() aptly.ChecksumStorage { - return &mockChecksumStorage{ - store: make(map[string]utils.ChecksumInfo), + return &MockChecksumStorage{ + Store: make(map[string]utils.ChecksumInfo), } } -func (st *mockChecksumStorage) Get(path string) (*utils.ChecksumInfo, error) { - c, ok := st.store[path] +func (st *MockChecksumStorage) Get(path string) (*utils.ChecksumInfo, error) { + c, ok := st.Store[path] if !ok { return nil, nil } @@ -25,12 +25,12 @@ func (st *mockChecksumStorage) Get(path string) (*utils.ChecksumInfo, error) { return &c, nil } -func (st *mockChecksumStorage) Update(path string, c *utils.ChecksumInfo) error { - st.store[path] = *c +func (st *MockChecksumStorage) Update(path string, c *utils.ChecksumInfo) error { + st.Store[path] = *c return nil } // Check interface var ( - _ aptly.ChecksumStorage = &mockChecksumStorage{} + _ aptly.ChecksumStorage = &MockChecksumStorage{} ) diff --git a/files/package_pool.go b/files/package_pool.go index 8b1e8b25..e82a7447 100644 --- a/files/package_pool.go +++ b/files/package_pool.go @@ -3,13 +3,14 @@ package files import ( "fmt" "io" - "io/ioutil" "os" "path/filepath" + "sort" "sync" "syscall" "github.com/pborman/uuid" + "github.com/saracen/walker" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/utils" @@ -31,8 +32,7 @@ var ( // NewPackagePool creates new instance of PackagePool which specified root func NewPackagePool(root string, supportLegacyPaths bool) *PackagePool { - rootPath := filepath.Join(root, "pool") - rootPath, err := filepath.Abs(rootPath) + rootPath, err := filepath.Abs(root) if err != nil { panic(err) } @@ -81,7 +81,7 @@ func (pool *PackagePool) FilepathList(progress aptly.Progress) ([]string, error) pool.Lock() defer pool.Unlock() - dirs, err := ioutil.ReadDir(pool.rootPath) + dirs, err := os.ReadDir(pool.rootPath) if err != nil { if os.IsNotExist(err) { return nil, nil @@ -99,13 +99,13 @@ func (pool *PackagePool) FilepathList(progress aptly.Progress) ([]string, error) } result := []string{} + resultLock := &sync.Mutex{} for _, dir := range dirs { - err = filepath.Walk(filepath.Join(pool.rootPath, dir.Name()), func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } + err = walker.Walk(filepath.Join(pool.rootPath, dir.Name()), func(path string, info os.FileInfo) error { if !info.IsDir() { + resultLock.Lock() + defer resultLock.Unlock() result = append(result, path[len(pool.rootPath)+1:]) } return nil @@ -119,6 +119,7 @@ func (pool *PackagePool) FilepathList(progress aptly.Progress) ([]string, error) } } + sort.Strings(result) return result, nil } @@ -378,6 +379,15 @@ func (pool *PackagePool) Import(srcPath, basename string, checksums *utils.Check return poolPath, err } +func (pool *PackagePool) Size(path string) (size int64, err error) { + stat, err := pool.Stat(path) + if err != nil { + return 0, err + } + + return stat.Size(), nil +} + // Open returns io.ReadCloser to access the file func (pool *PackagePool) Open(path string) (aptly.ReadSeekerCloser, error) { return os.Open(filepath.Join(pool.rootPath, path)) diff --git a/files/package_pool_test.go b/files/package_pool_test.go index 3f65ed2c..f06d6bcf 100644 --- a/files/package_pool_test.go +++ b/files/package_pool_test.go @@ -111,7 +111,7 @@ func (s *PackagePoolSuite) TestImportOk(c *C) { // SHA256 should be automatically calculated c.Check(s.checksum.SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") // checksum storage is filled with new checksum - c.Check(s.cs.(*mockChecksumStorage).store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") + c.Check(s.cs.(*MockChecksumStorage).Store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") info, err := s.pool.Stat(path) c.Assert(err, IsNil) @@ -128,7 +128,7 @@ func (s *PackagePoolSuite) TestImportOk(c *C) { c.Check(err, IsNil) c.Check(path, Equals, "c7/6b/4bd12fd92e4dfe1b55b18a67a669_some.deb") // checksum storage is filled with new checksum - c.Check(s.cs.(*mockChecksumStorage).store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") + c.Check(s.cs.(*MockChecksumStorage).Store[path].SHA256, Equals, "c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12") // double import, should be ok s.checksum.SHA512 = "" // clear checksum @@ -139,7 +139,7 @@ func (s *PackagePoolSuite) TestImportOk(c *C) { c.Check(s.checksum.SHA512, Equals, "d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c") // clear checksum storage, and do double-import - delete(s.cs.(*mockChecksumStorage).store, path) + delete(s.cs.(*MockChecksumStorage).Store, path) s.checksum.SHA512 = "" // clear checksum path, err = s.pool.Import(s.debFile, filepath.Base(s.debFile), &s.checksum, false, s.cs) c.Check(err, IsNil) @@ -244,7 +244,7 @@ func (s *PackagePoolSuite) TestVerify(c *C) { c.Check(exists, Equals, false) // check existence, with missing checksum and no info in checksum storage - delete(s.cs.(*mockChecksumStorage).store, path) + delete(s.cs.(*MockChecksumStorage).Store, path) s.checksum.SHA512 = "" ppath, exists, err = s.pool.Verify("", filepath.Base(s.debFile), &s.checksum, s.cs) c.Check(ppath, Equals, path) @@ -306,6 +306,18 @@ func (s *PackagePoolSuite) TestImportOverwrite(c *C) { c.Check(err, ErrorMatches, "unable to import into pool.*") } +func (s *PackagePoolSuite) TestSize(c *C) { + path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &s.checksum, false, s.cs) + c.Check(err, IsNil) + + size, err := s.pool.Size(path) + c.Assert(err, IsNil) + c.Check(size, Equals, int64(2738)) + + _, err = s.pool.Size("do/es/ntexist") + c.Assert(os.IsNotExist(err), Equals, true) +} + func (s *PackagePoolSuite) TestStat(c *C) { path, err := s.pool.Import(s.debFile, filepath.Base(s.debFile), &s.checksum, false, s.cs) c.Check(err, IsNil) diff --git a/files/public.go b/files/public.go index fc87b410..848f0c23 100644 --- a/files/public.go +++ b/files/public.go @@ -5,11 +5,14 @@ import ( "io" "os" "path/filepath" + "sort" "strings" + "sync" "syscall" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/utils" + "github.com/saracen/walker" ) // PublishedStorage abstract file system with public dirs (published repos) @@ -118,37 +121,49 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress // LinkFromPool links package file from pool to dist's pool location // -// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/) +// publishedPrefix is desired prefix for the location in the pool. +// publishedRelPath is desired location in pool (like pool/component/liba/libav/) // sourcePool is instance of aptly.PackagePool // sourcePath is a relative path to package file in package pool // // LinkFromPool returns relative path for the published file to be included in package index -func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName string, sourcePool aptly.PackagePool, +func (storage *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error { baseName := filepath.Base(fileName) - poolPath := filepath.Join(storage.rootPath, publishedDirectory, filepath.Dir(fileName)) + poolPath := filepath.Join(storage.rootPath, publishedPrefix, publishedRelPath, filepath.Dir(fileName)) + + var localSourcePool aptly.LocalPackagePool + if storage.linkMethod != LinkMethodCopy { + pp, ok := sourcePool.(aptly.LocalPackagePool) + if !ok { + return fmt.Errorf("cannot link %s from non-local pool %s", baseName, sourcePool) + } + + localSourcePool = pp + } err := os.MkdirAll(poolPath, 0777) if err != nil { return err } - var dstStat, srcStat os.FileInfo + var dstStat os.FileInfo dstStat, err = os.Stat(filepath.Join(poolPath, baseName)) if err == nil { // already exists, check source file - srcStat, err = sourcePool.Stat(sourcePath) - if err != nil { - // source file doesn't exist? problem! - return err - } if storage.linkMethod == LinkMethodCopy { + srcSize, err := sourcePool.Size(sourcePath) + if err != nil { + // source file doesn't exist? problem! + return err + } + if storage.verifyMethod == VerificationMethodFileSize { // if source and destination have the same size, no need to copy - if srcStat.Size() == dstStat.Size() { + if srcSize == dstStat.Size() { return nil } } else { @@ -165,6 +180,12 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin } } } else { + srcStat, err := localSourcePool.Stat(sourcePath) + if err != nil { + // source file doesn't exist? problem! + return err + } + srcSys := srcStat.Sys().(*syscall.Stat_t) dstSys := dstStat.Sys().(*syscall.Stat_t) @@ -219,9 +240,9 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin err = dst.Close() } else if storage.linkMethod == LinkMethodSymLink { - err = sourcePool.(aptly.LocalPackagePool).Symlink(sourcePath, filepath.Join(poolPath, baseName)) + err = localSourcePool.Symlink(sourcePath, filepath.Join(poolPath, baseName)) } else { - err = sourcePool.(aptly.LocalPackagePool).Link(sourcePath, filepath.Join(poolPath, baseName)) + err = localSourcePool.Link(sourcePath, filepath.Join(poolPath, baseName)) } return err @@ -231,12 +252,12 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) { root := filepath.Join(storage.rootPath, prefix) result := []string{} + resultLock := &sync.Mutex{} - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } + err := walker.Walk(root, func(path string, info os.FileInfo) error { if !info.IsDir() { + resultLock.Lock() + defer resultLock.Unlock() result = append(result, path[len(root)+1:]) } return nil @@ -247,6 +268,7 @@ func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) { return []string{}, nil } + sort.Strings(result) return result, err } diff --git a/files/public_test.go b/files/public_test.go index 16f724cb..f135bd3e 100644 --- a/files/public_test.go +++ b/files/public_test.go @@ -233,7 +233,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Assert(err, IsNil) // Test using hardlinks - err = s.storage.LinkFromPool(filepath.Join(t.prefix, t.publishedDirectory), t.sourcePath, pool, srcPoolPath, sourceChecksum, false) + err = s.storage.LinkFromPool(t.prefix, t.publishedDirectory, t.sourcePath, pool, srcPoolPath, sourceChecksum, false) c.Assert(err, IsNil) st, err := os.Stat(filepath.Join(s.storage.rootPath, t.prefix, t.expectedFilename)) @@ -243,7 +243,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(int(info.Nlink), Equals, 3) // Test using symlinks - err = s.storageSymlink.LinkFromPool(filepath.Join(t.prefix, t.publishedDirectory), t.sourcePath, pool, srcPoolPath, sourceChecksum, false) + err = s.storageSymlink.LinkFromPool(t.prefix, t.publishedDirectory, t.sourcePath, pool, srcPoolPath, sourceChecksum, false) c.Assert(err, IsNil) st, err = os.Lstat(filepath.Join(s.storageSymlink.rootPath, t.prefix, t.expectedFilename)) @@ -254,7 +254,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(int(info.Mode&syscall.S_IFMT), Equals, int(syscall.S_IFLNK)) // Test using copy with checksum verification - err = s.storageCopy.LinkFromPool(filepath.Join(t.prefix, t.publishedDirectory), t.sourcePath, pool, srcPoolPath, sourceChecksum, false) + err = s.storageCopy.LinkFromPool(t.prefix, t.publishedDirectory, t.sourcePath, pool, srcPoolPath, sourceChecksum, false) c.Assert(err, IsNil) st, err = os.Stat(filepath.Join(s.storageCopy.rootPath, t.prefix, t.expectedFilename)) @@ -264,7 +264,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(int(info.Nlink), Equals, 1) // Test using copy with size verification - err = s.storageCopySize.LinkFromPool(filepath.Join(t.prefix, t.publishedDirectory), t.sourcePath, pool, srcPoolPath, sourceChecksum, false) + err = s.storageCopySize.LinkFromPool(t.prefix, t.publishedDirectory, t.sourcePath, pool, srcPoolPath, sourceChecksum, false) c.Assert(err, IsNil) st, err = os.Stat(filepath.Join(s.storageCopySize.rootPath, t.prefix, t.expectedFilename)) @@ -289,7 +289,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Assert(err, IsNil) nlinks := int(st.Sys().(*syscall.Stat_t).Nlink) - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) c.Check(err, ErrorMatches, ".*file already exists and is different") st, err = pool.Stat(srcPoolPath) @@ -297,7 +297,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(int(st.Sys().(*syscall.Stat_t).Nlink), Equals, nlinks) // linking with force - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) c.Check(err, IsNil) st, err = pool.Stat(srcPoolPath) @@ -305,21 +305,21 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(int(st.Sys().(*syscall.Stat_t).Nlink), Equals, nlinks+1) // Test using symlinks - err = s.storageSymlink.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) + err = s.storageSymlink.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) c.Check(err, ErrorMatches, ".*file already exists and is different") - err = s.storageSymlink.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) + err = s.storageSymlink.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) c.Check(err, IsNil) // Test using copy with checksum verification - err = s.storageCopy.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) + err = s.storageCopy.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) c.Check(err, ErrorMatches, ".*file already exists and is different") - err = s.storageCopy.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) + err = s.storageCopy.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, true) c.Check(err, IsNil) // Test using copy with size verification (this will NOT detect the difference) - err = s.storageCopySize.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) + err = s.storageCopySize.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, srcPoolPath, sourceChecksum, false) c.Check(err, IsNil) } diff --git a/go.mod b/go.mod index 4c2e85ad..d053f1df 100644 --- a/go.mod +++ b/go.mod @@ -1,48 +1,132 @@ module github.com/aptly-dev/aptly -go 1.15 +go 1.22.7 require ( - github.com/AlekSi/pointer v1.0.0 + github.com/AlekSi/pointer v1.1.0 github.com/Azure/azure-storage-blob-go v0.15.0 - github.com/DisposaBoy/JsonConfigReader v0.0.0-20130112093355-33a99fdf1d5e - github.com/awalterschulze/gographviz v0.0.0-20160912181450-761fd5fbb34e - github.com/aws/aws-sdk-go v1.25.0 + github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 + github.com/awalterschulze/gographviz v2.0.1+incompatible github.com/cavaliergopher/grab/v3 v3.0.1 - github.com/cheggaaa/pb v1.0.10 - github.com/fatih/color v1.7.0 // indirect - github.com/gin-gonic/gin v1.7.7 - github.com/go-playground/validator/v10 v10.10.1 // indirect - github.com/h2non/filetype v1.0.5 - github.com/jlaffaye/ftp v0.0.0-20180404123514-2403248fa8cc // indirect - github.com/kjk/lzma v0.0.0-20161016003348-3fd93898850d - github.com/klauspost/compress v1.13.6 + github.com/cheggaaa/pb v1.0.25 + github.com/gin-gonic/gin v1.9.0 + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/h2non/filetype v1.1.3 + github.com/jlaffaye/ftp v0.2.0 // indirect + github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2 + github.com/klauspost/compress v1.17.9 github.com/klauspost/pgzip v1.2.5 - github.com/mattn/go-colorable v0.1.2 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-runewidth v0.0.2 // indirect - github.com/mattn/go-shellwords v1.0.2 + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-shellwords v1.0.12 github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f - github.com/ncw/swift v1.0.30 - github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3 + github.com/ncw/swift v1.0.53 + github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.1 - github.com/smartystreets/gunit v1.0.4 // indirect + github.com/prometheus/client_golang v1.20.0 + github.com/rs/zerolog v1.29.1 + github.com/saracen/walker v0.1.2 github.com/smira/commander v0.0.0-20140515201010-f408b00e68d5 github.com/smira/flag v0.0.0-20170926215700-695ea5e84e76 - github.com/smira/go-aws-auth v0.0.0-20180731211914-8b73995fd8d1 github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d - github.com/smira/go-xz v0.0.0-20150414201226-0c531f070014 - github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d - github.com/ugorji/go/codec v1.2.7 + github.com/smira/go-xz v0.1.0 + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca + github.com/ugorji/go/codec v1.2.11 github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 - golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 - golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 - golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 - google.golang.org/protobuf v1.28.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/sys v0.23.0 + golang.org/x/term v0.23.0 + golang.org/x/time v0.5.0 + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c - gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect - gopkg.in/h2non/filetype.v1 v1.0.1 // indirect +) + +require ( + github.com/Azure/azure-pipeline-go v0.2.3 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.25.2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.8.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudflare/circl v1.4.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-ieproxy v0.0.9 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.59.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + go.etcd.io/etcd/api/v3 v3.5.15 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.1 // indirect + gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +require ( + github.com/ProtonMail/go-crypto v1.0.0 + github.com/aws/aws-sdk-go-v2 v1.30.3 + github.com/aws/aws-sdk-go-v2/config v1.25.1 + github.com/aws/aws-sdk-go-v2/credentials v1.16.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 + github.com/aws/smithy-go v1.20.3 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.3 + go.etcd.io/etcd/client/v3 v3.5.15 ) diff --git a/go.sum b/go.sum index 370f953d..ac476e31 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,5 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AlekSi/pointer v1.0.0 h1:KWCWzsvFxNLcmM5XmiqHsGTTsuwZMsLFwWF9Y+//bNE= -github.com/AlekSi/pointer v1.0.0/go.mod h1:1kjywbfcPFCmncIxtk6fIEub6LKrfMz3gc5QKVOSOA8= +github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= +github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk= @@ -43,599 +10,433 @@ github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZ github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DisposaBoy/JsonConfigReader v0.0.0-20130112093355-33a99fdf1d5e h1:rv5qJCfIzQhhefHp8MO98hoGRI3mdps2iiGA3o4nm8A= -github.com/DisposaBoy/JsonConfigReader v0.0.0-20130112093355-33a99fdf1d5e/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/awalterschulze/gographviz v0.0.0-20160912181450-761fd5fbb34e h1:24jix3mqu421BBMWbVBOl5pDw0f9ncazW10kaMywzHQ= -github.com/awalterschulze/gographviz v0.0.0-20160912181450-761fd5fbb34e/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= -github.com/aws/aws-sdk-go v1.25.0 h1:MyXUdCesJLBvSSKYcaKeeEwxNUwUpG6/uqVYeH/Zzfo= -github.com/aws/aws-sdk-go v1.25.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 h1:jbGlDKdzAZ92NzK65hUP98ri0/r50vVVvmZsFP/nIqo= +github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/awalterschulze/gographviz v2.0.1+incompatible h1:XIECBRq9VPEQqkQL5pw2OtjCAdrtIgFKoJU8eT98AS8= +github.com/awalterschulze/gographviz v2.0.1+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= +github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= +github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= +github.com/aws/aws-sdk-go-v2/config v1.25.1 h1:YsjngBOl2mx4l3egkVWndr6/6TqtkdsWJFZIsQ924Ek= +github.com/aws/aws-sdk-go-v2/config v1.25.1/go.mod h1:yV6h7TRVzhdIFmUk9WWDRpWwYGg1woEzKr0k1IYz2Tk= +github.com/aws/aws-sdk-go-v2/credentials v1.16.1 h1:WessyrdgyFN5TB+eLQdrFSlN/3oMnqukIFhDxK6z8h0= +github.com/aws/aws-sdk-go-v2/credentials v1.16.1/go.mod h1:RQJyPxKcr+m4ArlIG1LUhMOrjposVfzbX6H8oR6oCgE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 h1:9wKDWEjwSnXZre0/O3+ZwbBl1SmlgWYBbrTV10X/H1s= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4/go.mod h1:t4i+yGHMCcUNIX1x7YVYa6bH/Do7civ5I6cG/6PMfyA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0 h1:usgqiJtamuGIBj+OvYmMq89+Z1hIKkMJToz1WpoeNUY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 h1:V47N5eKgVZoRSvx2+RQ0EpAEit/pqOhqeSQFiS4OFEQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.2/go.mod h1:/pE21vno3q1h4bbhUOEi+6Zu/aT26UK2WKkDXd+TssQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.2 h1:sMAcO7VHVw28HTAdZpTULDzFirHOsVm/x25CxhUH0jA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.2/go.mod h1:dWqm5G767qwKPuayKfzm4rjzFmVjiBFbOJrpSPnAMDs= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.2 h1:vwyiRTnXLqsak/6WAQ+uTRhVqKI6vxUQ0HJXjKij0zM= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.2/go.mod h1:4EqRHDCKP78hq3zOnmFXu5k0j4bXbRFfCh/zQ6KnEfQ= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheggaaa/pb v1.0.10 h1:CNg2511WECXZ7Ja6jjyz9CMBpQOrMuP5+H5zfjgVi/Q= -github.com/cheggaaa/pb v1.0.10/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v1.0.25 h1:tFpebHTkI7QZx1q1rWGOKhbunhZ3fMaxTvHDWn1bH/4= +github.com/cheggaaa/pb v1.0.25/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY= +github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= -github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= -github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/h2non/filetype v1.0.5 h1:Esu2EFM5vrzNynnGQpj0nxhCkzVQh2HRY7AXUh/dyJM= -github.com/h2non/filetype v1.0.5/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jlaffaye/ftp v0.0.0-20180404123514-2403248fa8cc h1:lWFup/SOhwcpvRJIFqx/WQis5U4SrOSyWfSqvfdF09w= -github.com/jlaffaye/ftp v0.0.0-20180404123514-2403248fa8cc/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= +github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kjk/lzma v0.0.0-20161016003348-3fd93898850d h1:RnWZeH8N8KXfbwMTex/KKMYMj0FJRCF6tQubUuQ02GM= -github.com/kjk/lzma v0.0.0-20161016003348-3fd93898850d/go.mod h1:phT/jsRPBAEqjAibu1BurrabCBNTYiVI+zbmyCZJY6Q= -github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2 h1:TVZQgMi+I83S3rCuE65HnmDO6+wFPRi3n2LOzr+tr68= +github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2/go.mod h1:phT/jsRPBAEqjAibu1BurrabCBNTYiVI+zbmyCZJY6Q= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-ieproxy v0.0.9 h1:RvVbLiMv/Hbjf1gRaC2AQyzwbdVhdId7D2vPnXIml4k= +github.com/mattn/go-ieproxy v0.0.9/go.mod h1:eF30/rfdQUO9EnzNIZQr0r9HiLMlZNCpJkHbmMuOAE0= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-shellwords v1.0.2 h1:5FJ7APbaUYdUTxxP/XXltfy/mICrGqugUEClfnj+D3Y= -github.com/mattn/go-shellwords v1.0.2/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da h1:Iu5QFXIMK/YrHJ0NgUnK0rqYTTyb0ldt/rqNenAj39U= github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da/go.mod h1:NfnmoBY0gGkr3/NmI+DP/UXbZvOCurCUYAzOdYJjlOc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/ncw/swift v1.0.30 h1:CrRYmUc+mFGIvBiS5JIA4sIdURfDpJ4CGmpmR9mQAZ0= -github.com/ncw/swift v1.0.30/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= +github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3 h1:9J0mOv1rXIBlRjQCiAGyx9C3dZZh5uIa3HU0oTV8v1E= -github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= -github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/gunit v1.0.4 h1:tpTjnuH7MLlqhoD21vRoMZbMIi5GmBsAJDFyF67GhZA= -github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ= +github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= +github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= +github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/saracen/walker v0.1.2 h1:/o1TxP82n8thLvmL4GpJXduYaRmJ7qXp8u9dSlV0zmo= +github.com/saracen/walker v0.1.2/go.mod h1:0oKYMsKVhSJ+ful4p/XbjvXbMgLEkLITZaxozsl4CGE= github.com/smira/commander v0.0.0-20140515201010-f408b00e68d5 h1:jLFwP6SDEUHmb6QSu5n2FHseWzMio1ou1FV9p7W6p7I= github.com/smira/commander v0.0.0-20140515201010-f408b00e68d5/go.mod h1:XTQy55hw5s3pxmC42m7X0/b+9naXQ1rGN9Of6BGIZmU= github.com/smira/flag v0.0.0-20170926215700-695ea5e84e76 h1:OM075OkN4x9IB1mbzkzaKaJjFxx8Mfss8Z3E1LHwawQ= github.com/smira/flag v0.0.0-20170926215700-695ea5e84e76/go.mod h1:KQ5bP0mZypI2qXa4Wjk+r7B6Wt/0L8/DvJwpbR1UWg4= -github.com/smira/go-aws-auth v0.0.0-20180731211914-8b73995fd8d1 h1:VPv+J50mFyP42/GzYhGuT4MJK8w/dlLt4jkoO5yhJRs= -github.com/smira/go-aws-auth v0.0.0-20180731211914-8b73995fd8d1/go.mod h1:KKhbssKjyR//TUP31t3ksE2b6oeAw328JzwmFJnzRCw= github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d h1:rvtR4+9N2LWPo0UHe6/aHvWpqD9Dhf10P2bfGFht74g= github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d/go.mod h1:Jm7yHrROA5tC42gyJ5EwiR8EWp0PUy0qOc4sE7Y8Uzo= -github.com/smira/go-xz v0.0.0-20150414201226-0c531f070014 h1:tne8XW3soRDJn4DIiqBc4jw+DPashtFMTSC9G0pC3ug= -github.com/smira/go-xz v0.0.0-20150414201226-0c531f070014/go.mod h1:smSuTvETRIkX95VAIWBdKoGJuUxif7NT7FgbkpVqOiA= +github.com/smira/go-xz v0.1.0 h1:1zVLT1sITUKcWNysfHMLZWJ2Yh7yJfhREsgmUdK4zb0= +github.com/smira/go-xz v0.1.0/go.mod h1:OmdEWnIIkuLzRLHGF4YtjDzF9VFUevEcP6YxDPRqVrs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk= +go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM= +go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA= +go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU= +go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4= +go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= -golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 h1:D1v9ucDTYBtbz5vNuBbAhIMAGhQhJ6Ym5ah3maMVNX4= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/h2non/filetype.v1 v1.0.1 h1:JMZLYHwIsvWGh+6UcU//eA1aiM8g4SaZm3lJweIR5Ew= -gopkg.in/h2non/filetype.v1 v1.0.1/go.mod h1:M0yem4rwSX5lLVrkEuRRp2/NinFMD5vgJ4DlAhZcfNo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/http/download.go b/http/download.go index 3c2a1ebd..5bb9d050 100644 --- a/http/download.go +++ b/http/download.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net" "net/http" "net/url" @@ -47,29 +46,27 @@ func NewDownloader(downLimit int64, maxTries int, progress aptly.Progress) aptly transport.RegisterProtocol("ftp", &protocol.FTPRoundTripper{}) downloader := &downloaderImpl{ - progress: progress, - maxTries: maxTries, + progress: progress, + maxTries: maxTries, + aggWriter: io.Writer(progress), client: &http.Client{ Transport: &transport, }, } - progressWriter := io.Writer(progress) if progress == nil { - progressWriter = ioutil.Discard + downloader.aggWriter = io.Discard + } + if downLimit > 0 { + downloader.aggWriter = flowrate.NewWriter(downloader.aggWriter, downLimit) } downloader.client.CheckRedirect = downloader.checkRedirect - if downLimit > 0 { - downloader.aggWriter = flowrate.NewWriter(progressWriter, downLimit) - } else { - downloader.aggWriter = progressWriter - } return downloader } -func (downloader *downloaderImpl) checkRedirect(req *http.Request, via []*http.Request) error { +func (downloader *downloaderImpl) checkRedirect(req *http.Request, _ []*http.Request) error { if downloader.progress != nil { downloader.progress.Printf("Following redirect to %s...\n", req.URL) } @@ -177,7 +174,7 @@ func (downloader *downloaderImpl) DownloadWithChecksum(ctx context.Context, url expected *utils.ChecksumInfo, ignoreMismatch bool) error { if downloader.progress != nil { - downloader.progress.Printf("Downloading %s...\n", url) + downloader.progress.Printf("Downloading: %s\n", url) defer downloader.progress.Flush() } req, err := downloader.newRequest(ctx, "GET", url) @@ -193,7 +190,7 @@ func (downloader *downloaderImpl) DownloadWithChecksum(ctx context.Context, url if err != nil { if retryableError(err) { if downloader.progress != nil { - downloader.progress.Printf("Error downloading %s: %s retrying...\n", url, err) + downloader.progress.Printf("Error (retrying): %s\n", err) } maxTries-- time.Sleep(delay) @@ -204,15 +201,12 @@ func (downloader *downloaderImpl) DownloadWithChecksum(ctx context.Context, url } } else { if downloader.progress != nil { - downloader.progress.Printf("Error downloading %s: %s cannot retry...\n", url, err) + downloader.progress.Printf("Error: %s \n", err) } break } } else { // get out of the loop - if downloader.progress != nil { - downloader.progress.Printf("Success downloading %s\n", url) - } break } if downloader.progress != nil { @@ -223,7 +217,7 @@ func (downloader *downloaderImpl) DownloadWithChecksum(ctx context.Context, url // still an error after retrying, giving up if err != nil { if downloader.progress != nil { - downloader.progress.Printf("Giving up on %s...\n", url) + downloader.progress.Printf("Download Error: %s\n", url) } return err } @@ -264,11 +258,7 @@ func (downloader *downloaderImpl) download(req *http.Request, url, destination s defer outfile.Close() checksummer := utils.NewChecksumWriter() - writers := []io.Writer{outfile} - - if downloader.progress != nil { - writers = append(writers, downloader.progress) - } + writers := []io.Writer{outfile, downloader.aggWriter} if expected != nil { writers = append(writers, checksummer) diff --git a/http/download_test.go b/http/download_test.go index 7f89a777..9cde0716 100644 --- a/http/download_test.go +++ b/http/download_test.go @@ -3,7 +3,6 @@ package http import ( "context" "fmt" - "io/ioutil" "net" "net/http" "os" @@ -27,7 +26,7 @@ type DownloaderSuiteBase struct { } func (s *DownloaderSuiteBase) SetUpTest(c *C) { - s.tempfile, _ = ioutil.TempFile(os.TempDir(), "aptly-test") + s.tempfile, _ = os.CreateTemp(os.TempDir(), "aptly-test") s.l, _ = net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}) s.url = fmt.Sprintf("http://localhost:%d", s.l.Addr().(*net.TCPAddr).Port) @@ -43,7 +42,7 @@ func (s *DownloaderSuiteBase) SetUpTest(c *C) { close(s.ch) }() - s.progress = console.NewProgress() + s.progress = console.NewProgress(false) s.progress.Start() s.d = NewDownloader(0, 1, s.progress) @@ -116,7 +115,7 @@ func (s *DownloaderSuite) TestDownload404(c *C) { } func (s *DownloaderSuite) TestDownloadConnectError(c *C) { - c.Assert(s.d.Download(s.ctx, "http://nosuch.host/", s.tempfile.Name()), + c.Assert(s.d.Download(s.ctx, "http://nosuch.host.invalid./", s.tempfile.Name()), ErrorMatches, ".*no such host") } @@ -151,7 +150,7 @@ func (s *DownloaderSuite) TestGetLength404(c *C) { } func (s *DownloaderSuite) TestGetLengthConnectError(c *C) { - _, err := s.d.GetLength(s.ctx, "http://nosuch.host/") + _, err := s.d.GetLength(s.ctx, "http://nosuch.host.invalid./") c.Assert(err, ErrorMatches, ".*no such host") } diff --git a/http/fake.go b/http/fake.go index 2cbb72d6..40a1093d 100644 --- a/http/fake.go +++ b/http/fake.go @@ -61,7 +61,7 @@ func (f *FakeDownloader) Empty() bool { } // GetLength returns content length of given url -func (f *FakeDownloader) GetLength(ctx context.Context, url string) (int64, error) { +func (f *FakeDownloader) GetLength(_ context.Context, url string) (int64, error) { expectation, err := f.getExpectedRequest(url) if err != nil { return -1, err @@ -89,7 +89,7 @@ func (f *FakeDownloader) getExpectedRequest(url string) (*expectedRequest, error } // DownloadWithChecksum performs fake download by matching against first expectation in the queue or any expectation, with cheksum verification -func (f *FakeDownloader) DownloadWithChecksum(ctx context.Context, url string, filename string, expected *utils.ChecksumInfo, ignoreMismatch bool) error { +func (f *FakeDownloader) DownloadWithChecksum(_ context.Context, url string, filename string, expected *utils.ChecksumInfo, ignoreMismatch bool) error { expectation, err := f.getExpectedRequest(url) if err != nil { return err diff --git a/http/grab.go b/http/grab.go index 2d07521c..51fc672b 100644 --- a/http/grab.go +++ b/http/grab.go @@ -59,14 +59,13 @@ func (d *GrabDownloader) DownloadWithChecksum(ctx context.Context, url string, d // Success break } - d.log("Error downloading %s: %v\n", url, err) if retryableError(err) { maxTries-- - d.log("Retrying download %s: %d\n", url, maxTries) + d.log("Retrying %d %s\n", maxTries, url) time.Sleep(delay) } else { // Can't retry - d.log("Cannot retry download %s\n", url) + d.log("Error (retrying): HTTP code %s while fetching %s\n", err, url) break } } @@ -114,9 +113,8 @@ func (d *GrabDownloader) maybeSetupChecksum(req *grab.Request, expected *utils.C return nil } -func (d *GrabDownloader) download(ctx context.Context, url string, destination string, expected *utils.ChecksumInfo, ignoreMismatch bool) error { - // TODO clean up dest dir on permanent failure - d.log("Download %s -> %s\n", url, destination) +func (d *GrabDownloader) download(_ context.Context, url string, destination string, expected *utils.ChecksumInfo, ignoreMismatch bool) error { + d.log("Downloading: %s\n", url) req, err := grab.NewRequest(destination, url) if err != nil { @@ -155,7 +153,7 @@ func (d *GrabDownloader) GetProgress() aptly.Progress { return d.progress } -func (d *GrabDownloader) GetLength(ctx context.Context, url string) (int64, error) { +func (d *GrabDownloader) GetLength(_ context.Context, url string) (int64, error) { resp, err := http.Head(url) if err != nil { return -1, err diff --git a/http/grab_test.go b/http/grab_test.go index 3980c453..dacdfa8f 100644 --- a/http/grab_test.go +++ b/http/grab_test.go @@ -3,7 +3,6 @@ package http import ( "context" "fmt" - "io/ioutil" "net" "net/http" "os" @@ -26,7 +25,7 @@ type GrabDownloaderSuiteBase struct { } func (s *GrabDownloaderSuiteBase) SetUpTest(c *C) { - s.tempfile, _ = ioutil.TempFile(os.TempDir(), "aptly-test") + s.tempfile, _ = os.CreateTemp(os.TempDir(), "aptly-test") s.l, _ = net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}) s.url = fmt.Sprintf("http://localhost:%d", s.l.Addr().(*net.TCPAddr).Port) @@ -42,7 +41,7 @@ func (s *GrabDownloaderSuiteBase) SetUpTest(c *C) { close(s.ch) }() - s.progress = console.NewProgress() + s.progress = console.NewProgress(false) s.progress.Start() s.d = NewGrabDownloader(0, 1, s.progress) @@ -107,7 +106,7 @@ func (s *GrabDownloaderSuite) TestDownload404(c *C) { } func (s *GrabDownloaderSuite) TestDownloadConnectError(c *C) { - c.Assert(s.d.Download(s.ctx, "http://nosuch.host/", s.tempfile.Name()), + c.Assert(s.d.Download(s.ctx, "http://nosuch.host.invalid./", s.tempfile.Name()), ErrorMatches, ".*no such host") } @@ -131,7 +130,7 @@ func (s *GrabDownloaderSuite) TestGetLength404(c *C) { } func (s *GrabDownloaderSuite) TestGetLengthConnectError(c *C) { - _, err := s.d.GetLength(s.ctx, "http://nosuch.host/") + _, err := s.d.GetLength(s.ctx, "http://nosuch.host.invalid./") c.Assert(err, ErrorMatches, ".*no such host") } diff --git a/http/temp.go b/http/temp.go index 8e6a3fde..ddc2d3af 100644 --- a/http/temp.go +++ b/http/temp.go @@ -2,7 +2,6 @@ package http import ( "context" - "io/ioutil" "os" "path/filepath" @@ -21,7 +20,7 @@ func DownloadTemp(ctx context.Context, downloader aptly.Downloader, url string) // // Temporary file would be already removed, so no need to cleanup func DownloadTempWithChecksum(ctx context.Context, downloader aptly.Downloader, url string, expected *utils.ChecksumInfo, ignoreMismatch bool) (*os.File, error) { - tempdir, err := ioutil.TempDir(os.TempDir(), "aptly") + tempdir, err := os.MkdirTemp(os.TempDir(), "aptly") if err != nil { return nil, err } diff --git a/main.go b/main.go index 80093443..337575a4 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,16 @@ package main import ( - "math/rand" "os" - "time" "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/cmd" + + _ "embed" ) -// Version variable, filled in at link time +//go:generate sh -c "make -s version | tr -d '\n' > VERSION" +//go:embed VERSION var Version string func main() { @@ -19,7 +20,5 @@ func main() { aptly.Version = Version - rand.Seed(time.Now().UnixNano()) - os.Exit(cmd.Run(cmd.RootCommand(), os.Args[1:], true)) } diff --git a/main_test.go b/main_test.go new file mode 100644 index 00000000..81ef138d --- /dev/null +++ b/main_test.go @@ -0,0 +1,60 @@ +//go:build testruncli +// +build testruncli + +package main + +import ( + "flag" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/aptly-dev/aptly/aptly" + "github.com/aptly-dev/aptly/cmd" +) + +func filterOutTestArgs(args []string) (out []string) { + for _, arg := range args { + if !strings.Contains(arg, "-test.coverprofile") { + out = append(out, arg) + } + } + return +} + +// redefine all the flags otherwise the go testing tool +// is not able to parse them ... +var _ = flag.Int("db-open-attempts", 10, "number of attempts to open DB if it's locked by other instance") +var _ = flag.Bool("dep-follow-suggests", false, "when processing dependencies, follow Suggests") +var _ = flag.Bool("dep-follow-source", false, "when processing dependencies, follow from binary to Source packages") +var _ = flag.Bool("dep-follow-recommends", false, "when processing dependencies, follow Recommends") +var _ = flag.Bool("dep-follow-all-variants", false, "when processing dependencies, follow a & b if dependency is 'a|b'") +var _ = flag.Bool("dep-verbose-resolve", false, "when processing dependencies, print detailed logs") +var _ = flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available") +var _ = flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)") +var _ = flag.String("gpg-provider", "", "PGP implementation (\"gpg\", \"gpg1\", \"gpg2\" for external gpg or \"internal\" for Go internal implementation)") + +var _ = flag.String("cpuprofile", "", "write cpu profile to file") +var _ = flag.String("memprofile", "", "write memory profile to this file") +var _ = flag.String("memstats", "", "write memory stats periodically to this file") +var _ = flag.Duration("meminterval", 100*time.Millisecond, "memory stats dump interval") + +var _ = flag.Bool("raw", false, "raw") +var _ = flag.String("sort", "false", "sort") +var _ = flag.Bool("json", false, "json") + +func TestRunMain(t *testing.T) { + if Version == "" { + Version = "unknown" + } + + aptly.Version = Version + + args := filterOutTestArgs(os.Args[1:]) + root := cmd.RootCommand() + root.UsageLine = "aptly" + + fmt.Printf("EXIT: %d\n", cmd.Run(root, args, true)) +} diff --git a/man/Makefile b/man/Makefile index de73526d..064630cb 100644 --- a/man/Makefile +++ b/man/Makefile @@ -4,7 +4,7 @@ all: $(RUBYBINPATH)/ronn generate $(RUBYBINPATH)/ronn: gem install --user-install specific_install - gem specific_install --user-install -l smira/ronn + gem specific_install --user-install -l https://github.com/smira/ronn.git -b 49e19e2409e462a96fd0f2a50ceead07f392893d generate: PATH=$(RUBYBINPATH):$(PATH) go run ../_man/gen.go diff --git a/man/aptly.1 b/man/aptly.1 index 4cc042a4..fe986f0f 100644 --- a/man/aptly.1 +++ b/man/aptly.1 @@ -84,6 +84,7 @@ Configuration file is stored in JSON format (default values shown below): "plusWorkaround": false, "disableMultiDel": false, "forceSigV2": false, + "forceVirtualHostedStyle": false, "debug": false } }, @@ -265,6 +266,10 @@ bucket name (optional) disable Signature V4 support, useful with non\-AWS S3\-compatible object stores which do not support SigV4, shouldn\(cqt be enabled for AWS . .TP +\fBforceVirtualHostedStyle\fR +(optional) disable path style visit, useful with non\-AWS S3\-compatible object stores which only support virtual hosted style +. +.TP \fBdebug\fR (optional) enables detailed request/response dump for each S3 operation . @@ -1500,6 +1505,10 @@ don\(cqt sign Release files with GPG \-\fBsuite\fR= suite to publish (defaults to distribution) . +.TP +\-\fBcodename\fR= +codename to publish (defaults to distribution) +. .SH "PUBLISH SNAPSHOT" \fBaptly\fR \fBpublish\fR \fBsnapshot\fR \fIname\fR [[\fIendpoint\fR:]\fIprefix\fR] . @@ -1603,6 +1612,10 @@ don\(cqt sign Release files with GPG \-\fBsuite\fR= suite to publish (defaults to distribution) . +.TP +\-\fBcodename\fR= +codename to publish (defaults to distribution) +. .SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SNAPSHOT" \fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [[\fIendpoint\fR:]\fIprefix\fR] \fInew\-snapshot\fR . diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index 82cc1dfc..baab5ff6 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -19,15 +19,19 @@ aptly has integrated help that matches contents of this manual page, to get help ## CONFIGURATION aptly looks for configuration file first in `~/.aptly.conf` then -in `/etc/aptly.conf` and, if no config file found, new one is created in +in `/usr/local/etc/aptly.conf` and `/etc/aptly.conf`. If no config file found (or they are not readable), a new one is created in the home directory. If `-config=` flag is specified, aptly would use config file at specified location. Also aptly needs root directory for database, package and published repository storage. -If not specified, directory defaults to `~/.aptly`, it will be created if missing. +If not specified, directory defaults to `~/.aptly/`, it will be created if missing. Configuration file is stored in JSON format (default values shown below): { "rootDir": "$HOME/.aptly", + "databaseBackend": { + "type": "", + "url": "" + }, "downloadConcurrency": 4, "downloadSpeedLimit": 0, "downloadRetries": 0, @@ -43,6 +47,16 @@ Configuration file is stored in JSON format (default values shown below): "gpgDisableVerify": false, "gpgProvider": "gpg", "downloadSourcePackages": false, + "packagePoolStorage": { + "path": "$ROOTDIR/pool", + "azure": { + "accountName": "", + "accountKey": "", + "container": "repo", + "prefix": "", + "endpoint": "" + } + }, "skipLegacyPool": true, "ppaDistributorID": "ubuntu", "ppaCodename": "", @@ -76,6 +90,7 @@ Configuration file is stored in JSON format (default values shown below): "plusWorkaround": false, "disableMultiDel": false, "forceSigV2": false, + "forceVirtualHostedStyle": true, "debug": false } }, @@ -95,8 +110,8 @@ Configuration file is stored in JSON format (default values shown below): "accountName": "", "accountKey": "", "container": "repo", - "prefix": "" - "endpoint": "blob.core.windows.net" + "prefix": "", + "endpoint": "" } } } @@ -104,9 +119,13 @@ Configuration file is stored in JSON format (default values shown below): Options: * `rootDir`: - is root of directory storage to store database (`rootDir`/db), downloaded packages (`rootDir`/pool) and + is root of directory storage to store database (`rootDir`/db), + the default for downloaded packages (`rootDir`/pool) and the default for published repositories (`rootDir`/public) + * `databaseBackend`: + the database config; if this config is empty, use levledb backend by default + * `downloadConcurrency`: is a number of parallel download threads to use when downloading packages @@ -157,6 +176,14 @@ Options: if enabled, all mirrors created would have flag set to download source packages; this setting could be controlled on per-mirror basis with `-with-sources` flag + * `packagePoolStorage`: + configures the location to store downloaded packages (defaults to the + path `$ROOTDIR/pool`), by setting the value of the `type`: + * `path`: store the packages in the given path + * `azure`: store the packages in the given Azure Blob Storage container + (see the section on Azure publishing below for information on the + configuration) + * `skipLegacyPool`: in aptly up to version 1.0.0, package files were stored in internal package pool with MD5-dervied path, since 1.1.0 package pool layout was changed; @@ -177,6 +204,22 @@ Options: * `SwiftPublishEndpoints`: configuration of OpenStack Swift publishing endpoints (see below) + * `AzurePublishEndpoints`: + configuration of Azure publishing endpoints (see below) + +## CUSTOM PACKAGE POOLS + +aptly defaults to storing downloaded packages at `rootDir/`pool. In order to +change this, you can set the `type` key within `packagePoolStorage` to one of +two values: + + * `local`: Store the package pool locally (the default). In order to change + the path, additionally set the `path` key within `packagePoolStorage` to + the desired location. + * `azure`: Store the package pool in an Azure Blob Storage container. Any + keys in the below section on Azure publishing may be set on the + `packagePoolStorage` object in order to configure the Azure connection. + ## FILESYSTEM PUBLISHING ENDPOINTS aptly defaults to publish to a single publish directory under `rootDir`/public. For @@ -251,6 +294,9 @@ and associated settings: * `forceSigV2`: (optional) disable Signature V4 support, useful with non-AWS S3-compatible object stores which do not support SigV4, shouldn't be enabled for AWS + * `forceVirtualHostedStyle`: + (optional) disable path style visit, useful with non-AWS S3-compatible object stores + which only support virtual hosted style * `debug`: (optional) enables detailed request/response dump for each S3 operation @@ -284,6 +330,24 @@ publishing prefix on the command line, e.g.: `aptly publish snapshot jessie-main swift:test:` +## AZURE PUBLISHING ENDPOINTS + +aptly can be configured to publish repositories directly to Microsoft Azure Blob +Storage. First, publishing endpoints should be described in the aptly +configuration file. Each endpoint has its name and associated settings: + + * `container`: + container name + * `prefix`: + (optional) do publishing under specified prefix in the container, defaults to + no prefix (container root) + * `accountName`, `accountKey`: + Azure storage account access key to access blob storage + * `endpoint`: + endpoint URL to connect to, as described in + [the Azure documentation](https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string); + defaults to `https://$accountName.blob.core.windows.net` + ## PACKAGE QUERY Some commands accept package queries to identify list of packages to process. diff --git a/pgp/gnupg.go b/pgp/gnupg.go index 99d06621..63076c3e 100644 --- a/pgp/gnupg.go +++ b/pgp/gnupg.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -164,8 +163,8 @@ func NewGpgVerifier(finder GPGFinder) *GpgVerifier { } // InitKeyring verifies that gpg is installed and some keys are trusted -func (g *GpgVerifier) InitKeyring() error { - if len(g.keyRings) == 0 { +func (g *GpgVerifier) InitKeyring(verbose bool) error { + if len(g.keyRings) == 0 && verbose { // using default keyring output, err := exec.Command(g.gpg, "--no-default-keyring", "--no-auto-check-trustdb", "--keyring", "trustedkeys.gpg", "--list-keys").Output() if err == nil && len(output) == 0 { @@ -200,7 +199,7 @@ func (g *GpgVerifier) runGpgv(args []string, context string, showKeyTip bool) (* args = append([]string{"--status-fd", "3"}, args...) cmd := exec.Command(g.gpgv, args...) - tempf, err := ioutil.TempFile("", "aptly-gpg-status") + tempf, err := os.CreateTemp("", "aptly-gpg-status") if err != nil { return nil, err } @@ -278,7 +277,7 @@ func (g *GpgVerifier) runGpgv(args []string, context string, showKeyTip bool) (* func (g *GpgVerifier) VerifyDetachedSignature(signature, cleartext io.Reader, showKeyTip bool) error { args := g.argsKeyrings() - sigf, err := ioutil.TempFile("", "aptly-gpg") + sigf, err := os.CreateTemp("", "aptly-gpg") if err != nil { return err } @@ -290,7 +289,7 @@ func (g *GpgVerifier) VerifyDetachedSignature(signature, cleartext io.Reader, sh return err } - clearf, err := ioutil.TempFile("", "aptly-gpg") + clearf, err := os.CreateTemp("", "aptly-gpg") if err != nil { return err } @@ -323,7 +322,7 @@ func (g *GpgVerifier) IsClearSigned(clearsigned io.Reader) (bool, error) { func (g *GpgVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*KeyInfo, error) { args := g.argsKeyrings() - clearf, err := ioutil.TempFile("", "aptly-gpg") + clearf, err := os.CreateTemp("", "aptly-gpg") if err != nil { return nil, err } @@ -341,7 +340,7 @@ func (g *GpgVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) // ExtractClearsigned extracts cleartext from clearsigned file WITHOUT signature verification func (g *GpgVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, err error) { - clearf, err := ioutil.TempFile("", "aptly-gpg") + clearf, err := os.CreateTemp("", "aptly-gpg") if err != nil { return } @@ -353,7 +352,7 @@ func (g *GpgVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, return } - text, err = ioutil.TempFile("", "aptly-gpg") + text, err = os.CreateTemp("", "aptly-gpg") if err != nil { return } diff --git a/pgp/gnupg_test.go b/pgp/gnupg_test.go index e1a30a0b..d17dbe20 100644 --- a/pgp/gnupg_test.go +++ b/pgp/gnupg_test.go @@ -94,7 +94,7 @@ func (s *Gnupg1VerifierSuite) SetUpTest(c *C) { s.verifier = NewGpgVerifier(finder) s.verifier.AddKeyring("./trusted.gpg") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) } type Gnupg1SignerSuite struct { @@ -110,8 +110,8 @@ func (s *Gnupg1SignerSuite) SetUpTest(c *C) { c.Skip(err.Error()) } - s.keyringNoPassphrase = [2]string{"keyrings/aptly.pub", "keyrings/aptly.sec"} - s.keyringPassphrase = [2]string{"keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec"} + s.keyringNoPassphrase = [2]string{"../system/files/aptly.pub", "../system/files/aptly.sec"} + s.keyringPassphrase = [2]string{"../system/files/aptly_passphrase.pub", "../system/files/aptly_passphrase.sec"} s.passphraseKey = "F30E8CB9CDDE2AF8" s.noPassphraseKey = "21DBB89C16DB3E6D" @@ -119,10 +119,10 @@ func (s *Gnupg1SignerSuite) SetUpTest(c *C) { s.signer.SetBatch(true) s.verifier = &GoVerifier{} - s.verifier.AddKeyring("./keyrings/aptly.pub") - s.verifier.AddKeyring("./keyrings/aptly_passphrase.pub") + s.verifier.AddKeyring("../system/files/aptly.pub") + s.verifier.AddKeyring("../system/files/aptly_passphrase.pub") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) s.SignerSuite.SetUpTest(c) } @@ -143,7 +143,7 @@ func (s *Gnupg2VerifierSuite) SetUpTest(c *C) { s.verifier = NewGpgVerifier(finder) s.verifier.AddKeyring("./trusted.gpg") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) } type Gnupg2SignerSuite struct { @@ -183,7 +183,7 @@ func (s *Gnupg2SignerSuite) SetUpTest(c *C) { args = append(args, "--pinentry-mode", "loopback") } } - args = append(args, "keyrings/aptly2"+item.suffix+".sec.armor") + args = append(args, "../system/files/aptly2"+item.suffix+".sec.armor") output, err := exec.Command(gpg, args...).CombinedOutput() c.Log(string(output)) @@ -193,14 +193,14 @@ func (s *Gnupg2SignerSuite) SetUpTest(c *C) { // import public keys into gpg2 // we can't use pre-built keyrings as gpg 2.0.x and 2.1+ have different keyring formats for _, suffix := range []string{"", "_passphrase"} { - output, err := exec.Command(gpg, "--no-default-keyring", "--batch", "--keyring", "./keyrings/aptly2"+suffix+".gpg", - "--import", "keyrings/aptly2"+suffix+".pub.armor").CombinedOutput() + output, err := exec.Command(gpg, "--no-default-keyring", "--batch", "--keyring", "../system/files/aptly2"+suffix+".gpg", + "--import", "../system/files/aptly2"+suffix+".pub.armor").CombinedOutput() c.Log(string(output)) c.Check(err, IsNil) } - s.keyringNoPassphrase = [2]string{"./keyrings/aptly2.gpg", ""} - s.keyringPassphrase = [2]string{"./keyrings/aptly2_passphrase.gpg", ""} + s.keyringNoPassphrase = [2]string{"../system/files/aptly2.gpg", ""} + s.keyringPassphrase = [2]string{"../system/files/aptly2_passphrase.gpg", ""} s.noPassphraseKey = "751DF85C2B220D45" s.passphraseKey = "6656CD181E92D2D5" @@ -208,9 +208,9 @@ func (s *Gnupg2SignerSuite) SetUpTest(c *C) { s.signer.SetBatch(true) s.verifier = &GoVerifier{} - s.verifier.AddKeyring("./keyrings/aptly2_trusted.pub") + s.verifier.AddKeyring("../system/files/aptly2_trusted.pub") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) s.skipDefaultKey = true @@ -220,6 +220,6 @@ func (s *Gnupg2SignerSuite) SetUpTest(c *C) { func (s *Gnupg2SignerSuite) TearDownTest(c *C) { s.SignerSuite.TearDownTest(c) - os.Remove("./keyrings/aptly2.gpg") - os.Remove("./keyrings/aptly2_passphrase.gpg") + os.Remove("../system/files/aptly2.gpg") + os.Remove("../system/files/aptly2_passphrase.gpg") } diff --git a/pgp/internal.go b/pgp/internal.go index add64267..9796295c 100644 --- a/pgp/internal.go +++ b/pgp/internal.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "path/filepath" "sort" @@ -14,12 +13,10 @@ import ( "github.com/pkg/errors" - // TODO: replace crypto/openpgp since it is deprecated - // https://github.com/golang/go/issues/44226 - "golang.org/x/crypto/openpgp" //nolint:staticcheck - "golang.org/x/crypto/openpgp/clearsign" //nolint:staticcheck - openpgp_errors "golang.org/x/crypto/openpgp/errors" //nolint:staticcheck - "golang.org/x/crypto/openpgp/packet" //nolint:staticcheck + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/clearsign" + openpgp_errors "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/ProtonMail/go-crypto/openpgp/packet" "golang.org/x/term" ) @@ -47,7 +44,8 @@ type GoSigner struct { signerConfig *packet.Config } -// SetBatch controls whether we allowed to interact with user +// SetBatch controls whether we allowed to interact with user, for example +// for getting the passphrase from stdin. func (g *GoSigner) SetBatch(batch bool) { g.batch = batch } @@ -83,7 +81,7 @@ func (g *GoSigner) Init() error { } defer passF.Close() - contents, err := ioutil.ReadAll(passF) + contents, err := io.ReadAll(passF) if err != nil { return errors.Wrap(err, "error reading passphrase file") } @@ -285,7 +283,7 @@ type GoVerifier struct { } // InitKeyring verifies that gpg is installed and some keys are trusted -func (g *GoVerifier) InitKeyring() error { +func (g *GoVerifier) InitKeyring(verbose bool) error { var err error if len(g.keyRingFiles) == 0 { @@ -306,7 +304,7 @@ func (g *GoVerifier) InitKeyring() error { } } - if len(g.trustedKeyring) == 0 { + if len(g.trustedKeyring) == 0 && verbose { fmt.Printf("\nLooks like your keyring with trusted keys is empty. You might consider importing some keys.\n") if len(g.keyRingFiles) == 0 { // using default keyring @@ -400,7 +398,7 @@ func (g *GoVerifier) VerifyDetachedSignature(signature, cleartext io.Reader, sho // IsClearSigned returns true if file contains signature func (g *GoVerifier) IsClearSigned(clearsigned io.Reader) (bool, error) { - signedBuffer, err := ioutil.ReadAll(clearsigned) + signedBuffer, err := io.ReadAll(clearsigned) if err != nil { return false, errors.Wrap(err, "failed to read clearsigned data") } @@ -412,7 +410,7 @@ func (g *GoVerifier) IsClearSigned(clearsigned io.Reader) (bool, error) { // VerifyClearsigned verifies clearsigned file using gpgv func (g *GoVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*KeyInfo, error) { - signedBuffer, err := ioutil.ReadAll(clearsigned) + signedBuffer, err := io.ReadAll(clearsigned) if err != nil { return nil, errors.Wrap(err, "failed to read clearsigned data") } @@ -451,7 +449,7 @@ func (g *GoVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) ( // ExtractClearsigned extracts cleartext from clearsigned file WITHOUT signature verification func (g *GoVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, err error) { var signedBuffer []byte - signedBuffer, err = ioutil.ReadAll(clearsigned) + signedBuffer, err = io.ReadAll(clearsigned) if err != nil { return nil, errors.Wrap(err, "failed to read clearsigned data") } @@ -461,7 +459,7 @@ func (g *GoVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File, e return nil, errors.New("no clearsigned data found") } - text, err = ioutil.TempFile("", "aptly-gpg") + text, err = os.CreateTemp("", "aptly-gpg") if err != nil { return } diff --git a/pgp/internal_test.go b/pgp/internal_test.go index 1780e73d..8601179f 100644 --- a/pgp/internal_test.go +++ b/pgp/internal_test.go @@ -14,7 +14,7 @@ func (s *GoVerifierSuite) SetUpTest(c *C) { s.verifier = &GoVerifier{} s.verifier.AddKeyring("./trusted.gpg") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) } type GoSignerSuite struct { @@ -24,8 +24,8 @@ type GoSignerSuite struct { var _ = Suite(&GoSignerSuite{}) func (s *GoSignerSuite) SetUpTest(c *C) { - s.keyringNoPassphrase = [2]string{"keyrings/aptly.pub", "keyrings/aptly.sec"} - s.keyringPassphrase = [2]string{"keyrings/aptly_passphrase.pub", "keyrings/aptly_passphrase.sec"} + s.keyringNoPassphrase = [2]string{"../system/files/aptly.pub", "../system/files/aptly.sec"} + s.keyringPassphrase = [2]string{"../system/files/aptly_passphrase.pub", "../system/files/aptly_passphrase.sec"} s.passphraseKey = "F30E8CB9CDDE2AF8" s.noPassphraseKey = "21DBB89C16DB3E6D" @@ -33,10 +33,10 @@ func (s *GoSignerSuite) SetUpTest(c *C) { s.signer.SetBatch(true) s.verifier = &GoVerifier{} - s.verifier.AddKeyring("./keyrings/aptly.pub") - s.verifier.AddKeyring("./keyrings/aptly_passphrase.pub") + s.verifier.AddKeyring("../system/files/aptly.pub") + s.verifier.AddKeyring("../system/files/aptly_passphrase.pub") - c.Assert(s.verifier.InitKeyring(), IsNil) + c.Assert(s.verifier.InitKeyring(false), IsNil) s.SignerSuite.SetUpTest(c) } diff --git a/pgp/keyrings/aptly.pub b/pgp/keyrings/aptly.pub deleted file mode 100644 index 08758e43..00000000 Binary files a/pgp/keyrings/aptly.pub and /dev/null differ diff --git a/pgp/keyrings/aptly.sec b/pgp/keyrings/aptly.sec deleted file mode 100644 index f90e1c91..00000000 Binary files a/pgp/keyrings/aptly.sec and /dev/null differ diff --git a/pgp/keyrings/aptly_passphrase.pub b/pgp/keyrings/aptly_passphrase.pub deleted file mode 100644 index ec24aa32..00000000 Binary files a/pgp/keyrings/aptly_passphrase.pub and /dev/null differ diff --git a/pgp/keyrings/aptly_passphrase.sec b/pgp/keyrings/aptly_passphrase.sec deleted file mode 100644 index 2ffe24ef..00000000 Binary files a/pgp/keyrings/aptly_passphrase.sec and /dev/null differ diff --git a/pgp/openpgp.go b/pgp/openpgp.go index 8577fc00..335a9ad9 100644 --- a/pgp/openpgp.go +++ b/pgp/openpgp.go @@ -11,12 +11,10 @@ import ( "strconv" "time" - // TODO: replace crypto/openpgp since it is deprecated - // https://github.com/golang/go/issues/44226 - "golang.org/x/crypto/openpgp" //nolint:staticcheck - "golang.org/x/crypto/openpgp/armor" //nolint:staticcheck - "golang.org/x/crypto/openpgp/errors" //nolint:staticcheck - "golang.org/x/crypto/openpgp/packet" //nolint:staticcheck + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/ProtonMail/go-crypto/openpgp/packet" ) // hashForSignature returns a pair of hashes that can be used to verify a @@ -94,12 +92,6 @@ func checkDetachedSignature(keyring openpgp.KeyRing, signed, signature io.Reader sigType = sig.SigType creationTime = sig.CreationTime pubKeyAlgo = sig.PubKeyAlgo - case *packet.SignatureV3: - issuerKeyID = sig.IssuerKeyId - hashFunc = sig.Hash - sigType = sig.SigType - creationTime = sig.CreationTime - pubKeyAlgo = sig.PubKeyAlgo default: return nil, 0, errors.StructuralError("non signature packet found") } @@ -129,8 +121,6 @@ func checkDetachedSignature(keyring openpgp.KeyRing, signed, signature io.Reader switch sig := p.(type) { case *packet.Signature: err = key.PublicKey.VerifySignature(h, sig) - case *packet.SignatureV3: - err = key.PublicKey.VerifySignatureV3(h, sig) default: panic("unreachable") } @@ -192,6 +182,8 @@ func pubkeyAlgorithmName(algorithm packet.PublicKeyAlgorithm) string { return "EDCH" case packet.PubKeyAlgoECDSA: return "ECDSA" + case packet.PubKeyAlgoEdDSA: + return "EdDSA" } return "unknown" diff --git a/pgp/pgp.go b/pgp/pgp.go index 37ef497c..228dbaaa 100644 --- a/pgp/pgp.go +++ b/pgp/pgp.go @@ -51,7 +51,7 @@ type Signer interface { // Verifier interface describes signature verification factility type Verifier interface { - InitKeyring() error + InitKeyring(verbose bool) error AddKeyring(keyring string) VerifyDetachedSignature(signature, cleartext io.Reader, showKeyTip bool) error IsClearSigned(clearsigned io.Reader) (bool, error) diff --git a/s3/public.go b/s3/public.go index b44c7fe6..47623a00 100644 --- a/s3/public.go +++ b/s3/public.go @@ -1,6 +1,7 @@ package s3 import ( + "context" "fmt" "io" "os" @@ -9,31 +10,52 @@ import ( "github.com/aptly-dev/aptly/aptly" "github.com/aptly-dev/aptly/utils" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/corehandlers" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" + + "github.com/aws/aws-sdk-go-v2/aws" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/smithy-go" + "github.com/aws/smithy-go/logging" "github.com/pkg/errors" - awsauth "github.com/smira/go-aws-auth" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" ) const errCodeNotFound = "NotFound" +type logger struct{} + +func (l *logger) Logf(classification logging.Classification, format string, v ...interface{}) { + var e *zerolog.Event + switch classification { + case logging.Debug: + e = log.Logger.Debug() + case logging.Warn: + e = log.Logger.Warn() + default: + e = log.Logger.Error() + } + e.Msgf(format, v...) +} + // PublishedStorage abstract file system with published files (actually hosted on S3) type PublishedStorage struct { - s3 *s3.S3 + s3 *s3.Client config *aws.Config bucket string - acl string + acl types.ObjectCannedACL prefix string - storageClass string - encryptionMethod string + storageClass types.StorageClass + encryptionMethod types.ServerSideEncryption plusWorkaround bool disableMultiDel bool pathCache map[string]string + + // True if the bucket encrypts objects by default. + encryptByDefault bool } // Check interface @@ -44,90 +66,96 @@ var ( // NewPublishedStorageRaw creates published storage from raw aws credentials func NewPublishedStorageRaw( bucket, defaultACL, prefix, storageClass, encryptionMethod string, - plusWorkaround, disabledMultiDel bool, - config *aws.Config, + plusWorkaround, disabledMultiDel, forceVirtualHostedStyle bool, + config *aws.Config, endpoint string, ) (*PublishedStorage, error) { - if defaultACL == "" { - defaultACL = "private" + var acl types.ObjectCannedACL + if defaultACL == "" || defaultACL == "private" { + acl = types.ObjectCannedACLPrivate + } else if defaultACL == "public-read" { + acl = types.ObjectCannedACLPublicRead } else if defaultACL == "none" { - defaultACL = "" + acl = "" } - if storageClass == "STANDARD" { + if storageClass == string(types.StorageClassStandard) { storageClass = "" } - sess, err := session.NewSession(config) - if err != nil { - return nil, err + var baseEndpoint *string + if endpoint != "" { + baseEndpoint = aws.String(endpoint) } result := &PublishedStorage{ - s3: s3.New(sess), + s3: s3.NewFromConfig(*config, func(o *s3.Options) { + o.UsePathStyle = !forceVirtualHostedStyle + o.HTTPSignerV4 = v4.NewSigner() + o.BaseEndpoint = baseEndpoint + }), bucket: bucket, config: config, - acl: defaultACL, + acl: acl, prefix: prefix, - storageClass: storageClass, - encryptionMethod: encryptionMethod, + storageClass: types.StorageClass(storageClass), + encryptionMethod: types.ServerSideEncryption(encryptionMethod), plusWorkaround: plusWorkaround, disableMultiDel: disabledMultiDel, } + result.setKMSFlag() + return result, nil } +func (storage *PublishedStorage) setKMSFlag() { + params := &s3.GetBucketEncryptionInput{ + Bucket: aws.String(storage.bucket), + } + output, err := storage.s3.GetBucketEncryption(context.TODO(), params) + if err != nil { + return + } + + if len(output.ServerSideEncryptionConfiguration.Rules) > 0 && + output.ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.SSEAlgorithm == "aws:kms" { + storage.encryptByDefault = true + } +} + // NewPublishedStorage creates new instance of PublishedStorage with specified S3 access // keys, region and bucket name -func NewPublishedStorage(accessKey, secretKey, sessionToken, region, endpoint, bucket, defaultACL, prefix, - storageClass, encryptionMethod string, plusWorkaround, disableMultiDel, forceSigV2, debug bool) (*PublishedStorage, error) { - - config := &aws.Config{ - Region: aws.String(region), - } - - if endpoint != "" { - config = config.WithEndpoint(endpoint).WithS3ForcePathStyle(true) - } +func NewPublishedStorage( + accessKey, secretKey, sessionToken, region, endpoint, bucket, defaultACL, prefix, storageClass, encryptionMethod string, + plusWorkaround, disableMultiDel, _, forceVirtualHostedStyle, debug bool) (*PublishedStorage, error) { + opts := []func(*config.LoadOptions) error{config.WithRegion(region)} if accessKey != "" { - config.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, sessionToken) + opts = append(opts, config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, sessionToken))) } if debug { - config = config.WithLogLevel(aws.LogDebug) + opts = append(opts, config.WithLogger(&logger{})) + } + + config, err := config.LoadDefaultConfig(context.TODO(), opts...) + if err != nil { + return nil, err } result, err := NewPublishedStorageRaw(bucket, defaultACL, prefix, storageClass, - encryptionMethod, plusWorkaround, disableMultiDel, config) - - if err == nil && forceSigV2 { - creds := []awsauth.Credentials{} - - if accessKey != "" { - creds = append(creds, awsauth.Credentials{ - AccessKeyID: accessKey, - SecretAccessKey: secretKey, - }) - } - - result.s3.Handlers.Sign.Clear() - result.s3.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) - result.s3.Handlers.Sign.PushBack(func(req *request.Request) { - awsauth.SignS3(req.HTTPRequest, creds...) - }) - } + encryptionMethod, plusWorkaround, disableMultiDel, forceVirtualHostedStyle, &config, endpoint) return result, err } // String func (storage *PublishedStorage) String() string { - return fmt.Sprintf("S3: %s:%s/%s", *storage.config.Region, storage.bucket, storage.prefix) + return fmt.Sprintf("S3: %s:%s/%s", storage.config.Region, storage.bucket, storage.prefix) } // MkDir creates directory recursively under public path -func (storage *PublishedStorage) MkDir(path string) error { +func (storage *PublishedStorage) MkDir(_ string) error { // no op for S3 return nil } @@ -158,12 +186,12 @@ func (storage *PublishedStorage) getMD5(path string) (string, error) { Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path)), } - output, err := storage.s3.HeadObject(params) + output, err := storage.s3.HeadObject(context.TODO(), params) if err != nil { return "", err } - return aws.StringValue(output.Metadata["Md5"]), nil + return output.Metadata["Md5"], nil } // putFile uploads file-like object to @@ -173,21 +201,21 @@ func (storage *PublishedStorage) putFile(path string, source io.ReadSeeker, sour Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path)), Body: source, - ACL: aws.String(storage.acl), + ACL: storage.acl, } if storage.storageClass != "" { - params.StorageClass = aws.String(storage.storageClass) + params.StorageClass = types.StorageClass(storage.storageClass) } if storage.encryptionMethod != "" { - params.ServerSideEncryption = aws.String(storage.encryptionMethod) + params.ServerSideEncryption = types.ServerSideEncryption(storage.encryptionMethod) } if sourceMD5 != "" { - params.Metadata = map[string]*string{ - "Md5": aws.String(sourceMD5), + params.Metadata = map[string]string{ + "Md5": sourceMD5, } } - _, err := storage.s3.PutObject(params) + _, err := storage.s3.PutObject(context.TODO(), params) if err != nil { return err } @@ -209,13 +237,12 @@ func (storage *PublishedStorage) Remove(path string) error { Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path)), } - _, err := storage.s3.DeleteObject(params) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == s3.ErrCodeNoSuchBucket { - // ignore 'no such bucket' errors on removal - return nil - } + + if _, err := storage.s3.DeleteObject(context.TODO(), params); err != nil { + var notFoundErr *smithy.GenericAPIError + if errors.As(err, ¬FoundErr) && notFoundErr.Code == "NoSuchBucket" { + // ignore 'no such bucket' errors on removal + return nil } return errors.Wrap(err, fmt.Sprintf("error deleting %s from %s", path, storage)) } @@ -224,20 +251,21 @@ func (storage *PublishedStorage) Remove(path string) error { // try to remove workaround version, but don't care about result _ = storage.Remove(strings.Replace(path, "+", " ", -1)) } + + delete(storage.pathCache, path) + return nil } // RemoveDirs removes directory structure under public path -func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error { +func (storage *PublishedStorage) RemoveDirs(path string, _ aptly.Progress) error { const page = 1000 filelist, _, err := storage.internalFilelist(path, false) if err != nil { - if aerr, ok := errors.Cause(err).(awserr.Error); ok { - if aerr.Code() == s3.ErrCodeNoSuchBucket { - // ignore 'no such bucket' errors on removal - return nil - } + if errors.Is(err, &types.NoSuchBucket{}) { + // ignore 'no such bucket' errors on removal + return nil } return err } @@ -248,10 +276,11 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path, filelist[i])), } - _, err := storage.s3.DeleteObject(params) + _, err := storage.s3.DeleteObject(context.TODO(), params) if err != nil { return fmt.Errorf("error deleting path %s from %s: %s", filelist[i], storage, err) } + delete(storage.pathCache, filepath.Join(path, filelist[i])) } } else { numParts := (len(filelist) + page - 1) / page @@ -263,26 +292,30 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress } else { part = filelist[i*page : (i+1)*page] } - paths := make([]*s3.ObjectIdentifier, len(part)) + paths := make([]types.ObjectIdentifier, len(part)) for i := range part { - paths[i] = &s3.ObjectIdentifier{ + paths[i] = types.ObjectIdentifier{ Key: aws.String(filepath.Join(storage.prefix, path, part[i])), } } + quiet := true params := &s3.DeleteObjectsInput{ Bucket: aws.String(storage.bucket), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: paths, - Quiet: aws.Bool(true), + Quiet: &quiet, }, } - _, err := storage.s3.DeleteObjects(params) + _, err := storage.s3.DeleteObjects(context.TODO(), params) if err != nil { return fmt.Errorf("error deleting multiple paths from %s: %s", storage, err) } + for i := range part { + delete(storage.pathCache, filepath.Join(path, part[i])) + } } } @@ -291,19 +324,21 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress // LinkFromPool links package file from pool to dist's pool location // -// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/) +// publishedPrefix is desired prefix for the location in the pool. +// publishedRelPath is desired location in pool (like pool/component/liba/libav/) // sourcePool is instance of aptly.PackagePool // sourcePath is filepath to package file in package pool // // LinkFromPool returns relative path for the published file to be included in package index -func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName string, sourcePool aptly.PackagePool, +func (storage *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error { + publishedDirectory := filepath.Join(publishedPrefix, publishedRelPath) relPath := filepath.Join(publishedDirectory, fileName) poolPath := filepath.Join(storage.prefix, relPath) if storage.pathCache == nil { - paths, md5s, err := storage.internalFilelist("", true) + paths, md5s, err := storage.internalFilelist(filepath.Join(storage.prefix, publishedPrefix, "pool"), true) if err != nil { return errors.Wrap(err, "error caching paths under prefix") } @@ -319,7 +354,11 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin sourceMD5 := sourceChecksums.MD5 if exists { - if len(destinationMD5) != 32 { + if sourceMD5 == "" { + return fmt.Errorf("unable to compare object, MD5 checksum missing") + } + + if len(destinationMD5) != 32 || storage.encryptByDefault { // doesn’t look like a valid MD5, // attempt to fetch one from the metadata var err error @@ -330,17 +369,13 @@ func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName strin } storage.pathCache[relPath] = destinationMD5 } - if sourceMD5 == "" { - return fmt.Errorf("unable to compare object, MD5 checksum missing") - } if destinationMD5 == sourceMD5 { return nil } - if !force && destinationMD5 != sourceMD5 { + if !force { return fmt.Errorf("error putting file to %s: file already exists and is different: %s", poolPath, storage) - } } @@ -374,14 +409,22 @@ func (storage *PublishedStorage) internalFilelist(prefix string, hidePlusWorkaro prefix += "/" } - params := &s3.ListObjectsInput{ + maxKeys := int32(1000) + params := &s3.ListObjectsV2Input{ Bucket: aws.String(storage.bucket), Prefix: aws.String(prefix), - MaxKeys: aws.Int64(1000), + MaxKeys: &maxKeys, } - err = storage.s3.ListObjectsPages(params, func(contents *s3.ListObjectsOutput, lastPage bool) bool { - for _, key := range contents.Contents { + p := s3.NewListObjectsV2Paginator(storage.s3, params) + for i := 1; p.HasMorePages(); i++ { + page, err := p.NextPage(context.TODO()) + if err != nil { + return nil, nil, fmt.Errorf("failed to get page %d: %w", i, err) + } + + // Log the objects found + for _, key := range page.Contents { if storage.plusWorkaround && hidePlusWorkaround && strings.Contains(*key.Key, " ") { // if we use plusWorkaround, we want to hide those duplicates /// from listing @@ -395,9 +438,7 @@ func (storage *PublishedStorage) internalFilelist(prefix string, hidePlusWorkaro } md5s = append(md5s, strings.Replace(*key.ETag, "\"", "", -1)) } - - return true - }) + } if err != nil { return nil, nil, errors.WithMessagef(err, "error listing under prefix %s in %s: %s", prefix, storage, err) @@ -414,17 +455,17 @@ func (storage *PublishedStorage) RenameFile(oldName, newName string) error { Bucket: aws.String(storage.bucket), CopySource: aws.String(source), Key: aws.String(filepath.Join(storage.prefix, newName)), - ACL: aws.String(storage.acl), + ACL: storage.acl, } if storage.storageClass != "" { - params.StorageClass = aws.String(storage.storageClass) + params.StorageClass = storage.storageClass } if storage.encryptionMethod != "" { - params.ServerSideEncryption = aws.String(storage.encryptionMethod) + params.ServerSideEncryption = storage.encryptionMethod } - _, err := storage.s3.CopyObject(params) + _, err := storage.s3.CopyObject(context.TODO(), params) if err != nil { return fmt.Errorf("error copying %s -> %s in %s: %s", oldName, newName, storage, err) } @@ -439,21 +480,21 @@ func (storage *PublishedStorage) SymLink(src string, dst string) error { Bucket: aws.String(storage.bucket), CopySource: aws.String(filepath.Join(storage.bucket, storage.prefix, src)), Key: aws.String(filepath.Join(storage.prefix, dst)), - ACL: aws.String(storage.acl), - Metadata: map[string]*string{ - "SymLink": aws.String(src), + ACL: types.ObjectCannedACL(storage.acl), + Metadata: map[string]string{ + "SymLink": src, }, - MetadataDirective: aws.String("REPLACE"), + MetadataDirective: types.MetadataDirective("REPLACE"), } if storage.storageClass != "" { - params.StorageClass = aws.String(storage.storageClass) + params.StorageClass = types.StorageClass(storage.storageClass) } if storage.encryptionMethod != "" { - params.ServerSideEncryption = aws.String(storage.encryptionMethod) + params.ServerSideEncryption = types.ServerSideEncryption(storage.encryptionMethod) } - _, err := storage.s3.CopyObject(params) + _, err := storage.s3.CopyObject(context.TODO(), params) if err != nil { return fmt.Errorf("error symlinking %s -> %s in %s: %s", src, dst, storage, err) } @@ -472,13 +513,24 @@ func (storage *PublishedStorage) FileExists(path string) (bool, error) { Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path)), } - _, err := storage.s3.HeadObject(params) + _, err := storage.s3.HeadObject(context.TODO(), params) if err != nil { - aerr, ok := err.(awserr.Error) - if ok && aerr.Code() == errCodeNotFound { + var notFoundErr *types.NotFound + if errors.As(err, ¬FoundErr) { return false, nil } + // falback in case the above condidition fails + var opErr *smithy.OperationError + if errors.As(err, &opErr) { + var ae smithy.APIError + if errors.As(err, &ae) { + if ae.ErrorCode() == "NotFound" { + return false, nil + } + } + } + return false, err } @@ -492,10 +544,10 @@ func (storage *PublishedStorage) ReadLink(path string) (string, error) { Bucket: aws.String(storage.bucket), Key: aws.String(filepath.Join(storage.prefix, path)), } - output, err := storage.s3.HeadObject(params) + output, err := storage.s3.HeadObject(context.TODO(), params) if err != nil { return "", err } - return aws.StringValue(output.Metadata["SymLink"]), nil + return output.Metadata["SymLink"], nil } diff --git a/s3/public_test.go b/s3/public_test.go index 72fe21ac..83605e3e 100644 --- a/s3/public_test.go +++ b/s3/public_test.go @@ -2,14 +2,18 @@ package s3 import ( "bytes" + "context" "io/ioutil" "os" "path/filepath" + "sort" + "strings" . "gopkg.in/check.v1" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aptly-dev/aptly/files" "github.com/aptly-dev/aptly/utils" @@ -29,14 +33,18 @@ func (s *PublishedStorageSuite) SetUpTest(c *C) { c.Assert(err, IsNil) c.Assert(s.srv, NotNil) - s.storage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "test", "", "", "", "", false, true, false, false) + s.storage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "test", "", "", "", "", false, true, false, false, false) c.Assert(err, IsNil) - s.prefixedStorage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "test", "", "lala", "", "", false, true, false, false) + s.prefixedStorage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "test", "", "lala", "", "", false, true, false, false, false) c.Assert(err, IsNil) - s.noSuchBucketStorage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "no-bucket", "", "", "", "", false, true, false, false) + s.noSuchBucketStorage, err = NewPublishedStorage("aa", "bb", "", "test-1", s.srv.URL(), "no-bucket", "", "", "", "", false, true, false, false, false) c.Assert(err, IsNil) - _, err = s.storage.s3.CreateBucket(&s3.CreateBucketInput{Bucket: aws.String("test")}) + _, err = s.storage.s3.CreateBucket(context.TODO(), &s3.CreateBucketInput{ + Bucket: aws.String("test"), + CreateBucketConfiguration: &types.CreateBucketConfiguration{ + LocationConstraint: "test-1", + }}) c.Assert(err, IsNil) } @@ -44,8 +52,19 @@ func (s *PublishedStorageSuite) TearDownTest(c *C) { s.srv.Quit() } +func (s *PublishedStorageSuite) checkGetRequestsEqual(c *C, prefix string, expectedGetRequestUris []string) { + getRequests := make([]string, 0, len(s.srv.Requests)) + for _, r := range s.srv.Requests { + if r.Method == "GET" && strings.HasPrefix(r.RequestURI, prefix) { + getRequests = append(getRequests, r.RequestURI) + } + } + sort.Strings(getRequests) + c.Check(getRequests, DeepEquals, expectedGetRequestUris) +} + func (s *PublishedStorageSuite) GetFile(c *C, path string) []byte { - resp, err := s.storage.s3.GetObject(&s3.GetObjectInput{ + resp, err := s.storage.s3.GetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(s.storage.bucket), Key: aws.String(path), }) @@ -59,20 +78,20 @@ func (s *PublishedStorageSuite) GetFile(c *C, path string) []byte { } func (s *PublishedStorageSuite) AssertNoFile(c *C, path string) { - _, err := s.storage.s3.HeadObject(&s3.HeadObjectInput{ + _, err := s.storage.s3.HeadObject(context.TODO(), &s3.HeadObjectInput{ Bucket: aws.String(s.storage.bucket), Key: aws.String(path), }) - c.Assert(err, ErrorMatches, ".*\n.*status code: 404.*") + c.Assert(err, ErrorMatches, ".*StatusCode: 404.*") } func (s *PublishedStorageSuite) PutFile(c *C, path string, data []byte) { - _, err := s.storage.s3.PutObject(&s3.PutObjectInput{ + _, err := s.storage.s3.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String(s.storage.bucket), Key: aws.String(path), Body: bytes.NewReader(data), ContentType: aws.String("binary/octet-stream"), - ACL: aws.String("private"), + ACL: types.ObjectCannedACLPrivate, }) c.Assert(err, IsNil) } @@ -228,7 +247,7 @@ func (s *PublishedStorageSuite) TestRemoveDirsPlusWorkaround(c *C) { func (s *PublishedStorageSuite) TestRemoveDirsNoSuchBucket(c *C) { err := s.noSuchBucketStorage.RemoveDirs("a/b", nil) - c.Check(err, IsNil) + c.Check(err, ErrorMatches, ".*StatusCode: 404.*") } func (s *PublishedStorageSuite) TestRenameFile(c *C) { @@ -264,50 +283,118 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Assert(err, IsNil) // first link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // duplicate link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with conflict - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) c.Check(err, ErrorMatches, ".*file already exists and is different.*") c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with conflict and force - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) c.Check(err, IsNil) c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Spam")) // for prefixed storage: // first link from pool - err = s.prefixedStorage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) // 2nd link from pool, providing wrong path for source file // // this test should check that file already exists in S3 and skip upload (which would fail if not skipped) - s.prefixedStorage.pathCache = nil - err = s.prefixedStorage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, "wrong-looks-like-pathcache-doesnt-work", cksum1, false) + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, "wrong-looks-like-pathcache-doesnt-work", cksum1, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "lala/pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents")) // link from pool with nested file name - err = s.storage.LinkFromPool("dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) + err = s.storage.LinkFromPool("", "dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) c.Check(err, IsNil) c.Check(s.GetFile(c, "dists/jessie/non-free/installer-i386/current/images/netboot/boot.img.gz"), DeepEquals, []byte("Contents")) } +func (s *PublishedStorageSuite) TestLinkFromPoolCache(c *C) { + root := c.MkDir() + pool := files.NewPackagePool(root, false) + cs := files.NewMockChecksumStorage() + + tmpFile1 := filepath.Join(c.MkDir(), "mars-invaders_1.03.deb") + err := ioutil.WriteFile(tmpFile1, []byte("Contents"), 0644) + c.Assert(err, IsNil) + cksum1 := utils.ChecksumInfo{MD5: "c1df1da7a1ce305a3b60af9d5733ac1d"} + + src1, err := pool.Import(tmpFile1, "mars-invaders_1.03.deb", &cksum1, true, cs) + c.Assert(err, IsNil) + + // Publish two packages at the same publish prefix + err = s.storage.LinkFromPool("", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + err = s.storage.LinkFromPool("", filepath.Join("pool", "b"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + // Check only one listing request was done to the server + s.checkGetRequestsEqual(c, "/test?", []string{"/test?encryption=", "/test?encryption=", "/test?list-type=2&max-keys=1000&prefix=pool%2F"}) + + s.srv.Requests = nil + // Publish two packages at a different prefix + err = s.storage.LinkFromPool("publish-prefix", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + err = s.storage.LinkFromPool("publish-prefix", filepath.Join("pool", "b"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + // Check no listing request was done to the server (pathCache is used) + s.checkGetRequestsEqual(c, "/test?", []string{}) + + s.srv.Requests = nil + // Publish two packages at a prefixed storage + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "b"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + // Check only one listing request was done to the server + s.checkGetRequestsEqual(c, "/test?", []string{ + "/test?list-type=2&max-keys=1000&prefix=lala%2Flala%2Fpool%2F", + }) + + // Publish two packages at a prefixed storage plus a publish prefix. + s.srv.Requests = nil + err = s.prefixedStorage.LinkFromPool("publish-prefix", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + err = s.prefixedStorage.LinkFromPool("publish-prefix", filepath.Join("pool", "b"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + c.Check(err, IsNil) + + // Check no listing request was done to the server (pathCache is used) + s.checkGetRequestsEqual(c, "/test?", []string{}) + + // This step checks that files already exists in S3 and skip upload (which would fail if not skipped). + err = s.prefixedStorage.LinkFromPool("publish-prefix", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, "non-existent-file", cksum1, false) + c.Check(err, IsNil) + err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, "non-existent-file", cksum1, false) + c.Check(err, IsNil) + err = s.storage.LinkFromPool("publish-prefix", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, "non-existent-file", cksum1, false) + c.Check(err, IsNil) + err = s.storage.LinkFromPool("", filepath.Join("pool", "a"), "mars-invaders_1.03.deb", pool, "non-existent-file", cksum1, false) + c.Check(err, IsNil) +} + func (s *PublishedStorageSuite) TestSymLink(c *C) { s.PutFile(c, "a/b", []byte("test")) diff --git a/s3/server_test.go b/s3/server_test.go index 573097ab..08c29040 100644 --- a/s3/server_test.go +++ b/s3/server_test.go @@ -59,6 +59,12 @@ func (c *Config) send409Conflict() bool { return false } +// Request stores the method and URI of an HTTP request. +type Request struct { + Method string + RequestURI string +} + // Server is a fake S3 server for testing purposes. // All of the data for the server is kept in memory. type Server struct { @@ -68,6 +74,8 @@ type Server struct { mu sync.Mutex buckets map[string]*bucket config *Config + // Requests holds a log of all requests received by the server. + Requests []Request } type bucket struct { @@ -140,6 +148,7 @@ func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) { if debug { log.Printf("s3test %q %q", req.Method, req.URL) } + srv.Requests = append(srv.Requests, Request{req.Method, req.RequestURI}) a := &action{ srv: srv, w: w, @@ -330,6 +339,10 @@ type Owner struct { DisplayName string } +type CommonPrefix struct { + Prefix string +} + // The ListResp type holds the results of a List bucket operation. type ListResp struct { Name string @@ -344,7 +357,7 @@ type ListResp struct { // http://goo.gl/YjQTc IsTruncated bool Contents []Key - CommonPrefixes []string `xml:">Prefix"` + CommonPrefixes []CommonPrefix } // The Key type represents an item stored in an S3 bucket. @@ -403,7 +416,7 @@ func (r bucketResource) get(a *action) interface{} { MaxKeys: maxKeys, } - var prefixes []string + var prefixes []CommonPrefix for _, obj := range objs { if !strings.HasPrefix(obj.name, prefix) { continue @@ -413,7 +426,7 @@ func (r bucketResource) get(a *action) interface{} { if delimiter != "" { if i := strings.Index(obj.name[len(prefix):], delimiter); i >= 0 { name = obj.name[:len(prefix)+i+len(delimiter)] - if prefixes != nil && prefixes[len(prefixes)-1] == name { + if prefixes != nil && prefixes[len(prefixes)-1].Prefix == name { continue } isPrefix = true @@ -427,7 +440,7 @@ func (r bucketResource) get(a *action) interface{} { break } if isPrefix { - prefixes = append(prefixes, name) + prefixes = append(prefixes, CommonPrefix{name}) } else { // Contents contains only keys not found in CommonPrefixes resp.Contents = append(resp.Contents, obj.s3Key()) diff --git a/swift/public.go b/swift/public.go index 0ca4796c..d1f01849 100644 --- a/swift/public.go +++ b/swift/public.go @@ -113,7 +113,7 @@ func (storage *PublishedStorage) String() string { } // MkDir creates directory recursively under public path -func (storage *PublishedStorage) MkDir(path string) error { +func (storage *PublishedStorage) MkDir(_ string) error { // no op for Swift return nil } @@ -155,7 +155,7 @@ func (storage *PublishedStorage) Remove(path string) error { } // RemoveDirs removes directory structure under public path -func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error { +func (storage *PublishedStorage) RemoveDirs(path string, _ aptly.Progress) error { path = filepath.Join(storage.prefix, path) opts := swift.ObjectsOpts{ Prefix: path, @@ -188,15 +188,16 @@ func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress // LinkFromPool links package file from pool to dist's pool location // -// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/) +// publishedPrefix is desired prefix for the location in the pool. +// publishedRelPath is desired location in pool (like pool/component/liba/libav/) // sourcePool is instance of aptly.PackagePool // sourcePath is filepath to package file in package pool // // LinkFromPool returns relative path for the published file to be included in package index -func (storage *PublishedStorage) LinkFromPool(publishedDirectory, fileName string, sourcePool aptly.PackagePool, +func (storage *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error { - relPath := filepath.Join(publishedDirectory, fileName) + relPath := filepath.Join(publishedPrefix, publishedRelPath, fileName) poolPath := filepath.Join(storage.prefix, relPath) var ( diff --git a/swift/public_test.go b/swift/public_test.go index 31b633e8..620b94a2 100644 --- a/swift/public_test.go +++ b/swift/public_test.go @@ -6,7 +6,6 @@ import ( "math/rand" "os" "path/filepath" - "time" . "gopkg.in/check.v1" @@ -27,8 +26,6 @@ var _ = Suite(&PublishedStorageSuite{}) func (s *PublishedStorageSuite) SetUpTest(c *C) { var err error - rand.Seed(int64(time.Now().Nanosecond())) - s.TestAddress = fmt.Sprintf("localhost:%d", rand.Intn(10000)+20000) s.AuthURL = "http://" + s.TestAddress + "/v1.0" @@ -172,7 +169,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Assert(err, IsNil) // first link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) data, err := s.storage.conn.ObjectGetBytes("test", "pool/main/m/mars-invaders/mars-invaders_1.03.deb") @@ -180,7 +177,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(data, DeepEquals, []byte("Contents")) // duplicate link from pool - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false) c.Check(err, IsNil) data, err = s.storage.conn.ObjectGetBytes("test", "pool/main/m/mars-invaders/mars-invaders_1.03.deb") @@ -188,7 +185,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(data, DeepEquals, []byte("Contents")) // link from pool with conflict - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false) c.Check(err, ErrorMatches, ".*file already exists and is different.*") data, err = s.storage.conn.ObjectGetBytes("test", "pool/main/m/mars-invaders/mars-invaders_1.03.deb") @@ -196,7 +193,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(data, DeepEquals, []byte("Contents")) // link from pool with conflict and force - err = s.storage.LinkFromPool(filepath.Join("", "pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) + err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true) c.Check(err, IsNil) data, err = s.storage.conn.ObjectGetBytes("test", "pool/main/m/mars-invaders/mars-invaders_1.03.deb") @@ -204,7 +201,7 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) { c.Check(data, DeepEquals, []byte("Spam")) // link from pool with nested file name - err = s.storage.LinkFromPool("dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) + err = s.storage.LinkFromPool("", "dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false) c.Check(err, IsNil) data, err = s.storage.conn.ObjectGetBytes("test", "dists/jessie/non-free/installer-i386/current/images/netboot/boot.img.gz") diff --git a/system/Dockerfile b/system/Dockerfile new file mode 100644 index 00000000..c57f27df --- /dev/null +++ b/system/Dockerfile @@ -0,0 +1,25 @@ +FROM debian:bookworm-slim + +RUN echo deb http://deb.debian.org/debian bookworm-backports main > /etc/apt/sources.list.d/backports.list + +RUN apt-get update -y && apt-get install -y --no-install-recommends curl gnupg bzip2 xz-utils ca-certificates vim procps \ + golang/bookworm-backports golang-go/bookworm-backports golang-doc/bookworm-backports golang-src/bookworm-backports \ + make git python3 python3-requests-unixsocket python3-termcolor python3-swiftclient python3-boto python3-azure-storage \ + g++ python3-etcd3 python3-plyvel graphviz devscripts sudo dh-golang binutils-i686-linux-gnu binutils-aarch64-linux-gnu \ + binutils-arm-linux-gnueabihf bash-completion zip ruby3.1-dev && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN useradd -m --shell /bin/bash --home-dir /var/lib/aptly aptly +RUN sed -i 's/#force_color_prompt=yes/force_color_prompt=yes/' /var/lib/aptly/.bashrc + +RUN mkdir /work +WORKDIR /work/src +RUN chown aptly /work + +RUN cd /var/lib/aptly; git clone https://github.com/aptly-dev/aptly-fixture-db.git +RUN cd /var/lib/aptly; git clone https://github.com/aptly-dev/aptly-fixture-pool.git +RUN cd /var/lib/aptly; curl -O http://repo.aptly.info/system-tests/etcd.db.xz && xz -d etcd.db.xz +RUN echo "aptly ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aptly +ADD system/t13_etcd/install-etcd.sh /src/ +RUN /src/install-etcd.sh +RUN rm -rf /src diff --git a/system/api_lib.py b/system/api_lib.py index d6aaf97c..a41161ea 100644 --- a/system/api_lib.py +++ b/system/api_lib.py @@ -1,24 +1,41 @@ -from lib import BaseTest -import time -import json -import random -import string -import os import inspect +import json +import os +import random import shutil +import string +import time + +from lib import BaseTest +from testout import TestOut try: import requests except ImportError: requests = None +# States for returned tasks from the API +TASK_SUCCEEDED = 2 +TASK_FAILED = 3 + class APITest(BaseTest): """ BaseTest + testing aptly API """ aptly_server = None + aptly_out = None + debugOutput = True base_url = "127.0.0.1:8765" + configOverride = { + "FileSystemPublishEndpoints": { + "apiandserve": { + "rootDir": f"{os.environ['HOME']}/{BaseTest.aptlyDir}/apiandserve", + "linkMethod": "symlink" + } + }, + "enableSwaggerEndpoint": True + } def fixture_available(self): return super(APITest, self).fixture_available() and requests is not None @@ -27,11 +44,21 @@ class APITest(BaseTest): if APITest.aptly_server is None: super(APITest, self).prepare() - APITest.aptly_server = self._start_process("aptly api serve -no-lock -listen=%s" % (self.base_url),) - time.sleep(1) + APITest.aptly_out = TestOut() - if os.path.exists(os.path.join(os.environ["HOME"], ".aptly", "upload")): - shutil.rmtree(os.path.join(os.environ["HOME"], ".aptly", "upload")) + configPath = os.path.join(os.environ["HOME"], self.aptlyConfigFile) + APITest.aptly_server = self._start_process(f"aptly api serve -no-lock -config={configPath} -listen={self.base_url}", stdout=APITest.aptly_out, stderr=APITest.aptly_out) + time.sleep(1) + else: + APITest.aptly_out.clear() + + if os.path.exists(os.path.join(os.environ["HOME"], self.aptlyDir, "upload")): + shutil.rmtree(os.path.join(os.environ["HOME"], self.aptlyDir, "upload")) + + self.prepare_fixture() + + def debug_output(self): + return APITest.aptly_out.get_contents() def run(self): pass @@ -65,6 +92,20 @@ class APITest(BaseTest): return self.get("/api/tasks/" + str(_id)) + def check_task(self, task): + self.check_equal(task.status_code, 200) + if task.json()['State'] != TASK_SUCCEEDED: + resp2 = self.get("/api/tasks/" + str(task.json()['ID']) + "/output") + raise Exception(f"task failed: {resp2.text}") + + def check_task_fail(self, task, expected_output=None): + self.check_equal(task.status_code, 200) + if task.json()['State'] == TASK_SUCCEEDED: + raise Exception("task expected to fail") + if expected_output: + resp = self.get("/api/tasks/" + str(task.json()['ID']) + "/output") + self.check_equal(resp.json(), expected_output) + def put(self, uri, *args, **kwargs): if "json" in kwargs: kwargs["data"] = json.dumps(kwargs.pop("json")) @@ -128,6 +169,8 @@ class APITest(BaseTest): cls.aptly_server.terminate() cls.aptly_server.wait() cls.aptly_server = None + if APITest.aptly_out is not None: + APITest.aptly_out.close() def random_name(self): return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(15)) diff --git a/system/azure_lib.py b/system/azure_lib.py new file mode 100644 index 00000000..2b871d7b --- /dev/null +++ b/system/azure_lib.py @@ -0,0 +1,115 @@ +from lib import BaseTest +import uuid +import os + +try: + from azure.storage.blob import BlobServiceClient + + azure_storage_account = os.environ.get('AZURE_STORAGE_ACCOUNT') + azure_storage_access_key = os.environ.get('AZURE_STORAGE_ACCESS_KEY') + azure_storage_endpoint = os.environ.get( + 'AZURE_STORAGE_ENDPOINT', + f'https://{azure_storage_account}.blob.core.windows.net', + ) + if azure_storage_account is not None and azure_storage_access_key is not None: + blob_client = BlobServiceClient( + account_url=azure_storage_endpoint, + credential=azure_storage_access_key, + ) + else: + print('Azure tests disabled: Azure creds not found in the environment') + blob_client = None +except ImportError as e: + print("Azure tests disabled: can't import azure.storage.blob", e) + blob_client = None + + +class AzureTest(BaseTest): + """ + BaseTest + support for Azure Blob Storage + """ + + use_azure_pool = False + + def __init__(self) -> None: + super(AzureTest, self).__init__() + self.container_name = None + self.container = None + self.container_contents = None + + def fixture_available(self): + return super(AzureTest, self).fixture_available() and blob_client is not None + + def prepare(self): + self.container_name = 'aptly-sys-test-' + str(uuid.uuid1()) + self.container = blob_client.create_container( + self.container_name, public_access='blob' + ) + + self.azure_endpoint = { + 'accountName': azure_storage_account, + 'accountKey': azure_storage_access_key, + 'container': self.container_name, + 'endpoint': azure_storage_endpoint, + } + + self.configOverride = { + 'AzurePublishEndpoints': { + 'test1': self.azure_endpoint, + }, + } + if self.use_azure_pool: + self.configOverride['packagePoolStorage'] = { + 'type': 'azure', + **self.azure_endpoint, + } + + super(AzureTest, self).prepare() + + def shutdown(self): + if self.container_name is not None: + blob_client.delete_container(self.container_name) + + super(AzureTest, self).shutdown() + + def check_path(self, path): + if self.container_contents is None: + self.container_contents = [ + p.name for p in self.container.list_blobs() if p.name is not None + ] + + if path.startswith('public/'): + path = path.removeprefix('public/') + + if path in self.container_contents: + return True + + if not path.endswith('/'): + path = path + '/' + + for item in self.container_contents: + if item.startswith(path): + return True + + return False + + def check_exists(self, path): + if not self.check_path(path): + raise Exception("path %s doesn't exist" % (path,)) + + def check_exists_azure_only(self, path): + self.check_exists(path) + BaseTest.check_not_exists(self, path) + + def check_not_exists(self, path): + if self.check_path(path): + raise Exception('path %s exists' % (path,)) + + def read_file(self, path, mode=''): + assert not mode + + if path.startswith('public/'): + path = path.removeprefix('public/') + + blob = self.container.download_blob(path) + return blob.readall().decode('utf-8') diff --git a/system/build-deb b/system/build-deb new file mode 100755 index 00000000..3c70e0b0 --- /dev/null +++ b/system/build-deb @@ -0,0 +1,18 @@ +#!/bin/sh -e + +usermod -u `stat -c %u /work/src` aptly >/dev/null +chown -R `stat -c %u /work/src` /var/lib/aptly + +su aptly -c 'set -e; cd /work/src; +GOPATH=$PWD/.go go generate -v +# install and initialize swagger +GOPATH=$PWD/.go go install github.com/swaggo/swag/cmd/swag@latest +PATH=$PWD/.go/bin:$PATH swag init -q --markdownFiles docs +git checkout debian/changelog +DEBEMAIL="CI " dch -v `make version` "CI build" +dpkg-buildpackage -us -uc -b -d +mkdir -p build && mv ../*.deb build/ +rm -rf obj-*-linux-gnu* +git checkout debian/changelog +cd build && ls -l *.deb +' diff --git a/system/docker-wrapper b/system/docker-wrapper new file mode 100755 index 00000000..3bee17e7 --- /dev/null +++ b/system/docker-wrapper @@ -0,0 +1,15 @@ +#!/bin/sh -e + +# make sure files are written with correct user ownership +usermod -u `stat -c %u /work/src` aptly >/dev/null +chown -R `stat -c %u /work/src` /var/lib/aptly + +args="$@" +if [ -z "$args" ]; then + cmd="bash" +else + cmd="make $@" +fi + +cd /work/src +sudo -u aptly PATH=$PATH:/work/src/build GOPATH=/work/src/.go $cmd diff --git a/pgp/keyrings/aptly2.pub.armor b/system/files/aptly2.pub.armor similarity index 100% rename from pgp/keyrings/aptly2.pub.armor rename to system/files/aptly2.pub.armor diff --git a/pgp/keyrings/aptly2.sec.armor b/system/files/aptly2.sec.armor similarity index 100% rename from pgp/keyrings/aptly2.sec.armor rename to system/files/aptly2.sec.armor diff --git a/pgp/keyrings/aptly2_passphrase.pub.armor b/system/files/aptly2_passphrase.pub.armor similarity index 100% rename from pgp/keyrings/aptly2_passphrase.pub.armor rename to system/files/aptly2_passphrase.pub.armor diff --git a/pgp/keyrings/aptly2_passphrase.sec.armor b/system/files/aptly2_passphrase.sec.armor similarity index 100% rename from pgp/keyrings/aptly2_passphrase.sec.armor rename to system/files/aptly2_passphrase.sec.armor diff --git a/pgp/keyrings/aptly2_trusted.pub b/system/files/aptly2_trusted.pub similarity index 100% rename from pgp/keyrings/aptly2_trusted.pub rename to system/files/aptly2_trusted.pub diff --git a/system/files/flat.key b/system/files/flat.key index e6d6d224..f4f63af8 100644 Binary files a/system/files/flat.key and b/system/files/flat.key differ diff --git a/system/files/jenkins.key b/system/files/jenkins.key index cd0eef50..43f7a7c1 100644 --- a/system/files/jenkins.key +++ b/system/files/jenkins.key @@ -1,52 +1,52 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -mQINBF6B77kBEACZoUU41uYVDbagtNQrNQsnbx7UkRdu2rdUZLHryTOKv4InT33Z -mR73lTKT/8UlRYUp1kCLFebMTY73/x7Gk7tSQlURthLEGWpP7hpHZ4Co7slExvg4 -U1ULJfte30EqzwzM4vd6RGYSo6oeReP0Zffd8OYXz6mzcMvcTaKoUfsFbUVJS2ps -rmy2Xzu6arXivSVun8srE121bYf3DfM99G4vRf8VameamMRlSUxOThl+0pLULCwq -iAZR6hNbUbU4IOk6ZkaAUAEYzlwbrn0UjTO3iEkACgkOlcd9juB9+o/Vucbymdto -YioOAB6TcAJ/KM2snChmbkcV2at2CP5d+LVa/waYnd36C+TGCNRPZBNGlUrEeiMA -WGw14vUYMtZG3+04Holwhd/iZ3iqvMLjI5Z6SYueGvqzg8lCfeCTXFHmitWllZr6 -NTvcZeBMVnR/SlTI2IdwaO4ODArtsaC26bLesdfLEL3MnrztUQaJ14Vyv9hOb+bQ -VwxzpWrjXq03zmyeMyta6hvsTDgHCiZQivZjBjSHPbHEM10mKVu+oeVcwuSGFp8Z -zxLiHucwjeQDJ006/dJQH//3BO7P//LH4K11a87Ewj/aG2AIxvV4mMzS3YGSni8a -pCH+GA4GHfybTC6ztFAU8tjKS9u2MSpbo/1gKdmvdLFoYSgGLvjD/+ls8QARAQAB +mQINBGQhzisBEAC7yUhIqVCcyCXJWeZZf/BA6/+KguDQpycck0xUomj5ogT1+lwJ +Mnr6XsPFdTt5DgzjHKg6SM8PTIpLpzOcpqIG9eB8MnvtTp6qFSfIdZnEZccTot1e +cArnM2H6yw/4OW+8QHx9Zgj1miiqolVZ1RusHT3cvPdkF4GFTZnChiF0epd+6iKi +Em8gfzECIltl+McYCwjPXlx38p1mwPI0tgQ7GGD1VzjS/GycuD+shM7lPQ9PmCnC +8zkZIBsbGbSTbAYqnARrbczmg9BKCyErfdQJKi6+r/fg6cWAairXsiOlzqCLCBoZ +ssLKkRAc2ib3cm/RHBm+MK2wLZ5q8xgh9e/iBoBOpJXXARvfu67uQjfLPj/o4FwM +ZWxGZlj2b3cL5q+thjGWOliEh15gciGU17vT15YGcEPVMeDVBYKp/Z+TgkJIlUmD +4bU+K89qYCzp/AP3tsozFwazQRultkjuHVCZrJQtCaVu3/wjtkVd101Oj/Gi4ajn +2WU2KkGWkM0jArUCohJPsZodLHj8DAT2V5SqrEq6jF6ONnAlK1MNmPTKAoDmP6LJ +3of4VHcIbGq1p+I6R9292Lv3Avs/uMbWtR7nae4XWT9l49hY3p8gc5rPOs2wzPgV +v8X6vaQSlgjJDaNVPSZCo8hQkqHsoskri5BHVhxBpjaJ0mNKCeSHWfP+RwARAQAB tDJKZW5raW5zIFByb2plY3QgPGplbmtpbnNjaS1ib2FyZEBnb29nbGVncm91cHMu -Y29tPokCVAQTAQoAPhYhBGKpdWv9eAw3fPJLqPzvMudF8sPVBQJege+5AhsDBQkF -o5qABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEPzvMudF8sPVD9YQAI6jJSP2 -kzwUI4aGYU2SFYel5Uk3ps7mbAcMHcxJMsq/WhjSVWYzTTL4RSgNRI1J6fC8C97k -ONYqE0H1SeIPRQ0h8YiAXCoGhzH6IUMKZv2QlSb+GtZOD0c2oBwVdPC1jIjrUZ7N -BEhsnE20teqCyBy+ReognfTeZRjYkWGDoF0PrCqwybYU1DYoe0NsmKVcwrzNOu1s -6vDIkjyZ6eUPoRLdjNUXoMcgnS8fAxyNksfabJtqo3XoCxy38NqoCH9Bft/nyQgE -Tq7D96PcrnjdqLuqndb09TzhEbYMA1OJ/m8rE5eDxXn0hVef5ZTdSbAGDZ3vak4R -6NtkyYsaDgONWDZGNwfZrQiPDm+ziGdcQ61oRp6dldF6PiG/E++yQbrNLmFoLvqg -UCzEkyuh5ws+QeX5CnrFqxGb1KAVjKWo4bWZuG7Aro6aouCBTzqW60rnYWzlUGzd -eWGMmvIJYLpdiN0hOpdr995jDXLCJzds8Qle+Zpv3SCtnXTD9vFyHQhV9y1UycPJ -gQ3FFT0SSXIlnD7aoqDku/jq/pFCeccUqUjEFWeKa6shiXPXcqo3PCwYOhE1WFAn -MrxKcKzKUyabzI1i9Din5udUtWAEuqH7g2yX6kAr3RBBVjrCe7iALBDzXUTNOj0J -w9eTf917JDRcCeYOhDmUM70Cl0gfQUqzhYzzuQINBF6B77kBEAC8sdb/x+CSQWqX -KLEvIAo1qIusCGWICJqPO/3nG6Y2FUEA9HjZU+/i/Q3mbDk4QN/1qoqUiwg27iOa -Q3GwjWn887U7ZK4QqDPaMZL62Vf5OAC0hA2iXnncvAcRCAo/FUhXkhI+p2w76a3U -LffCOUdevTF/eE8c85GeCxUH/h4tmbDmCsWmYakEs8HpZ+CmOWm3Z/oWmrXYOBbO -UuzGVTOo3oUR0f+CjzsrnPW0oFIFAzBmPLfZSFCcuIeR4gosvtvFurTsQ4tuoVpB -Tgu5Dzyc0iJgFjviSA+lVcBEyye/c0pkXaZss0ZbCEtIgTyWptfSUcxDJISYO5ov -em1DgtM7U8jCO3R4D/nRhjFBx5Wup6F2r1mPz+xGvWCry0ryivGTcIaHZHT8QICJ -aFJ6VfDXJzToxEnlrrXK2Y5qM5HmJa7R/uA9mdYHuhbJJ1m8aB6o8EYR9QtIMJ8h -XGX/Bhdxu+8O4EYDO5bpA/A9zcIsIvT77yJTfaDI9FUL3BWefTS1uswake8xqowF -O+YrTyPUkMlH5tbQFXQ6vzWrkt69nSEBW629ronXm3E6R+1i5uEnN/SHsWoTU2v4 -xcP+K/HT7a6AYq3bEp/vUMASSmaI51U3BA2XyxANtWTzDeseHNIMF6tuZuewwcjN -5F8jFI7iFtvrfUPZFPPQ2/vX2SwOlQARAQABiQI8BBgBCgAmFiEEYql1a/14DDd8 -8kuo/O8y50Xyw9UFAl6B77kCGwwFCQWjmoAACgkQ/O8y50Xyw9XGGxAAhcLj80iM -M26mZA+hPxriP27eLI3yLOsuEKjZftcfOV5WC3iaklkZAmMkmIfhwg/QEkLqL4f4 -MdnVj5/aVyygG2czW3Lvg4otjySTjBv+rf55GVK7KomAjJBU6m+IJdCHJbKKuixP -CEy5GXqdnXkaNbU+DAba0dP8lfQXHgpeeAYUushJrEOEVriCyrxyQan2HomJ2zs7 -IoB1fCLI2FGV5MItyCmVOjJJ6ViJoQz6FRL9kvmT/xwMSwmrQMhMgU6zTZcYzdBL -KYkxahUr7ltETFy3LaPnDezX3zT8mNQ9bqfxaMLn/+Ku/AdriMhfzoC9NXvzhZYY -kWVGYwWzFAVOyn3o1A+MRjhT7FikWXQxKlGuGgcXDhbPWR4gUSWlEga1aFVRzYHO -Ty60f6SWcuTgL0tBNcdXqEkhSpoV/9wxhTox6lfaH3vajganr9gPyew1oiOrvIzw -PNbzJTe+Yj1WEUheSdWuI5jPQl5Mr5YYxf9j0T2xqb2k01/FW+aR5Xte5Bj9OGz2 -Ou4QDK481XaUKovplz3jj2PtK8d/12OJT11ukFb8py6u1ezxRjOm3Nk6kzySG8vP -hjqccnUDI8Eg8yo0s02+SVt9lNkVe7ggF99TRp/rMBCxb+e27OPjqdRKEArB8JyI -Z77i4FhdLio04srxWsN+FkRwkBJdkJ8VKEE= -=0xpA +Y29tPokCVwQTAQgAQRYhBGNmfudLuh8KCKaYclujHVfvWXXKBQJkIc4rAhsDBQkF +o5qABQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEFujHVfvWXXK4+kP/0cR +nNYrjb4gWG/rcwJ8zo0YKZBO30RPul1INnyufDediDb0UCOJwT+CnEZULx+HeUOi +xHVBMD70LRP3ym+40Naw3s4nJWvBpOYIqQhjoRqrWkdIrMgNSAwRrufgXqSBvvfZ ++xQYrNRuu8/00U6Bz2eeCL2SNZpShL0iPjP9Bcu7763jaGvnS/WUVaAqqyNwxGRl +afffRvCV/Wjy47W+ifCPgku4SKZgG+QPMuthI842+lLSl2BXhiEVJ4auK5rjFHsv +RrUEQrjEGZ9vEoitZAQL/CDWmlkhrqYSpgTVsMCoByRzZqQG9fOAJNFniFqrANQQ +m9NkZN0ZljOnZfJh+ZzbjjVUS522piJtVqdOU0noT6awMtSO/CO4EmuElj8LkVI6 +jbP0FqxYecNQtlAzBguRD5UWjAi3jgkdbap0ooqZm2YQPNaLD3OLWdvtj/jx+EI4 +DTrSoSSoHea5xiAFQNB3ab2fk5kN5ufVWIV5F9AQHU+kWE9jgS+zl8apzbwMinm8 +ZW0KeIcW63MH5hvbmsfBjdyroTTy2mwy096mB2vvqwWv6nt9mQy1YCmBeyp7oshI +qNeXIunP1NekAfGY+dRlldA3SoxNuJhVGd5eCOFWYmipb9XD+JrSgncHjCgewHq1 +ycptdm1q8OZ26ZOaAIVOYENk8WUOz5DzOuOS81EJuQINBGQhzisBEADtvyAOnz23 +gKKKVzSY9bhEvQxJWQUY/jXek7LjhflLw4xugGARMrTMc6zzabOJefyrVkucWqso +spCWoj+M8HGfhHXpNDHbn21fyHB6jpOh8Ors2ZHH2skswcAcWcLlWQWrUtqQFuje +1rXShp8IhYz308MIZ65VYf/Z9Bk7VNNTgRLmOMTn+KlN8qiQZ0SZbPj/wFK1iwAh +/xPu586a7xVN4xdy6RJNfrSCG84kMNyaHTDFOEKchWPoGe5D6EqF8dufvrcKoSxc +T2sC6WzDqG/+Jfk//xrHblxeCXiOAX/Dm+McvceV0dBSVJJx67FoHUyWBRj5coHU +4YfrUTHREEKdYcpUAHQGPJBLyx0QNs2URhYSCwNU5yYL+z3UIpsS93HosUPEzrTD +XE1D2eV1gGf0YzCWxWTAuOjoUD8D22p//GAaLXYpuwSgVzgKwvPefkWJ94Euvz6T +sKrljMPsxOdPLBs8AJgrqmYIwbRXoxNEzv/PT/9sST5nl5tlWc9PonzwzHqStU4Y +f8jQhIv1yq2wAE2OB0Q7B6i62QWqSWAWEAc6LPRdSalgS8ooj/MIQFGwsd4VuNSN +JD9p7bHHlHceeXMR2F0JeG8G91RqlTkxu7cUMkqheXXAyTa/OuG5xauHyLzt4xVp +fnHd5fNjxcc02ADF46X6/nze6hClUBqMAQARAQABiQI8BBgBCAAmFiEEY2Z+50u6 +HwoIpphyW6MdV+9ZdcoFAmQhzisCGwwFCQWjmoAACgkQW6MdV+9ZdcoRGA/+JmjW +09ZmAlBM846GgI0B00YtXMu3PuhhOq8sJEXvcvlCfSAlVpHfnwUJE7q5QaUrD3wT +VKT4pe/zBRN+zD84gXxGANJY813EhpngBEJmptIjNkKvWclr/nG4MI8yezZmeEgP +142LviJmNYb0+3s1CU7Q03g3b/wsHNFpuA9zVJu24xVAM/Af65N1STvnSQAjcXa9 +rgIwdiZ7XbCD6rpF1ms8i6RYsflB+dGLgEOiAlX+lZ6843WpMWlDUBd2v+OHtXvm +zLYbg8SYtHV8xMJWPjz6e9yoKuyjvWAwAiDcjO0SpCqlkHsUzWRS44z3hQssgywP +iFKGqP5eHDaSCqUHF5VkGdtg/a9M7vthhEoB/2IKSf82CQE9IdmNtEJHAPgWamgm +VPpyMliDTd2gyqD+FmduRdY/yHMP0QV6G/VRTV4gfQ80qU/U2JXWAQdw6ok1+k5V +t0ur8buQo+49diyr8WPHA4CwpSwriwIClDZdq38JiCdnfICfFxAQYdBMbL6S4wqA +Sv+OqcDBvu7m5yV/hrfcVztRkWUwr21kUmvx04xpvvpG/cUAnQOog3Q7Ce5xkaX7 +99Ewd0xUXma/H++IGX77jxU7jW5n2FPeVEn+zcNF8of/XAi1uaP1WL5T/iEl6EsI +MetBbjkOnNXyWrP3SAPwqQMMg/vNa+mJIjoNByw= +=sdsH -----END PGP PUBLIC KEY BLOCK----- diff --git a/system/fixture.sh b/system/fixture.sh index e5474bb1..81b26aee 100644 --- a/system/fixture.sh +++ b/system/fixture.sh @@ -22,11 +22,11 @@ aptly mirror update wheezy-non-free-src aptly mirror update wheezy-updates-src aptly mirror update wheezy-backports-src -aptly mirror create gnuplot-maverick http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick +aptly mirror create gnuplot-maverick http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick aptly mirror update gnuplot-maverick -aptly mirror create -with-sources gnuplot-maverick-src http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick +aptly mirror create -with-sources gnuplot-maverick-src http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick aptly mirror update gnuplot-maverick-src aptly mirror create sensu http://repos.sensuapp.org/apt sensu -aptly mirror update sensu \ No newline at end of file +aptly mirror update sensu diff --git a/system/leveldb2etcd.py b/system/leveldb2etcd.py new file mode 100644 index 00000000..65788b12 --- /dev/null +++ b/system/leveldb2etcd.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import plyvel +import etcd3 +import argparse +from termcolor import cprint + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--datadir", required=True, help="leveldb data dir") + parser.add_argument("--etcdaddr", default="127.0.0.1", help="etcd server address") + parser.add_argument("--etcdport", default="2379", help="etcd server address") + + args = parser.parse_args() + + ldb = plyvel.DB(args.datadir) + etcd = etcd3.client(args.etcdaddr, args.etcdport) + + for key, value in ldb: + try: + keystr = key + valuestr = value + etcd.put(keystr, valuestr) + # cprint("key: "+keystr+", value: "+valuestr+"put success!\n", 'green') + except Exception as e: + cprint("key: " + str(keystr) + ", value: " + str(valuestr) + "put err: " + str(e) + "\n", 'red') + exit(1) diff --git a/system/lib.py b/system/lib.py index 013cfc3a..e162b964 100644 --- a/system/lib.py +++ b/system/lib.py @@ -3,24 +3,27 @@ Test library. """ import difflib +import http.server import inspect import json -import subprocess import os import posixpath +import pprint import re import shlex import shutil +import socketserver import string +import subprocess import threading import urllib.error import urllib.parse import urllib.request -import pprint -import socketserver -import http.server import zlib +from pathlib import Path +from uuid import uuid4 + def ungzip_if_required(output): if isinstance(output, bytes) and output.startswith(b"\x1f\x8b"): @@ -100,7 +103,7 @@ class DotFinder(object): def find_dot(self, executables): for executable in executables: try: - subprocess.check_output([executable, "-V"], text=True) + subprocess.check_output([executable, "-V"], text=True, stderr=subprocess.DEVNULL) return executable except Exception: pass @@ -125,25 +128,15 @@ class BaseTest(object): requiresGPG2 = False requiresDot = False sortOutput = False + debugOutput = False + EtcdServer = None + aptlyDir = ".aptly" + aptlyConfigFile = ".aptly.conf" expectedCode = 0 - configFile = { - "rootDir": "%s/.aptly" % os.environ["HOME"], - "downloadConcurrency": 4, - "downloadSpeedLimit": 0, - "downloadRetries": 5, - "databaseOpenAttempts": 10, - "architectures": [], - "dependencyFollowSuggests": False, - "dependencyFollowRecommends": False, - "dependencyFollowAllVariants": False, - "dependencyFollowSource": False, - "gpgDisableVerify": False, - "gpgDisableSign": False, - "ppaDistributorID": "ubuntu", - "ppaCodename": "", - "enableMetricsEndpoint": True, - } + databaseType = "" + databaseUrl = "" + configOverride = {} environmentOverride = {} @@ -169,26 +162,55 @@ class BaseTest(object): try: self.run() self.check() + except Exception as exc: + if self.debugOutput: + print(f"API log:\n{self.debug_output()}") + raise exc finally: self.teardown() def prepare_remove_all(self): - if os.path.exists(os.path.join(os.environ["HOME"], ".aptly")): - shutil.rmtree(os.path.join(os.environ["HOME"], ".aptly")) - if os.path.exists(os.path.join(os.environ["HOME"], ".aptly.conf")): - os.remove(os.path.join(os.environ["HOME"], ".aptly.conf")) + if os.path.exists(os.path.join(os.environ["HOME"], self.aptlyDir)): + shutil.rmtree(os.path.join(os.environ["HOME"], self.aptlyDir)) + if os.path.exists(os.path.join(os.environ["HOME"], self.aptlyConfigFile)): + os.remove(os.path.join(os.environ["HOME"], self.aptlyConfigFile)) if os.path.exists(os.path.join(os.environ["HOME"], ".gnupg", "aptlytest.gpg")): os.remove(os.path.join( os.environ["HOME"], ".gnupg", "aptlytest.gpg")) def prepare_default_config(self): - cfg = self.configFile.copy() + databaseBackend = { + "type": self.databaseType, + "url": self.databaseUrl, + } + + cfg = { + "rootDir": f"{os.environ['HOME']}/{self.aptlyDir}", + "downloadConcurrency": 4, + "downloadSpeedLimit": 0, + "downloadRetries": 5, + "databaseOpenAttempts": 10, + "architectures": [], + "dependencyFollowSuggests": False, + "dependencyFollowRecommends": False, + "dependencyFollowAllVariants": False, + "dependencyFollowSource": False, + "gpgDisableVerify": False, + "gpgDisableSign": False, + "ppaDistributorID": "ubuntu", + "ppaCodename": "", + "enableMetricsEndpoint": True, + "logLevel": "debug", + "logFormat": "default", + "serveInAPIMode": True, + "databaseBackend": databaseBackend, + } if self.requiresGPG1: cfg["gpgProvider"] = "gpg1" elif self.requiresGPG2: cfg["gpgProvider"] = "gpg2" cfg.update(**self.configOverride) - f = open(os.path.join(os.environ["HOME"], ".aptly.conf"), "w") + f = open(os.path.join(os.environ["HOME"], self.aptlyConfigFile), "w") f.write(json.dumps(cfg)) f.close() @@ -210,24 +232,42 @@ class BaseTest(object): def prepare_fixture(self): if self.fixturePool: - os.makedirs(os.path.join(os.environ["HOME"], ".aptly"), 0o755) + os.makedirs(os.path.join(os.environ["HOME"], self.aptlyDir), 0o755) os.symlink(self.fixturePoolDir, os.path.join( - os.environ["HOME"], ".aptly", "pool")) + os.environ["HOME"], self.aptlyDir, "pool")) if self.fixturePoolCopy: - os.makedirs(os.path.join(os.environ["HOME"], ".aptly"), 0o755) + os.makedirs(os.path.join(os.environ["HOME"], self.aptlyDir), 0o755) shutil.copytree(self.fixturePoolDir, os.path.join( - os.environ["HOME"], ".aptly", "pool"), ignore=shutil.ignore_patterns(".git")) + os.environ["HOME"], self.aptlyDir, "pool"), ignore=shutil.ignore_patterns(".git")) - if self.fixtureDB: - shutil.copytree(self.fixtureDBDir, os.path.join( - os.environ["HOME"], ".aptly", "db")) + if self.databaseType == "etcd": + if not os.path.exists("/srv/etcd"): + self.run_cmd([os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "t13_etcd/install-etcd.sh")]) + + if self.fixtureDB and self.databaseType != "etcd": + shutil.copytree(self.fixtureDBDir, os.path.join(os.environ["HOME"], self.aptlyDir, "db")) + + if self.databaseType == "etcd": + if self.EtcdServer: + self.shutdown_etcd() + + # remove existing database + if os.path.exists("/tmp/etcd-data"): + shutil.rmtree("/tmp/etcd-data") + + if self.fixtureDB: + print("import etcd") + self.run_cmd(["/srv/etcd/etcdctl", "--data-dir=/tmp/etcd-data", "snapshot", "restore", os.path.join(os.environ["HOME"], "etcd.db")]) + + print("starting etcd") + self.EtcdServer = self._start_process([os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "t13_etcd/start-etcd.sh")], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if self.fixtureWebServer: self.webServerUrl = self.start_webserver(os.path.join(os.path.dirname(inspect.getsourcefile(self.__class__)), self.fixtureWebServer)) - if self.requiresGPG2: + if self.requiresGPG2 or self.gpgFinder.gpg2: self.run_cmd([ self.gpgFinder.gpg2, "--import", os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files") + "/aptly.sec"], expected_code=None) @@ -235,10 +275,14 @@ class BaseTest(object): if self.fixtureGpg: self.run_cmd([self.gpgFinder.gpg, "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import"] + [os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", key) for key in self.fixtureGpgKeys]) + self.run_cmd(["chmod", "400", os.path.join(os.environ["HOME"], ".gnupg/aptlytest.gpg")]) if hasattr(self, "fixtureCmds"): for cmd in self.fixtureCmds: - self.run_cmd(cmd) + output = self.run_cmd(cmd) + print("fixture Output:\n") + for line in output.split("\n"): + print(f" {line}") def sort_lines(self, output): return "\n".join(sorted(self.ensure_utf8(output).split("\n"))) @@ -256,14 +300,19 @@ class BaseTest(object): 'changes': os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "changes"), 'udebs': os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "udebs"), 'testfiles': os.path.join(os.path.dirname(inspect.getsourcefile(self.__class__)), self.__class__.__name__), - 'aptlyroot': os.path.join(os.environ["HOME"], ".aptly"), + 'aptlyroot': os.path.join(os.environ["HOME"], self.aptlyDir), } if self.fixtureWebServer: params['url'] = self.webServerUrl command = string.Template(command).substitute(params) + print(f"running command: {command}\n") command = shlex.split(command) + if command[0] == "aptly": + aptly_testing_bin = Path(__file__).parent / ".." / "aptly.test" + command = [str(aptly_testing_bin), f"-test.coverprofile={Path(self.coverage_dir) / self.__class__.__name__}-{uuid4()}.out", *command[1:]] + environ = os.environ.copy() environ["LC_ALL"] = "C" environ.update(self.environmentOverride) @@ -272,14 +321,37 @@ class BaseTest(object): def run_cmd(self, command, expected_code=0): try: proc = self._start_process(command, stdout=subprocess.PIPE) - output, _ = proc.communicate() + raw_output, _ = proc.communicate() + + raw_output = raw_output.decode("utf-8", errors='replace') + + returncodes = [proc.returncode] + is_aptly_command = False + if isinstance(command, str): + is_aptly_command = command.startswith("aptly") + + if isinstance(command, list): + is_aptly_command = command[0] == "aptly" + + if is_aptly_command: + # remove the last two rows as go tests always print PASS/FAIL and coverage in those + # two lines. This would otherwise fail the tests as they would not match gold + matches = re.findall(r"((.|\n)*)EXIT: (\d)\n.*\ncoverage: .*", raw_output) + if not matches: + raise Exception("no matches found in output '%s'" % raw_output) + + output, _, returncode = matches[0] + returncodes.append(int(returncode)) + else: + output = raw_output + if expected_code is not None: - if proc.returncode != expected_code: + if expected_code not in returncodes: raise Exception("exit code %d != %d (output: %s)" % ( - proc.returncode, expected_code, output)) + proc.returncode, expected_code, raw_output)) return output except Exception as e: - raise Exception("Running command %s failed: %s" % + raise Exception("Running command '%s' failed: %s" % (command, str(e))) def gold_processor(self, gold): @@ -310,7 +382,7 @@ class BaseTest(object): try: self.verify_match(self.get_gold(), self.output, match_prepare=self.outputMatchPrepare) - except: # noqa: E722 + except Exception: # noqa: E722 if self.captureResults: if self.outputMatchPrepare is not None: self.output = self.outputMatchPrepare(self.output) @@ -333,11 +405,11 @@ class BaseTest(object): raise def read_file(self, path, mode=''): - with open(os.path.join(os.environ["HOME"], ".aptly", path), "r" + mode) as f: + with open(os.path.join(os.environ["HOME"], self.aptlyDir, path), "r" + mode) as f: return f.read() def delete_file(self, path): - os.unlink(os.path.join(os.environ["HOME"], ".aptly", path)) + os.unlink(os.path.join(os.environ["HOME"], self.aptlyDir, path)) def check_file_contents(self, path, gold_name, match_prepare=None, mode='', ensure_utf8=True): contents = self.read_file(path, mode=mode) @@ -367,15 +439,15 @@ class BaseTest(object): raise def check_exists(self, path): - if not os.path.exists(os.path.join(os.environ["HOME"], ".aptly", path)): + if not os.path.exists(os.path.join(os.environ["HOME"], self.aptlyDir, path)): raise Exception("path %s doesn't exist" % (path, )) def check_not_exists(self, path): - if os.path.exists(os.path.join(os.environ["HOME"], ".aptly", path)): + if os.path.exists(os.path.join(os.environ["HOME"], self.aptlyDir, path)): raise Exception("path %s exists" % (path, )) def check_file_not_empty(self, path): - if os.stat(os.path.join(os.environ["HOME"], ".aptly", path))[6] == 0: + if os.stat(os.path.join(os.environ["HOME"], self.aptlyDir, path))[6] == 0: raise Exception("file %s is empty" % (path, )) def check_equal(self, a, b): @@ -407,7 +479,7 @@ class BaseTest(object): diff += "wrong value '%s' for key '%s', expected '%s'\n" % ( v, k, b[k]) if diff: - raise Exception("content doesn't match:\n" + diff) + raise Exception("content subset doesn't match:\n" + diff) def ensure_utf8(self, a): if isinstance(a, bytes): @@ -423,6 +495,10 @@ class BaseTest(object): a = match_prepare(a) b = match_prepare(b) + # strip trailing whitespace and newlines + a = a.strip() + b = b.strip() + if a != b: diff = "".join(difflib.unified_diff( [l + "\n" for l in a.split("\n")], [l + "\n" for l in b.split("\n")])) @@ -437,7 +513,8 @@ class BaseTest(object): self.prepare_fixture() def teardown(self): - pass + if self.EtcdServer: + self.shutdown_etcd() def start_webserver(self, directory): FileHTTPServerRequestHandler.rootPath = directory @@ -453,10 +530,18 @@ class BaseTest(object): def shutdown(self): if hasattr(self, 'webserver'): self.shutdown_webserver() + if self.EtcdServer: + self.shutdown_etcd() def shutdown_webserver(self): self.webserver.shutdown() + def shutdown_etcd(self): + print("stopping etcd") + self.EtcdServer.terminate() + self.EtcdServer.wait() + self.EtcdServer = None + @classmethod def shutdown_class(cls): pass diff --git a/system/requirements.txt b/system/requirements.txt index 3d4be24f..b0627340 100644 --- a/system/requirements.txt +++ b/system/requirements.txt @@ -1,6 +1,9 @@ +azure-storage-blob boto -requests +requests==2.28.2 requests-unixsocket python-swiftclient flake8 termcolor +etcd3 +leveldb diff --git a/system/run.py b/system/run.py index e27377d0..599afe5f 100755 --- a/system/run.py +++ b/system/run.py @@ -7,15 +7,19 @@ import inspect import fnmatch import re import sys +from tempfile import mkdtemp import traceback import random import subprocess +import time from lib import BaseTest from s3_lib import S3Test from swift_lib import SwiftTest +from azure_lib import AzureTest from api_lib import APITest from fs_endpoint_lib import FileSystemEndpointTest +from testout import TestOut try: from termcolor import colored @@ -32,35 +36,56 @@ def natural_key(string_): return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)] -def walk_modules(package): - yield importlib.import_module(package) - for name in sorted(glob.glob(package + "/*.py"), key=natural_key): - name = os.path.splitext(os.path.basename(name))[0] - if name == "__init__": - continue - - yield importlib.import_module(package + "." + name) - - -def run(include_long_tests=False, capture_results=False, tests=None, filters=None): +def run(include_long_tests=False, capture_results=False, tests=None, filters=None, coverage_dir=None): """ Run system test. """ + print(colored("\n Aptly System Tests\n====================\n", color="green", attrs=["bold"])) + if not tests: tests = sorted(glob.glob("t*_*"), key=natural_key) fails = [] numTests = numFailed = numSkipped = 0 lastBase = None + if not coverage_dir: + coverage_dir = mkdtemp(suffix="aptly-coverage") for test in tests: - for testModule in walk_modules(test): - for name in sorted(dir(testModule), key=natural_key): - o = getattr(testModule, name) + orig_stdout = sys.stdout + orig_stderr = sys.stderr - if not (inspect.isclass(o) and issubclass(o, BaseTest) and o is not BaseTest and - o is not SwiftTest and o is not S3Test and o is not APITest and o is not FileSystemEndpointTest): + # importlib.import_module(test) + for fname in sorted(glob.glob(test + "/*.py"), key=natural_key): + fname = os.path.splitext(os.path.basename(fname))[0] + if fname == "__init__": + continue + + testout = TestOut() + sys.stdout = testout + sys.stderr = testout + + try: + testModule = importlib.import_module(test + "." + fname) + except Exception as exc: + orig_stdout.write(f"error importing: {test + '.' + fname}: {exc}\n") + continue + + testignore = [] + if hasattr(testModule, "TEST_IGNORE"): + testignore = testModule.TEST_IGNORE + for name in sorted(dir(testModule), key=natural_key): + if name in testignore: continue + o = getattr(testModule, name) + if not (inspect.isclass(o) and issubclass(o, BaseTest) and o is not BaseTest and + o is not SwiftTest and o is not S3Test and o is not AzureTest and + o is not APITest and o is not FileSystemEndpointTest): + continue + + testout.clear() + start_time = time.time() + newBase = o.__bases__[0] if lastBase is not None and lastBase is not newBase: lastBase.shutdown_class() @@ -78,77 +103,108 @@ def run(include_long_tests=False, capture_results=False, tests=None, filters=Non if not matches: continue - sys.stdout.write("%s:%s... " % (test, o.__name__)) - sys.stdout.flush() + orig_stdout.write("· %-13s ➔ %-48s ... " % (test, colored(o.__name__, color="yellow", attrs=["bold"]))) + orig_stdout.flush() t = o() + if t.longTest and not include_long_tests or not t.fixture_available() or t.skipTest: numSkipped += 1 msg = 'SKIP' if t.skipTest and t.skipTest is not True: # If we have a reason to skip, print it msg += ': ' + t.skipTest - sys.stdout.write(colored(msg + "\n", color="yellow")) + orig_stdout.write(colored(msg + "\n", color="yellow")) continue numTests += 1 + failed = False + t.captureResults = capture_results + t.coverage_dir = coverage_dir + typ = None + val = None + tb = None try: - t.captureResults = capture_results t.test() except Exception: - numFailed += 1 typ, val, tb = sys.exc_info() - fails.append((test, t, typ, val, tb, testModule)) - traceback.print_exception(typ, val, tb) - sys.stdout.write(colored("FAIL\n", color="red")) + failed = True + + end_time = time.time() + execution_time = int(end_time - start_time) + 1 + minutes = execution_time // 60 + seconds = execution_time % 60 + if minutes > 0: + minutes = f"{minutes}m" + if seconds < 10: + seconds = f"0{seconds}" else: - sys.stdout.write(colored("OK\n", color="green")) + minutes = " " + if seconds < 10: + seconds = f" {seconds}" + duration = f"{minutes}{seconds}s" + + if failed: + numFailed += 1 + fails.append((test, t, typ, val, tb, testModule)) + orig_stdout.write(colored("\b\b\b\bFAIL", color="red", attrs=["bold"]) + f" {duration}\n") + + orig_stdout.write(testout.get_contents()) + traceback.print_exception(typ, val, tb, file=orig_stdout) + else: + orig_stdout.write(colored("\b\b\b\bOK", color="green", attrs=["bold"]) + f" {duration}\n") t.shutdown() + sys.stdout = orig_stdout + sys.stderr = orig_stderr + if lastBase is not None: lastBase.shutdown_class() - print("TESTS: %d SUCCESS: %d FAIL: %d SKIP: %d" % ( - numTests, numTests - numFailed, numFailed, numSkipped)) + print("\nCOVERAGE_RESULTS: %s" % coverage_dir) + + print(f"TESTS: {numTests} ", + colored(f"SUCCESS: {numTests - numFailed} ", color="green", attrs=["bold"]) if numFailed == 0 else + f"SUCCESS: {numTests - numFailed} ", + colored(f"FAIL: {numFailed} ", color="red", attrs=["bold"]) if numFailed > 0 else "FAIL: 0 ", + colored(f"SKIP: {numSkipped}", color="yellow", attrs=["bold"]) if numSkipped > 0 else "SKIP: 0") + print() if len(fails) > 0: - print("\nFAILURES (%d):" % (len(fails), )) + print(colored("FAILURES (%d):" % (len(fails), ), color="red", attrs=["bold"])) for (test, t, typ, val, tb, testModule) in fails: doc = t.__doc__ or '' - print("%s:%s %s" % (test, t.__class__.__name__, - testModule.__name__ + ": " + doc.strip())) - traceback.print_exception(typ, val, tb) - print("=" * 60) - + print(" - %s: %s %s" % (test, colored(t.__class__.__name__, color="yellow", attrs=["bold"]), + testModule.__name__ + ": " + doc.strip())) + print() sys.exit(1) if __name__ == "__main__": - if 'APTLY_VERSION' not in os.environ: - try: - os.environ['APTLY_VERSION'] = os.popen( - "make version").read().strip() - except BaseException as e: - print("Failed to capture current version: ", e) + try: + os.environ['APTLY_VERSION'] = os.popen("make -s version").read().strip() + except BaseException as e: + print("Failed to capture current version: ", e) if sys.version_info < PYTHON_MINIMUM_VERSION: raise RuntimeError(f'Tests require Python {PYTHON_MINIMUM_VERSION} or higher.') - output = subprocess.check_output(['gpg1', '--version'], text=True) - if not output.startswith('gpg (GnuPG) 1'): - raise RuntimeError('Tests require gpg v1') + output = subprocess.check_output(['gpg', '--version'], text=True) + if not output.startswith('gpg (GnuPG) 2'): + raise RuntimeError('Tests require gpg v2') - output = subprocess.check_output(['gpgv1', '--version'], text=True) - if not output.startswith('gpgv (GnuPG) 1'): - raise RuntimeError('Tests require gpgv v1') + output = subprocess.check_output(['gpgv', '--version'], text=True) + if not output.startswith('gpgv (GnuPG) 2'): + raise RuntimeError('Tests require gpgv v2') os.chdir(os.path.realpath(os.path.dirname(sys.argv[0]))) random.seed() include_long_tests = False capture_results = False + coverage_dir = None tests = None args = sys.argv[1:] @@ -157,6 +213,9 @@ if __name__ == "__main__": include_long_tests = True elif args[0] == "--capture": capture_results = True + elif args[0] == "--coverage-dir": + coverage_dir = args[1] + args = args[1:] args = args[1:] @@ -169,4 +228,4 @@ if __name__ == "__main__": else: filters.append(arg) - run(include_long_tests, capture_results, tests, filters) + run(include_long_tests, capture_results, tests, filters, coverage_dir) diff --git a/system/s3_lib.py b/system/s3_lib.py index 9940fe13..4a52b9ad 100644 --- a/system/s3_lib.py +++ b/system/s3_lib.py @@ -5,10 +5,11 @@ import os try: import boto - if 'AWS_SECRET_ACCESS_KEY' in os.environ and 'AWS_ACCESS_KEY_ID' in os.environ: + if 'AWS_SECRET_ACCESS_KEY' in os.environ and 'AWS_ACCESS_KEY_ID' in os.environ and \ + os.environ['AWS_SECRET_ACCESS_KEY'] != "" and os.environ['AWS_ACCESS_KEY_ID'] != "": s3_conn = boto.connect_s3() else: - print("S3 tests disabled: AWS creds not found in the environment") + print("S3 tests disabled: AWS creds not found in the environment (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)") s3_conn = None except ImportError as e: print("S3 tests disabled: can't import boto", e) @@ -32,6 +33,8 @@ class S3Test(BaseTest): "test1": { "region": "us-east-1", "bucket": self.bucket_name, + "awsAccessKeyID": os.environ["AWS_ACCESS_KEY_ID"], + "awsSecretAccessKey": os.environ["AWS_SECRET_ACCESS_KEY"] } }} @@ -76,7 +79,10 @@ class S3Test(BaseTest): if self.check_path(path): raise Exception("path %s exists" % (path, )) - def read_file(self, path): + def read_file(self, path, mode=''): + # We don't support reading as binary here. + assert not mode + if path.startswith("public/"): path = path[7:] diff --git a/system/t01_version/__init__.py b/system/t01_version/__init__.py index 388e7df6..e0a28e39 100644 --- a/system/t01_version/__init__.py +++ b/system/t01_version/__init__.py @@ -1,14 +1,3 @@ """ Test aptly version """ - -from lib import BaseTest - - -class VersionTest(BaseTest): - """ - version should match - """ - gold_processor = BaseTest.expand_environ - - runCmd = "aptly version" diff --git a/system/t01_version/version.py b/system/t01_version/version.py new file mode 100644 index 00000000..388e7df6 --- /dev/null +++ b/system/t01_version/version.py @@ -0,0 +1,14 @@ +""" +Test aptly version +""" + +from lib import BaseTest + + +class VersionTest(BaseTest): + """ + version should match + """ + gold_processor = BaseTest.expand_environ + + runCmd = "aptly version" diff --git a/system/t02_config/ConfigShowTest_gold b/system/t02_config/ConfigShowTest_gold index 57b42b6a..0529de71 100644 --- a/system/t02_config/ConfigShowTest_gold +++ b/system/t02_config/ConfigShowTest_gold @@ -15,6 +15,7 @@ "gpgDisableVerify": false, "gpgProvider": "gpg", "downloadSourcePackages": false, + "packagePoolStorage": {}, "skipLegacyPool": false, "ppaDistributorID": "ubuntu", "ppaCodename": "", @@ -25,5 +26,14 @@ "SwiftPublishEndpoints": {}, "AzurePublishEndpoints": {}, "AsyncAPI": false, - "enableMetricsEndpoint": true + "enableMetricsEndpoint": true, + "logLevel": "debug", + "logFormat": "default", + "serveInAPIMode": true, + "databaseBackend": { + "type": "", + "url": "", + "dbPath": "" + }, + "enableSwaggerEndpoint": false } diff --git a/system/t02_config/CreateConfigTest_gold b/system/t02_config/CreateConfigTest_gold index 7d1a23e1..181efa4d 100644 --- a/system/t02_config/CreateConfigTest_gold +++ b/system/t02_config/CreateConfigTest_gold @@ -15,6 +15,7 @@ "gpgDisableVerify": false, "gpgProvider": "gpg", "downloadSourcePackages": false, + "packagePoolStorage": {}, "skipLegacyPool": true, "ppaDistributorID": "ubuntu", "ppaCodename": "", @@ -25,5 +26,14 @@ "SwiftPublishEndpoints": {}, "AzurePublishEndpoints": {}, "AsyncAPI": false, - "enableMetricsEndpoint": false -} \ No newline at end of file + "enableMetricsEndpoint": false, + "logLevel": "debug", + "logFormat": "default", + "serveInAPIMode": false, + "databaseBackend": { + "type": "", + "url": "", + "dbPath": "" + }, + "enableSwaggerEndpoint": false +} diff --git a/system/t02_config/__init__.py b/system/t02_config/__init__.py index 240e5944..a5b0d2f4 100644 --- a/system/t02_config/__init__.py +++ b/system/t02_config/__init__.py @@ -1,66 +1,3 @@ """ Test config file """ - -import os -import re -import inspect -from lib import BaseTest - - -class CreateConfigTest(BaseTest): - """ - new file is generated if missing - """ - runCmd = "aptly mirror list" - checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf") - - check = BaseTest.check_file - gold_processor = BaseTest.expand_environ - prepare = BaseTest.prepare_remove_all - - -class BadConfigTest(BaseTest): - """ - broken config file - """ - runCmd = "aptly mirror list" - expectedCode = 1 - - gold_processor = BaseTest.expand_environ - - def prepare(self): - self.prepare_remove_all() - - f = open(os.path.join(os.environ["HOME"], ".aptly.conf"), "w") - f.write("{some crap") - f.close() - - -class ConfigInFileTest(BaseTest): - """ - config in other file test - """ - runCmd = ["aptly", "mirror", "list", - "-config=%s" % (os.path.join(os.path.dirname(inspect.getsourcefile(BadConfigTest)), "aptly.conf"), )] - prepare = BaseTest.prepare_remove_all - - def outputMatchPrepare(_, s): - return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) - - -class ConfigInMissingFileTest(BaseTest): - """ - config in other file test - """ - runCmd = ["aptly", "mirror", "list", "-config=nosuchfile.conf"] - expectedCode = 1 - prepare = BaseTest.prepare_remove_all - - -class ConfigShowTest(BaseTest): - """ - config showing - """ - runCmd = ["aptly", "config", "show"] - gold_processor = BaseTest.expand_environ diff --git a/system/t02_config/config.py b/system/t02_config/config.py new file mode 100644 index 00000000..240e5944 --- /dev/null +++ b/system/t02_config/config.py @@ -0,0 +1,66 @@ +""" +Test config file +""" + +import os +import re +import inspect +from lib import BaseTest + + +class CreateConfigTest(BaseTest): + """ + new file is generated if missing + """ + runCmd = "aptly mirror list" + checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf") + + check = BaseTest.check_file + gold_processor = BaseTest.expand_environ + prepare = BaseTest.prepare_remove_all + + +class BadConfigTest(BaseTest): + """ + broken config file + """ + runCmd = "aptly mirror list" + expectedCode = 1 + + gold_processor = BaseTest.expand_environ + + def prepare(self): + self.prepare_remove_all() + + f = open(os.path.join(os.environ["HOME"], ".aptly.conf"), "w") + f.write("{some crap") + f.close() + + +class ConfigInFileTest(BaseTest): + """ + config in other file test + """ + runCmd = ["aptly", "mirror", "list", + "-config=%s" % (os.path.join(os.path.dirname(inspect.getsourcefile(BadConfigTest)), "aptly.conf"), )] + prepare = BaseTest.prepare_remove_all + + def outputMatchPrepare(_, s): + return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) + + +class ConfigInMissingFileTest(BaseTest): + """ + config in other file test + """ + runCmd = ["aptly", "mirror", "list", "-config=nosuchfile.conf"] + expectedCode = 1 + prepare = BaseTest.prepare_remove_all + + +class ConfigShowTest(BaseTest): + """ + config showing + """ + runCmd = ["aptly", "config", "show"] + gold_processor = BaseTest.expand_environ diff --git a/system/t03_help/MainHelpTest_gold b/system/t03_help/MainHelpTest_gold index 004f140e..92f07618 100644 --- a/system/t03_help/MainHelpTest_gold +++ b/system/t03_help/MainHelpTest_gold @@ -12,7 +12,7 @@ package environment to new version. Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/MainTest_gold b/system/t03_help/MainTest_gold index 5452f3f1..949288c5 100644 --- a/system/t03_help/MainTest_gold +++ b/system/t03_help/MainTest_gold @@ -20,7 +20,7 @@ Use "aptly help " for more information about a command. Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/MirrorCreateHelpTest_gold b/system/t03_help/MirrorCreateHelpTest_gold index b266c7e0..1816e6d3 100644 --- a/system/t03_help/MirrorCreateHelpTest_gold +++ b/system/t03_help/MirrorCreateHelpTest_gold @@ -14,7 +14,7 @@ Example: Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/MirrorCreateTest_gold b/system/t03_help/MirrorCreateTest_gold index 8783fa5e..74502216 100644 --- a/system/t03_help/MirrorCreateTest_gold +++ b/system/t03_help/MirrorCreateTest_gold @@ -5,7 +5,7 @@ aptly mirror create - create new mirror Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/MirrorHelpTest_gold b/system/t03_help/MirrorHelpTest_gold index 08f6f55a..4c105bf0 100644 --- a/system/t03_help/MirrorHelpTest_gold +++ b/system/t03_help/MirrorHelpTest_gold @@ -16,7 +16,7 @@ Use "mirror help " for more information about a command. Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/MirrorTest_gold b/system/t03_help/MirrorTest_gold index e4825104..ae03d19f 100644 --- a/system/t03_help/MirrorTest_gold +++ b/system/t03_help/MirrorTest_gold @@ -16,7 +16,7 @@ Use "mirror help " for more information about a command. Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/WrongFlagTest_gold b/system/t03_help/WrongFlagTest_gold index 3b293aaf..4dc0cb19 100644 --- a/system/t03_help/WrongFlagTest_gold +++ b/system/t03_help/WrongFlagTest_gold @@ -6,7 +6,7 @@ aptly mirror create - create new mirror Options: -architectures="": list of architectures to consider during (comma-separated), default to all available - -config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf) + -config="": location of configuration file (default locations in order: ~/.aptly.conf, /usr/local/etc/aptly.conf, /etc/aptly.conf) -db-open-attempts=10: number of attempts to open DB if it's locked by other instance -dep-follow-all-variants: when processing dependencies, follow a & b if dependency is 'a|b' -dep-follow-recommends: when processing dependencies, follow Recommends diff --git a/system/t03_help/__init__.py b/system/t03_help/__init__.py index 07f1f828..bfd292b1 100644 --- a/system/t03_help/__init__.py +++ b/system/t03_help/__init__.py @@ -1,65 +1,3 @@ """ Test help screens """ - -import re -from lib import BaseTest - - -class MainTest(BaseTest): - """ - main - """ - expectedCode = 2 - runCmd = "aptly" - - def outputMatchPrepare(_, s): - return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) - - -class MirrorTest(BaseTest): - """ - main - """ - expectedCode = 2 - runCmd = "aptly mirror" - - -class MirrorCreateTest(BaseTest): - """ - main - """ - expectedCode = 2 - runCmd = "aptly mirror create" - - -class MainHelpTest(BaseTest): - """ - main - """ - runCmd = "aptly help" - - def outputMatchPrepare(_, s): - return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) - - -class MirrorHelpTest(BaseTest): - """ - main - """ - runCmd = "aptly help mirror" - - -class MirrorCreateHelpTest(BaseTest): - """ - main - """ - runCmd = "aptly help mirror create" - - -class WrongFlagTest(BaseTest): - """ - main - """ - expectedCode = 2 - runCmd = "aptly mirror create -fxz=sss" diff --git a/system/t03_help/help.py b/system/t03_help/help.py new file mode 100644 index 00000000..07f1f828 --- /dev/null +++ b/system/t03_help/help.py @@ -0,0 +1,65 @@ +""" +Test help screens +""" + +import re +from lib import BaseTest + + +class MainTest(BaseTest): + """ + main + """ + expectedCode = 2 + runCmd = "aptly" + + def outputMatchPrepare(_, s): + return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) + + +class MirrorTest(BaseTest): + """ + main + """ + expectedCode = 2 + runCmd = "aptly mirror" + + +class MirrorCreateTest(BaseTest): + """ + main + """ + expectedCode = 2 + runCmd = "aptly mirror create" + + +class MainHelpTest(BaseTest): + """ + main + """ + runCmd = "aptly help" + + def outputMatchPrepare(_, s): + return re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE) + + +class MirrorHelpTest(BaseTest): + """ + main + """ + runCmd = "aptly help mirror" + + +class MirrorCreateHelpTest(BaseTest): + """ + main + """ + runCmd = "aptly help mirror create" + + +class WrongFlagTest(BaseTest): + """ + main + """ + expectedCode = 2 + runCmd = "aptly mirror create -fxz=sss" diff --git a/system/t04_mirror/CreateMirror10Test_gold b/system/t04_mirror/CreateMirror10Test_gold index 454968b1..d4644347 100644 --- a/system/t04_mirror/CreateMirror10Test_gold +++ b/system/t04_mirror/CreateMirror10Test_gold @@ -1,17 +1,18 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch-backports/InRelease -gpgv: RSA key ID 22F3D138 +gpgv: Signature made Thu Mar 30 14:21:34 2023 UTC +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 -gpgv: RSA key ID 386FA1D9 +gpgv: Signature made Thu Mar 30 14:22:13 2023 UTC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch-backports/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch-backports/Release.gpg -gpgv: RSA key ID 22F3D138 +gpgv: Signature made Thu Mar 30 14:20:54 2023 UTC +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 -gpgv: RSA key ID 386FA1D9 +gpgv: Signature made Thu Mar 30 14:21:30 2023 UTC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 ERROR: unable to fetch mirror: verification of detached signature failed: exit status 2 diff --git a/system/t04_mirror/CreateMirror11Test_gold b/system/t04_mirror/CreateMirror11Test_gold index f225f436..2b5f5051 100644 --- a/system/t04_mirror/CreateMirror11Test_gold +++ b/system/t04_mirror/CreateMirror11Test_gold @@ -1,19 +1,22 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg -gpgv: RSA key ID B7D453EC +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " -gpgv: RSA key ID 22F3D138 +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " -gpgv: RSA key ID 386FA1D9 +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " -gpgv: RSA key ID 1A7B6500 +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: issuer "debian-release@lists.debian.org" gpgv: Good signature from "Debian Stable Release Key (9/stretch) " -Mirror [mirror11]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror11]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror11' to download repository contents. diff --git a/system/t04_mirror/CreateMirror11Test_mirror_show b/system/t04_mirror/CreateMirror11Test_mirror_show index 2d3d2dce..b2c40eb6 100644 --- a/system/t04_mirror/CreateMirror11Test_mirror_show +++ b/system/t04_mirror/CreateMirror11Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror11 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/CreateMirror12Test_gold b/system/t04_mirror/CreateMirror12Test_gold index b6f86cb4..2bd20ad1 100644 --- a/system/t04_mirror/CreateMirror12Test_gold +++ b/system/t04_mirror/CreateMirror12Test_gold @@ -1,18 +1,21 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg -gpgv: RSA key ID B7D453EC +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC -gpgv: RSA key ID 22F3D138 +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 -gpgv: RSA key ID 386FA1D9 +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 -gpgv: RSA key ID 1A7B6500 +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: issuer "debian-release@lists.debian.org" ERROR: unable to fetch mirror: verification of detached signature failed: exit status 2 diff --git a/system/t04_mirror/CreateMirror13Test_gold b/system/t04_mirror/CreateMirror13Test_gold index e3af17b0..f630f384 100644 --- a/system/t04_mirror/CreateMirror13Test_gold +++ b/system/t04_mirror/CreateMirror13Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror13]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror13]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror13' to download repository contents. diff --git a/system/t04_mirror/CreateMirror13Test_mirror_show b/system/t04_mirror/CreateMirror13Test_mirror_show index fb0116a4..61e380fd 100644 --- a/system/t04_mirror/CreateMirror13Test_mirror_show +++ b/system/t04_mirror/CreateMirror13Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror13 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/CreateMirror14Test_gold b/system/t04_mirror/CreateMirror14Test_gold index 2ca76b61..6ba64199 100644 --- a/system/t04_mirror/CreateMirror14Test_gold +++ b/system/t04_mirror/CreateMirror14Test_gold @@ -1,8 +1,7 @@ -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease... -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease -gpgv: RSA key ID 115C3D8A -gpgv: Good signature from "Johannes Ranke (Wissenschaftlicher Berater) " -gpgv: aka "Johannes Ranke " +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/InRelease +gpgv: Signature made Thu Nov 2 07:43:52 2023 UTC +gpgv: using RSA key 7BA040A510E4E66ED3743EC1B8F25A8A73EACF41 +gpgv: Good signature from "Johannes Ranke " -Mirror [mirror14]: https://cloud.r-project.org/bin/linux/debian/ ./jessie-cran35/ successfully added. +Mirror [mirror14]: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/ ./bullseye-cran40/ successfully added. You can run 'aptly mirror update mirror14' to download repository contents. diff --git a/system/t04_mirror/CreateMirror14Test_mirror_show b/system/t04_mirror/CreateMirror14Test_mirror_show index 3309f75d..754770d0 100644 --- a/system/t04_mirror/CreateMirror14Test_mirror_show +++ b/system/t04_mirror/CreateMirror14Test_mirror_show @@ -1,6 +1,6 @@ Name: mirror14 -Archive Root URL: https://cloud.r-project.org/bin/linux/debian/ -Distribution: ./jessie-cran35/ +Archive Root URL: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/ +Distribution: ./bullseye-cran40/ Components: Architectures: Download Sources: no @@ -8,9 +8,9 @@ Download .udebs: no Last update: never Information from release file: -Architectures: i386 amd64 armel all -Codename: jessie-cran35 +Architectures: i386 amd64 all +Codename: bullseye-cran40 Components: main Label: CRAN Backports Origin: CRAN -Suite: jessie-cran35 +Suite: bullseye-cran40 diff --git a/system/t04_mirror/CreateMirror16Test_gold b/system/t04_mirror/CreateMirror16Test_gold index 8badf778..4511ddd9 100644 --- a/system/t04_mirror/CreateMirror16Test_gold +++ b/system/t04_mirror/CreateMirror16Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -ERROR: unable to fetch mirror: architecture source not available in repo [mirror16]: http://cdn-fastly.deb.debian.org/debian/ stretch, use -force-architectures to override +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +ERROR: unable to fetch mirror: architecture source not available in repo [mirror16]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch, use -force-architectures to override diff --git a/system/t04_mirror/CreateMirror17Test_gold b/system/t04_mirror/CreateMirror17Test_gold index d552ada6..b5866902 100644 --- a/system/t04_mirror/CreateMirror17Test_gold +++ b/system/t04_mirror/CreateMirror17Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror17]: http://cdn-fastly.deb.debian.org/debian/ stretch [src] successfully added. +Mirror [mirror17]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch [src] successfully added. You can run 'aptly mirror update mirror17' to download repository contents. diff --git a/system/t04_mirror/CreateMirror17Test_mirror_show b/system/t04_mirror/CreateMirror17Test_mirror_show index cd9eec87..5f233f29 100644 --- a/system/t04_mirror/CreateMirror17Test_mirror_show +++ b/system/t04_mirror/CreateMirror17Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror17 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: i386 diff --git a/system/t04_mirror/CreateMirror18Test_gold b/system/t04_mirror/CreateMirror18Test_gold index 7367a3fc..d63b8745 100644 --- a/system/t04_mirror/CreateMirror18Test_gold +++ b/system/t04_mirror/CreateMirror18Test_gold @@ -1,12 +1,9 @@ -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Error downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease: HTTP code 404 while fetching http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease retrying... -Retrying 0 http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Giving up on http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg -gpgv: RSA key ID 3B1F56C0 +Downloading: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease +gpgv: Signature made Sun Jul 28 07:57:01 2024 UTC +gpgv: using RSA key 5BFCD481D86D5824470E469F9000B1C3A01F726C +gpgv: Good signature from "Launchpad PPA for Anton Gladky" +gpgv: Signature made Sun Jul 28 07:57:01 2024 UTC +gpgv: using RSA key 02219381E9161C78A46CB2BFA5279A973B1F56C0 gpgv: Good signature from "Launchpad sim" Mirror [mirror18]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick successfully added. diff --git a/system/t04_mirror/CreateMirror18Test_mirror_show b/system/t04_mirror/CreateMirror18Test_mirror_show index d2d32be5..750161b0 100644 --- a/system/t04_mirror/CreateMirror18Test_mirror_show +++ b/system/t04_mirror/CreateMirror18Test_mirror_show @@ -11,7 +11,7 @@ Information from release file: Architectures: amd64 armel i386 powerpc Codename: maverick Components: main -Date: Mon, 22 Oct 2012 13:19:50 UTC +Date: Sun, 28 Jul 2024 7:57:00 UTC Description: Ubuntu Maverick 10.10 Label: gnuplot diff --git a/system/t04_mirror/CreateMirror19Test_gold b/system/t04_mirror/CreateMirror19Test_gold index 97eae908..4ae30b74 100644 --- a/system/t04_mirror/CreateMirror19Test_gold +++ b/system/t04_mirror/CreateMirror19Test_gold @@ -1,9 +1,10 @@ -Downloading http://security.debian.org/dists/stretch/updates/InRelease... -Success downloading http://security.debian.org/dists/stretch/updates/InRelease -gpgv: RSA key ID 331F7F50 +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC +gpgv: using RSA key 379483D8B60160B155B372DDAA8E81B4331F7F50 gpgv: Good signature from "Debian Security Archive Automatic Signing Key (9/stretch) " -gpgv: RSA key ID E562B32A +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC +gpgv: using RSA key 5237CEEEF212F3D51C74ABE0112695A0E562B32A gpgv: Good signature from "Debian Security Archive Automatic Signing Key (10/buster) " -Mirror [mirror19]: http://security.debian.org/ stretch/updates [src] successfully added. +Mirror [mirror19]: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates [src] successfully added. You can run 'aptly mirror update mirror19' to download repository contents. diff --git a/system/t04_mirror/CreateMirror19Test_mirror_show b/system/t04_mirror/CreateMirror19Test_mirror_show index 4a1f27e9..5bcaf744 100644 --- a/system/t04_mirror/CreateMirror19Test_mirror_show +++ b/system/t04_mirror/CreateMirror19Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror19 -Archive Root URL: http://security.debian.org/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ Distribution: stretch/updates Components: main Architectures: i386 diff --git a/system/t04_mirror/CreateMirror1Test_gold b/system/t04_mirror/CreateMirror1Test_gold index a14855d8..6a9d12ed 100644 --- a/system/t04_mirror/CreateMirror1Test_gold +++ b/system/t04_mirror/CreateMirror1Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror1]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror1]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror1' to download repository contents. diff --git a/system/t04_mirror/CreateMirror1Test_mirror_show b/system/t04_mirror/CreateMirror1Test_mirror_show index 44e12aec..3acf9b5b 100644 --- a/system/t04_mirror/CreateMirror1Test_mirror_show +++ b/system/t04_mirror/CreateMirror1Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror1 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/CreateMirror20Test_gold b/system/t04_mirror/CreateMirror20Test_gold index 0099d586..2beb4d39 100644 --- a/system/t04_mirror/CreateMirror20Test_gold +++ b/system/t04_mirror/CreateMirror20Test_gold @@ -1,9 +1,9 @@ -Downloading http://security.debian.org/dists/stretch/updates/InRelease... -Error downloading http://security.debian.org/dists/stretch/updates/InRelease: http://security.debian.org/dists/stretch/updates/InRelease: Get "http://security.debian.org/dists/stretch/updates/InRelease": http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused retrying... -Retrying 0 http://security.debian.org/dists/stretch/updates/InRelease... -Giving up on http://security.debian.org/dists/stretch/updates/InRelease... -Downloading http://security.debian.org/dists/stretch/updates/Release... -Error downloading http://security.debian.org/dists/stretch/updates/Release: http://security.debian.org/dists/stretch/updates/Release: Get "http://security.debian.org/dists/stretch/updates/Release": http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused retrying... -Retrying 0 http://security.debian.org/dists/stretch/updates/Release... -Giving up on http://security.debian.org/dists/stretch/updates/Release... -ERROR: unable to fetch mirror: http://security.debian.org/dists/stretch/updates/Release: Get http://security.debian.org/dists/stretch/updates/Release: http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease +Error (retrying): http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease: Get "http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease": http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release +Error (retrying): http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release: Get "http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release": http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release +ERROR: unable to fetch mirror: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release: Get "http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release": http: error connecting to proxy http://127.0.0.1:3137: dial tcp 127.0.0.1:3137: connection refused diff --git a/system/t04_mirror/CreateMirror21Test_gold b/system/t04_mirror/CreateMirror21Test_gold index de4be269..f53413fc 100644 --- a/system/t04_mirror/CreateMirror21Test_gold +++ b/system/t04_mirror/CreateMirror21Test_gold @@ -1,13 +1,12 @@ -Downloading http://pkg.jenkins-ci.org/debian-stable/binary/InRelease... -Error downloading http://pkg.jenkins-ci.org/debian-stable/binary/InRelease: HTTP code 404 while fetching http://pkg.jenkins-ci.org/debian-stable/binary/InRelease retrying... -Retrying 0 http://pkg.jenkins-ci.org/debian-stable/binary/InRelease... -Giving up on http://pkg.jenkins-ci.org/debian-stable/binary/InRelease... -Downloading http://pkg.jenkins-ci.org/debian-stable/binary/Release... -Success downloading http://pkg.jenkins-ci.org/debian-stable/binary/Release -Downloading http://pkg.jenkins-ci.org/debian-stable/binary/Release.gpg... -Success downloading http://pkg.jenkins-ci.org/debian-stable/binary/Release.gpg -gpgv: RSA key ID 45F2C3D5 +Downloading: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/InRelease +Retrying 0 http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/InRelease... +Download Error: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/InRelease +Downloading: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/Release +Downloading: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/binary/Release.gpg +gpgv: Signature made Wed Dec 13 17:19:55 2023 UTC +gpgv: using RSA key 63667EE74BBA1F0A08A698725BA31D57EF5975CA gpgv: Good signature from "Jenkins Project " -Mirror [mirror21]: http://pkg.jenkins-ci.org/debian-stable/ ./binary/ successfully added. +Mirror [mirror21]: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/ ./binary/ successfully added. You can run 'aptly mirror update mirror21' to download repository contents. diff --git a/system/t04_mirror/CreateMirror21Test_mirror_show b/system/t04_mirror/CreateMirror21Test_mirror_show index ba5365ac..a0389012 100644 --- a/system/t04_mirror/CreateMirror21Test_mirror_show +++ b/system/t04_mirror/CreateMirror21Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror21 -Archive Root URL: http://pkg.jenkins-ci.org/debian-stable/ +Archive Root URL: http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable/ Distribution: ./binary/ Components: Architectures: @@ -9,6 +9,5 @@ Last update: never Information from release file: Architectures: all -Date: Wed, 28 Jan 2015 02:32:16 UTC Origin: jenkins.io Suite: binary diff --git a/system/t04_mirror/CreateMirror22Test_gold b/system/t04_mirror/CreateMirror22Test_gold index dc74de6a..1c6143a6 100644 --- a/system/t04_mirror/CreateMirror22Test_gold +++ b/system/t04_mirror/CreateMirror22Test_gold @@ -1,5 +1,4 @@ -Downloading http://security.debian.org/dists/stretch/updates/Release... -Success downloading http://security.debian.org/dists/stretch/updates/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release -Mirror [mirror22]: http://security.debian.org/ stretch/updates successfully added. +Mirror [mirror22]: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates successfully added. You can run 'aptly mirror update mirror22' to download repository contents. diff --git a/system/t04_mirror/CreateMirror22Test_mirror_show b/system/t04_mirror/CreateMirror22Test_mirror_show index 54e7268b..2e8ddb9d 100644 --- a/system/t04_mirror/CreateMirror22Test_mirror_show +++ b/system/t04_mirror/CreateMirror22Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror22 -Archive Root URL: http://security.debian.org/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ Distribution: stretch/updates Components: main Architectures: amd64, arm64, armel, armhf, i386 diff --git a/system/t04_mirror/CreateMirror24Test_gold b/system/t04_mirror/CreateMirror24Test_gold index 4ca1af86..4986d89b 100644 --- a/system/t04_mirror/CreateMirror24Test_gold +++ b/system/t04_mirror/CreateMirror24Test_gold @@ -1,9 +1,10 @@ -Downloading http://security.debian.org/dists/stretch/updates/InRelease... -Success downloading http://security.debian.org/dists/stretch/updates/InRelease -gpgv: RSA key ID 331F7F50 +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC +gpgv: using RSA key 379483D8B60160B155B372DDAA8E81B4331F7F50 gpgv: Good signature from "Debian Security Archive Automatic Signing Key (9/stretch) " -gpgv: RSA key ID E562B32A +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC +gpgv: using RSA key 5237CEEEF212F3D51C74ABE0112695A0E562B32A gpgv: Good signature from "Debian Security Archive Automatic Signing Key (10/buster) " -Mirror [mirror24]: http://security.debian.org/ stretch/updates successfully added. +Mirror [mirror24]: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates successfully added. You can run 'aptly mirror update mirror24' to download repository contents. diff --git a/system/t04_mirror/CreateMirror25Test_gold b/system/t04_mirror/CreateMirror25Test_gold index 511269d4..fb4354c4 100644 --- a/system/t04_mirror/CreateMirror25Test_gold +++ b/system/t04_mirror/CreateMirror25Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror25]: http://cdn-fastly.deb.debian.org/debian/ stretch [udeb] successfully added. +Mirror [mirror25]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch [udeb] successfully added. You can run 'aptly mirror update mirror25' to download repository contents. diff --git a/system/t04_mirror/CreateMirror25Test_mirror_show b/system/t04_mirror/CreateMirror25Test_mirror_show index bf0723ff..0b2c675e 100644 --- a/system/t04_mirror/CreateMirror25Test_mirror_show +++ b/system/t04_mirror/CreateMirror25Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror25 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: i386 diff --git a/system/t04_mirror/CreateMirror27Test_gold b/system/t04_mirror/CreateMirror27Test_gold index 7f76508f..0b5009fb 100644 --- a/system/t04_mirror/CreateMirror27Test_gold +++ b/system/t04_mirror/CreateMirror27Test_gold @@ -1,6 +1,4 @@ -Downloading https://mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/dists/wheezy/Release... -Following redirect to https://linux.dell.com/repo/community/ubuntu/dists/wheezy/Release... -Success downloading https://mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/dists/wheezy/Release +Downloading: http://repo.aptly.info/system-tests/mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/dists/wheezy/Release -Mirror [mirror27]: https://mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/ wheezy successfully added. +Mirror [mirror27]: http://repo.aptly.info/system-tests/mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/ wheezy successfully added. You can run 'aptly mirror update mirror27' to download repository contents. diff --git a/system/t04_mirror/CreateMirror27Test_mirror_show b/system/t04_mirror/CreateMirror27Test_mirror_show index fd272187..97f56255 100644 --- a/system/t04_mirror/CreateMirror27Test_mirror_show +++ b/system/t04_mirror/CreateMirror27Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror27 -Archive Root URL: https://mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/ +Archive Root URL: http://repo.aptly.info/system-tests/mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu/ Distribution: wheezy Components: openmanage/740 Architectures: amd64, i386 diff --git a/system/t04_mirror/CreateMirror29Test_gold b/system/t04_mirror/CreateMirror29Test_gold index be15443b..a4e8c3c3 100644 --- a/system/t04_mirror/CreateMirror29Test_gold +++ b/system/t04_mirror/CreateMirror29Test_gold @@ -1,9 +1,8 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch-backports/InRelease openpgp: RSA key ID 648ACFD622F3D138 openpgp: Good signature from "Debian Archive Automatic Signing Key (10/buster) " openpgp: RSA key ID 0E98404D386FA1D9 openpgp: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " -Mirror [mirror9]: http://cdn-fastly.deb.debian.org/debian/ stretch-backports successfully added. +Mirror [mirror9]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch-backports successfully added. You can run 'aptly mirror update mirror9' to download repository contents. diff --git a/system/t04_mirror/CreateMirror2Test_gold b/system/t04_mirror/CreateMirror2Test_gold index 2f74f102..2fda5e6f 100644 --- a/system/t04_mirror/CreateMirror2Test_gold +++ b/system/t04_mirror/CreateMirror2Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror2]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror2]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror2' to download repository contents. diff --git a/system/t04_mirror/CreateMirror2Test_mirror_show b/system/t04_mirror/CreateMirror2Test_mirror_show index 8e898fc4..e17e9619 100644 --- a/system/t04_mirror/CreateMirror2Test_mirror_show +++ b/system/t04_mirror/CreateMirror2Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror2 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/CreateMirror30Test_gold b/system/t04_mirror/CreateMirror30Test_gold index 7da5ef71..ae944b8e 100644 --- a/system/t04_mirror/CreateMirror30Test_gold +++ b/system/t04_mirror/CreateMirror30Test_gold @@ -1,14 +1,12 @@ opengpg: failure opening keyring '${HOME}/.gnupg/aptlytest.gpg': open ${HOME}/.gnupg/aptlytest.gpg: no such file or directory Looks like your keyring with trusted keys is empty. You might consider importing some keys. -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg openpgp: RSA key ID 04EE7237B7D453EC openpgp: Can't check signature: public key not found openpgp: RSA key ID 648ACFD622F3D138 diff --git a/system/t04_mirror/CreateMirror31Test_gold b/system/t04_mirror/CreateMirror31Test_gold index 8dc0bb89..6ea78d7a 100644 --- a/system/t04_mirror/CreateMirror31Test_gold +++ b/system/t04_mirror/CreateMirror31Test_gold @@ -1,11 +1,9 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg openpgp: RSA key ID 04EE7237B7D453EC openpgp: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " openpgp: RSA key ID 648ACFD622F3D138 @@ -15,5 +13,5 @@ openpgp: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) openpgp: RSA key ID EF0F382A1A7B6500 openpgp: Good signature from "Debian Stable Release Key (9/stretch) " -Mirror [mirror11]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror11]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror11' to download repository contents. diff --git a/system/t04_mirror/CreateMirror32Test_gold b/system/t04_mirror/CreateMirror32Test_gold index 95ca9062..74b4fd17 100644 --- a/system/t04_mirror/CreateMirror32Test_gold +++ b/system/t04_mirror/CreateMirror32Test_gold @@ -1,16 +1,14 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " gpgv: issuer "debian-release@lists.debian.org" gpgv: Good signature from "Debian Stable Release Key (9/stretch) " -Mirror [mirror32]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror32]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror32' to download repository contents. diff --git a/system/t04_mirror/CreateMirror32Test_mirror_show b/system/t04_mirror/CreateMirror32Test_mirror_show index 63fb46fd..6cd09c53 100644 --- a/system/t04_mirror/CreateMirror32Test_mirror_show +++ b/system/t04_mirror/CreateMirror32Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror32 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/CreateMirror33Test_gold b/system/t04_mirror/CreateMirror33Test_gold new file mode 100644 index 00000000..5e363199 --- /dev/null +++ b/system/t04_mirror/CreateMirror33Test_gold @@ -0,0 +1,8 @@ +Downloading: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/Release +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/Release +Retrying 0 http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/Release... +Download Error: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/Release +Downloading: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/InRelease + +Mirror [mirror33]: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/ ./ successfully added. +You can run 'aptly mirror update mirror33' to download repository contents. diff --git a/system/t04_mirror/CreateMirror33Test_mirror_show b/system/t04_mirror/CreateMirror33Test_mirror_show new file mode 100644 index 00000000..1b058198 --- /dev/null +++ b/system/t04_mirror/CreateMirror33Test_mirror_show @@ -0,0 +1,20 @@ +Name: mirror33 +Archive Root URL: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/ +Distribution: ./ +Components: +Architectures: +Download Sources: no +Download .udebs: no +Last update: never + +Information from release file: +Architectures: amd64 +Codename: xenial +Components: main +Date: Wed, 27 Sep 2017 23:08:53 +0000 +Description: NVIDIA container runtime library repository + +Label: NVIDIA CORPORATION +Origin: https://nvidia.github.io/libnvidia-container +Suite: xenial +Version: 1.0 diff --git a/system/t04_mirror/CreateMirror3Test_gold b/system/t04_mirror/CreateMirror3Test_gold index 5fabc64f..8897cd5b 100644 --- a/system/t04_mirror/CreateMirror3Test_gold +++ b/system/t04_mirror/CreateMirror3Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror3]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror3]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror3' to download repository contents. diff --git a/system/t04_mirror/CreateMirror3Test_mirror_show b/system/t04_mirror/CreateMirror3Test_mirror_show index 520c6ea3..f016c6ef 100644 --- a/system/t04_mirror/CreateMirror3Test_mirror_show +++ b/system/t04_mirror/CreateMirror3Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror3 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib Architectures: i386, amd64 diff --git a/system/t04_mirror/CreateMirror4Test_gold b/system/t04_mirror/CreateMirror4Test_gold index 0824a5ea..49002f9d 100644 --- a/system/t04_mirror/CreateMirror4Test_gold +++ b/system/t04_mirror/CreateMirror4Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -ERROR: unable to fetch mirror: component life not available in repo [mirror4]: http://cdn-fastly.deb.debian.org/debian/ stretch, use -force-components to override +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +ERROR: unable to fetch mirror: component life not available in repo [mirror4]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch, use -force-components to override diff --git a/system/t04_mirror/CreateMirror5Test_gold b/system/t04_mirror/CreateMirror5Test_gold index 3bbe6335..9cf18a4a 100644 --- a/system/t04_mirror/CreateMirror5Test_gold +++ b/system/t04_mirror/CreateMirror5Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -ERROR: unable to fetch mirror: architecture nano68 not available in repo [mirror5]: http://cdn-fastly.deb.debian.org/debian/ stretch, use -force-architectures to override +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +ERROR: unable to fetch mirror: architecture nano68 not available in repo [mirror5]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch, use -force-architectures to override diff --git a/system/t04_mirror/CreateMirror6Test_gold b/system/t04_mirror/CreateMirror6Test_gold index 748dd862..956c93bc 100644 --- a/system/t04_mirror/CreateMirror6Test_gold +++ b/system/t04_mirror/CreateMirror6Test_gold @@ -1,9 +1,9 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/suslik/InRelease... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/suslik/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/suslik/InRelease retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/suslik/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/suslik/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release retrying... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release... -ERROR: unable to fetch mirror: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/suslik/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/InRelease... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/Release +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/Release +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/Release... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/Release +ERROR: unable to fetch mirror: HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/suslik/Release diff --git a/system/t04_mirror/CreateMirror7Test_gold b/system/t04_mirror/CreateMirror7Test_gold index e527f84e..10bfc5ba 100644 --- a/system/t04_mirror/CreateMirror7Test_gold +++ b/system/t04_mirror/CreateMirror7Test_gold @@ -1,5 +1,4 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release -Mirror [mirror7]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully added. +Mirror [mirror7]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully added. You can run 'aptly mirror update mirror7' to download repository contents. diff --git a/system/t04_mirror/CreateMirror7Test_mirror_show b/system/t04_mirror/CreateMirror7Test_mirror_show index 4465c015..a62cfb67 100644 --- a/system/t04_mirror/CreateMirror7Test_mirror_show +++ b/system/t04_mirror/CreateMirror7Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror7 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib Architectures: i386, amd64 diff --git a/system/t04_mirror/CreateMirror8Test_gold b/system/t04_mirror/CreateMirror8Test_gold index 69138eca..e9b9017f 100644 --- a/system/t04_mirror/CreateMirror8Test_gold +++ b/system/t04_mirror/CreateMirror8Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release ERROR: unable to add mirror: mirror with name mirror8 already exists diff --git a/system/t04_mirror/CreateMirror9Test_gold b/system/t04_mirror/CreateMirror9Test_gold index d3be9e6a..be1879e1 100644 --- a/system/t04_mirror/CreateMirror9Test_gold +++ b/system/t04_mirror/CreateMirror9Test_gold @@ -1,9 +1,10 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch-backports/InRelease -gpgv: RSA key ID 22F3D138 +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch-backports/InRelease +gpgv: Signature made Thu Mar 30 14:21:34 2023 UTC +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " -gpgv: RSA key ID 386FA1D9 +gpgv: Signature made Thu Mar 30 14:22:13 2023 UTC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " -Mirror [mirror9]: http://cdn-fastly.deb.debian.org/debian/ stretch-backports successfully added. +Mirror [mirror9]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch-backports successfully added. You can run 'aptly mirror update mirror9' to download repository contents. diff --git a/system/t04_mirror/CreateMirror9Test_mirror_show b/system/t04_mirror/CreateMirror9Test_mirror_show index 37039266..302a565c 100644 --- a/system/t04_mirror/CreateMirror9Test_mirror_show +++ b/system/t04_mirror/CreateMirror9Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror9 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch-backports Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x @@ -8,7 +8,6 @@ Download .udebs: no Last update: never Information from release file: -Acquire-By-Hash: yes Architectures: amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x ButAutomaticUpgrades: yes Codename: stretch-backports diff --git a/system/t04_mirror/EditMirror10Test_gold b/system/t04_mirror/EditMirror10Test_gold index 563cdde8..71263eca 100644 --- a/system/t04_mirror/EditMirror10Test_gold +++ b/system/t04_mirror/EditMirror10Test_gold @@ -1,3 +1,2 @@ -Downloading ftp://ftp.ch.debian.org/debian/dists/stretch/Release... -Success downloading ftp://ftp.ch.debian.org/debian/dists/stretch/Release -Mirror [mirror10]: ftp://ftp.ch.debian.org/debian/ stretch successfully updated. +Downloading: http://repo.aptly.info/system-tests/ftp.ch.debian.org/debian/dists/bookworm/Release +Mirror [mirror10]: http://repo.aptly.info/system-tests/ftp.ch.debian.org/debian/ bookworm successfully updated. diff --git a/system/t04_mirror/EditMirror5Test_gold b/system/t04_mirror/EditMirror5Test_gold index 7b872740..23379081 100644 --- a/system/t04_mirror/EditMirror5Test_gold +++ b/system/t04_mirror/EditMirror5Test_gold @@ -1 +1 @@ -Mirror [mirror5]: http://security.debian.org/ stretch/updates successfully updated. +Mirror [mirror5]: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates successfully updated. diff --git a/system/t04_mirror/EditMirror5Test_mirror_show b/system/t04_mirror/EditMirror5Test_mirror_show index 685e8fff..c6dfb1fb 100644 --- a/system/t04_mirror/EditMirror5Test_mirror_show +++ b/system/t04_mirror/EditMirror5Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror5 -Archive Root URL: http://security.debian.org/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ Distribution: stretch/updates Components: main Architectures: amd64, arm64, armel, armhf, i386 diff --git a/system/t04_mirror/EditMirror6Test_gold b/system/t04_mirror/EditMirror6Test_gold index bc37c97b..8aaca4ef 100644 --- a/system/t04_mirror/EditMirror6Test_gold +++ b/system/t04_mirror/EditMirror6Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Mirror [mirror6]: http://cdn-fastly.deb.debian.org/debian/ stretch successfully updated. +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Mirror [mirror6]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch successfully updated. diff --git a/system/t04_mirror/EditMirror6Test_mirror_show b/system/t04_mirror/EditMirror6Test_mirror_show index 2ff6c423..ac42dcfc 100644 --- a/system/t04_mirror/EditMirror6Test_mirror_show +++ b/system/t04_mirror/EditMirror6Test_mirror_show @@ -1,5 +1,5 @@ Name: mirror6 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main Architectures: amd64, i386 diff --git a/system/t04_mirror/EditMirror7Test_gold b/system/t04_mirror/EditMirror7Test_gold index 2c57a1b6..52e969c7 100644 --- a/system/t04_mirror/EditMirror7Test_gold +++ b/system/t04_mirror/EditMirror7Test_gold @@ -1,3 +1,2 @@ -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -ERROR: unable to edit: architecture x56 not available in repo [stretch]: http://cdn-fastly.deb.debian.org/debian/ stretch, use -force-architectures to override +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +ERROR: unable to edit: architecture x56 not available in repo [stretch]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch, use -force-architectures to override diff --git a/system/t04_mirror/ListMirror1Test_gold b/system/t04_mirror/ListMirror1Test_gold index f618902f..dff50d88 100644 --- a/system/t04_mirror/ListMirror1Test_gold +++ b/system/t04_mirror/ListMirror1Test_gold @@ -1,7 +1,7 @@ List of mirrors: - * [mirror1]: http://cdn-fastly.deb.debian.org/debian/ stretch - * [mirror2]: http://cdn-fastly.deb.debian.org/debian/ stretch [src] - * [mirror3]: http://cdn-fastly.deb.debian.org/debian/ stretch - * [mirror4]: http://download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./ + * [mirror1]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch + * [mirror2]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch [src] + * [mirror3]: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch + * [mirror4]: http://repo.aptly.info/system-tests/download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./ To get more information about mirror, run `aptly mirror show `. diff --git a/system/t04_mirror/ListMirror6Test_gold b/system/t04_mirror/ListMirror6Test_gold index cf8b565e..bed19fa2 100644 --- a/system/t04_mirror/ListMirror6Test_gold +++ b/system/t04_mirror/ListMirror6Test_gold @@ -1,7 +1,7 @@ [ { "Name": "mirror1", - "ArchiveRoot": "http://cdn-fastly.deb.debian.org/debian/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/", "Distribution": "stretch", "Components": [ "main", @@ -46,7 +46,7 @@ }, { "Name": "mirror2", - "ArchiveRoot": "http://cdn-fastly.deb.debian.org/debian/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/", "Distribution": "stretch", "Components": [ "contrib" @@ -89,7 +89,7 @@ }, { "Name": "mirror3", - "ArchiveRoot": "http://cdn-fastly.deb.debian.org/debian/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/", "Distribution": "stretch", "Components": [ "non-free" @@ -123,7 +123,7 @@ }, { "Name": "mirror4", - "ArchiveRoot": "http://download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/", "Distribution": "./", "Components": null, "Architectures": null, diff --git a/system/t04_mirror/ShowMirror1Test_gold b/system/t04_mirror/ShowMirror1Test_gold index 44e12aec..3acf9b5b 100644 --- a/system/t04_mirror/ShowMirror1Test_gold +++ b/system/t04_mirror/ShowMirror1Test_gold @@ -1,5 +1,5 @@ Name: mirror1 -Archive Root URL: http://cdn-fastly.deb.debian.org/debian/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ Distribution: stretch Components: main, contrib, non-free Architectures: amd64, arm64, armel, armhf, i386, mips, mips64el, mipsel, ppc64el, s390x diff --git a/system/t04_mirror/ShowMirror4Test_gold b/system/t04_mirror/ShowMirror4Test_gold index c531b649..48ff3286 100644 --- a/system/t04_mirror/ShowMirror4Test_gold +++ b/system/t04_mirror/ShowMirror4Test_gold @@ -1,5 +1,5 @@ Name: mirror4 -Archive Root URL: http://security.debian.org/ +Archive Root URL: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ Distribution: stretch/updates Components: main Architectures: amd64, arm64, armel, armhf, i386 diff --git a/system/t04_mirror/ShowMirror5Test_gold b/system/t04_mirror/ShowMirror5Test_gold index 5e5aaa63..d8ba1780 100644 --- a/system/t04_mirror/ShowMirror5Test_gold +++ b/system/t04_mirror/ShowMirror5Test_gold @@ -1,7 +1,6 @@ { - "UUID": "82ca6517-ab0b-4be9-81bd-e884a07167f2", "Name": "mirror1", - "ArchiveRoot": "http://cdn-fastly.deb.debian.org/debian/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/", "Distribution": "stretch", "Components": [ "main", diff --git a/system/t04_mirror/ShowMirror8Test_gold b/system/t04_mirror/ShowMirror8Test_gold index 2b8ae8fe..9d3f70c5 100644 --- a/system/t04_mirror/ShowMirror8Test_gold +++ b/system/t04_mirror/ShowMirror8Test_gold @@ -1,7 +1,6 @@ { - "UUID": "548dbdb6-75d6-42ac-80de-d6aff8012f83", "Name": "mirror4", - "ArchiveRoot": "http://security.debian.org/", + "ArchiveRoot": "http://repo.aptly.info/system-tests/archive.debian.org/debian-security/", "Distribution": "stretch/updates", "Components": [ "main" @@ -18,12 +17,11 @@ "Architectures": "amd64 arm64 armel armhf i386", "Codename": "stretch", "Components": "updates/main updates/contrib updates/non-free", - "Date": "Wed, 26 Jan 2022 10:02:07 UTC", + "Date": "anytime", "Description": " Debian 9 Security Updates\n", "Label": "Debian-Security", "Origin": "Debian", "Suite": "oldoldstable", - "Valid-Until": "Sat, 05 Feb 2022 10:02:07 UTC", "Version": "9" }, "LastDownloadDate": "0001-01-01T00:00:00Z", diff --git a/system/t04_mirror/UpdateMirror10Test_gold b/system/t04_mirror/UpdateMirror10Test_gold index e1e94596..fa0f41f2 100644 --- a/system/t04_mirror/UpdateMirror10Test_gold +++ b/system/t04_mirror/UpdateMirror10Test_gold @@ -2,34 +2,24 @@ Applying filter... Building download queue... -Download queue: 9 items (3.50 MiB) +Download queue: 11 items (39.66 MiB) Downloading & parsing package files... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Sources.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb... +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/InRelease +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Sources.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-2~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-data_0.7.5-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_i386.deb Mirror `flat-src` has been successfully updated. -Packages filtered: 107 -> 9. -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Sources.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb -gpgv: aka "Johannes Ranke " -gpgv: Good signature from "Johannes Ranke (Wissenschaftlicher Berater) " -gpgv: RSA key ID 115C3D8A \ No newline at end of file +Packages filtered: 110 -> 11. +gpgv: using RSA key 7BA040A510E4E66ED3743EC1B8F25A8A73EACF41 +gpgv: Good signature from "Johannes Ranke " +gpgv: Signature made Thu Nov 2 07:43:52 2023 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror11FTPTest_gold b/system/t04_mirror/UpdateMirror11FTPTest_gold new file mode 100644 index 00000000..24f61552 --- /dev/null +++ b/system/t04_mirror/UpdateMirror11FTPTest_gold @@ -0,0 +1,31 @@ + + +Applying filter... +Building download queue... +Download Error: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease +Download queue: 3 items (354.29 KiB) +Downloading & parsing package files... +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sed/sed_4.4-1_i386.deb +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sensible-utils/sensible-utils_0.0.9+deb9u1_all.deb +Downloading: http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sysvinit/sysvinit-utils_2.88dsf-59.9_i386.deb +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease +Mirror `stretch-main` has been successfully updated. +Packages filtered: 50604 -> 3. +Retrying 0 http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease... +gpgv: issuer "debian-release@lists.debian.org" +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 +gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " +gpgv: Good signature from "Debian Stable Release Key (9/stretch) " +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror11Test_gold b/system/t04_mirror/UpdateMirror11Test_gold deleted file mode 100644 index 735d7085..00000000 --- a/system/t04_mirror/UpdateMirror11Test_gold +++ /dev/null @@ -1,32 +0,0 @@ - - -Applying filter... -Building download queue... -Download queue: 3 items (354.29 KiB) -Downloading & parsing package files... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release.gpg... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/main/binary-i386/Packages.gz... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sed/sed_4.4-1_i386.deb... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sensible-utils/sensible-utils_0.0.9+deb9u1_all.deb... -Downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sysvinit/sysvinit-utils_2.88dsf-59.9_i386.deb... -Error downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease: HTTP code 404 while fetching https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease retrying... -Giving up on https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease... -Mirror `stretch-main` has been successfully updated. -Packages filtered: 50604 -> 3. -Retrying 0 https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/InRelease... -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/Release.gpg -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/dists/stretch/main/binary-i386/Packages.gz -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sed/sed_4.4-1_i386.deb -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sensible-utils/sensible-utils_0.0.9+deb9u1_all.deb -Success downloading https://snapshot.debian.org/archive/debian/20220201T025006Z/pool/main/s/sysvinit/sysvinit-utils_2.88dsf-59.9_i386.deb -gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " -gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " -gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " -gpgv: Good signature from "Debian Stable Release Key (9/stretch) " -gpgv: RSA key ID B7D453EC -gpgv: RSA key ID 22F3D138 -gpgv: RSA key ID 1A7B6500 -gpgv: RSA key ID 386FA1D9 \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror12Test_gold b/system/t04_mirror/UpdateMirror12Test_gold index 34071495..eff42e76 100644 --- a/system/t04_mirror/UpdateMirror12Test_gold +++ b/system/t04_mirror/UpdateMirror12Test_gold @@ -2,79 +2,54 @@ Applying filter... Building download queue... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease Download queue: 20 items (11.93 MiB) Downloading & parsing package files... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-amd64/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/debian-installer/binary-amd64/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/debian-installer/binary-i386/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-amd64/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-i386/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/debian-installer/binary-amd64/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/debian-installer/binary-i386/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-l10n_2.1.18-8~deb9u4_all.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg2_2.1.18-8~deb9u4_all.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_amd64.udeb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_i386.udeb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-win32_2.1.18-8~deb9u4_all.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv2_2.1.18-8~deb9u4_all.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_i386.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_amd64.deb... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_i386.deb... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/debian-installer/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/debian-installer/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/debian-installer/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/debian-installer/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg-l10n_2.1.18-8~deb9u4_all.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg2_2.1.18-8~deb9u4_all.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_amd64.udeb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_i386.udeb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv-win32_2.1.18-8~deb9u4_all.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv2_2.1.18-8~deb9u4_all.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_i386.deb +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease Mirror `stretch` has been successfully updated. Packages filtered: 78248 -> 20. -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-amd64/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/debian-installer/binary-amd64/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/debian-installer/binary-i386/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-amd64/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-i386/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/debian-installer/binary-amd64/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/debian-installer/binary-i386/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/dirmngr_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-agent_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg-l10n_2.1.18-8~deb9u4_all.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg2_2.1.18-8~deb9u4_all.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gnupg_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgsm_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-static_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_amd64.udeb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-udeb_2.1.18-8~deb9u4_i386.udeb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv-win32_2.1.18-8~deb9u4_all.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv2_2.1.18-8~deb9u4_all.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/gpgv_2.1.18-8~deb9u4_i386.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_amd64.deb -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/g/gnupg2/scdaemon_2.1.18-8~deb9u4_i386.deb +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +gpgv: issuer "debian-release@lists.debian.org" +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " gpgv: Good signature from "Debian Stable Release Key (9/stretch) " -gpgv: RSA key ID B7D453EC -gpgv: RSA key ID 22F3D138 -gpgv: RSA key ID 1A7B6500 -gpgv: RSA key ID 386FA1D9 \ No newline at end of file +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror13Test_gold b/system/t04_mirror/UpdateMirror13Test_gold index 4f6c6a66..63c166c8 100644 --- a/system/t04_mirror/UpdateMirror13Test_gold +++ b/system/t04_mirror/UpdateMirror13Test_gold @@ -3,114 +3,59 @@ Building download queue... Download queue: 52 items (19.79 MiB) Downloading & parsing package files... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb... -Mirror `varnish` has been successfully updated. -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb \ No newline at end of file +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb +Mirror `varnish` has been successfully updated. \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror14Test_gold b/system/t04_mirror/UpdateMirror14Test_gold index 2c66db83..0c1b5c59 100644 --- a/system/t04_mirror/UpdateMirror14Test_gold +++ b/system/t04_mirror/UpdateMirror14Test_gold @@ -3,10 +3,7 @@ Building download queue... Download queue: 0 items (0 B) Downloading & parsing package files... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2... -Mirror `varnish` has been successfully updated. -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 \ No newline at end of file +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 +Mirror `varnish` has been successfully updated. \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror17Test_gold b/system/t04_mirror/UpdateMirror17Test_gold index b99be85c..6341c1de 100644 --- a/system/t04_mirror/UpdateMirror17Test_gold +++ b/system/t04_mirror/UpdateMirror17Test_gold @@ -4,9 +4,7 @@ Applying filter... Building download queue... Download queue: 0 items (0 B) Downloading & parsing package files... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz Mirror `stretch` has been successfully updated. -Packages filtered: 50604 -> 1. -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz \ No newline at end of file +Packages filtered: 50604 -> 1. \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror18Test_gold b/system/t04_mirror/UpdateMirror18Test_gold index 33e2dd98..0e0deb88 100644 --- a/system/t04_mirror/UpdateMirror18Test_gold +++ b/system/t04_mirror/UpdateMirror18Test_gold @@ -4,11 +4,8 @@ Applying filter... Building download queue... Download queue: 1 items (3.35 KiB) Downloading & parsing package files... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb Mirror `stretch` has been successfully updated. -Packages filtered: 50604 -> 1. -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-i386/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb \ No newline at end of file +Packages filtered: 50604 -> 1. \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror19Test_gold b/system/t04_mirror/UpdateMirror19Test_gold index b4c1abc7..fcf7c33c 100644 --- a/system/t04_mirror/UpdateMirror19Test_gold +++ b/system/t04_mirror/UpdateMirror19Test_gold @@ -1,16 +1,14 @@ -Downloading https://packages.pagerduty.com/pdagent/deb/InRelease... -Error downloading https://packages.pagerduty.com/pdagent/deb/InRelease: HTTP code 404 while fetching https://packages.pagerduty.com/pdagent/deb/InRelease retrying... -Retrying 0 https://packages.pagerduty.com/pdagent/deb/InRelease... -Giving up on https://packages.pagerduty.com/pdagent/deb/InRelease... -Downloading https://packages.pagerduty.com/pdagent/deb/Release... -Success downloading https://packages.pagerduty.com/pdagent/deb/Release -Downloading https://packages.pagerduty.com/pdagent/deb/Release.gpg... -Success downloading https://packages.pagerduty.com/pdagent/deb/Release.gpg -gpgv: RSA key ID F8253540 +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Retrying 0 http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease... +Download Error: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Release +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Release.gpg +gpgv: Signature made Tue Jun 30 15:56:03 2020 UTC +gpgv: using RSA key AE0396CFF8253540 gpgv: Good signature from "Package Maintainer (PagerDuty, Inc.) " Downloading & parsing package files... -Downloading https://packages.pagerduty.com/pdagent/deb/Packages.gz... -Success downloading https://packages.pagerduty.com/pdagent/deb/Packages.gz +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Packages.gz Building download queue... Download queue: 23 items (3.46 MiB) diff --git a/system/t04_mirror/UpdateMirror1Test_gold b/system/t04_mirror/UpdateMirror1Test_gold index 4f6c6a66..63c166c8 100644 --- a/system/t04_mirror/UpdateMirror1Test_gold +++ b/system/t04_mirror/UpdateMirror1Test_gold @@ -3,114 +3,59 @@ Building download queue... Download queue: 52 items (19.79 MiB) Downloading & parsing package files... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb... -Downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb... -Mirror `varnish` has been successfully updated. -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb -Success downloading https://packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb \ No newline at end of file +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/Release +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/dists/wheezy/main/binary-i386/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi-dev_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.4-1%29/libvarnishapi1_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi-dev_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.5-1%29/libvarnishapi1_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi-dev_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.6-1%29/libvarnishapi1_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi-dev_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish%20%283.0.7-1%29/libvarnishapi1_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi-dev_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/libv/varnish/libvarnishapi1_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-dbg_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish-doc_3.0.4-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.4-1%29/varnish_3.0.4-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-dbg_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish-doc_3.0.5-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.5-1%29/varnish_3.0.5-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-dbg_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish-doc_3.0.6-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.6-1%29/varnish_3.0.6-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-dbg_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish-doc_3.0.7-1~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish%20%283.0.7-1%29/varnish_3.0.7-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%281.16.0%29/varnish-agent_1.16.0~wheezy_all.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.0%29/varnish-agent_2.2.0~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1%29/varnish-agent_2.2.1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%282.2.1+nmu1%29/varnish-agent_2.2.1+nmu1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.0%29/varnish-agent_3.0.0~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish-agent%20%283.0.1%29/varnish-agent_3.0.1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish-dbg_3.0.3-1~wheezy_i386.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_amd64.deb +Downloading: http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/pool/wheezy/main/v/varnish/varnish_3.0.3-1~wheezy_i386.deb +Mirror `varnish` has been successfully updated. \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror20Test_gold b/system/t04_mirror/UpdateMirror20Test_gold index ef7ecd29..3353fc5b 100644 --- a/system/t04_mirror/UpdateMirror20Test_gold +++ b/system/t04_mirror/UpdateMirror20Test_gold @@ -1,23 +1,14 @@ - aka "Johannes Ranke " Applying filter... Building download queue... -Download queue: 4 items (338.12 KiB) +Download queue: 2 items (173.67 KiB) Downloading & parsing package files... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb... +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/InRelease +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_i386.deb Mirror `flat` has been successfully updated. -Packages filtered: 78 -> 4. -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb -openpgp: Good signature from "Johannes Ranke (Wissenschaftlicher Berater) " -openpgp: RSA key ID FCAE2A0E115C3D8A \ No newline at end of file +Packages filtered: 89 -> 2. +openpgp: Good signature from "Johannes Ranke " +openpgp: RSA key ID B8F25A8A73EACF41 \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror21Test_gold b/system/t04_mirror/UpdateMirror21Test_gold index f74816a9..869ec65b 100644 --- a/system/t04_mirror/UpdateMirror21Test_gold +++ b/system/t04_mirror/UpdateMirror21Test_gold @@ -1,16 +1,13 @@ -Downloading https://packages.pagerduty.com/pdagent/deb/InRelease... -Error downloading https://packages.pagerduty.com/pdagent/deb/InRelease: HTTP code 404 while fetching https://packages.pagerduty.com/pdagent/deb/InRelease retrying... -Retrying 0 https://packages.pagerduty.com/pdagent/deb/InRelease... -Giving up on https://packages.pagerduty.com/pdagent/deb/InRelease... -Downloading https://packages.pagerduty.com/pdagent/deb/Release... -Success downloading https://packages.pagerduty.com/pdagent/deb/Release -Downloading https://packages.pagerduty.com/pdagent/deb/Release.gpg... -Success downloading https://packages.pagerduty.com/pdagent/deb/Release.gpg +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Retrying 0 http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease... +Download Error: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/InRelease +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Release +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Release.gpg openpgp: RSA key ID AE0396CFF8253540 openpgp: Good signature from "Package Maintainer (PagerDuty, Inc.) " Downloading & parsing package files... -Downloading https://packages.pagerduty.com/pdagent/deb/Packages.gz... -Success downloading https://packages.pagerduty.com/pdagent/deb/Packages.gz +Downloading: http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent/deb/Packages.gz Building download queue... Download queue: 23 items (3.46 MiB) diff --git a/system/t04_mirror/UpdateMirror22Test_gold b/system/t04_mirror/UpdateMirror22Test_gold index 34edb82c..6724bab1 100644 --- a/system/t04_mirror/UpdateMirror22Test_gold +++ b/system/t04_mirror/UpdateMirror22Test_gold @@ -1,10 +1,8 @@ -Downloading https://nvidia.github.io/libnvidia-container/ubuntu16.04/amd64/InRelease... -Success downloading https://nvidia.github.io/libnvidia-container/ubuntu16.04/amd64/InRelease +Downloading: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/InRelease openpgp: RSA key ID DDCAE044F796ECB0 openpgp: Good signature from "NVIDIA CORPORATION (Open Source Projects) " Downloading & parsing package files... -Downloading https://nvidia.github.io/libnvidia-container/ubuntu16.04/amd64/Packages.xz... -Success downloading https://nvidia.github.io/libnvidia-container/ubuntu16.04/amd64/Packages.xz +Downloading: http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64/Packages.xz Applying filter... Building download queue... diff --git a/system/t04_mirror/UpdateMirror23Test_gold b/system/t04_mirror/UpdateMirror23Test_gold index 2f7f9fd7..5e6157c7 100644 --- a/system/t04_mirror/UpdateMirror23Test_gold +++ b/system/t04_mirror/UpdateMirror23Test_gold @@ -2,49 +2,41 @@ Applying filter... Building download queue... +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS Download queue: 8 items (20.93 MiB) Downloading & parsing package files... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-s390x/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST.udebs... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MD5SUMS... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/SHA256SUMS... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/debian.exec... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/initrd.debian... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/kernel.debian... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/parmfile.debian... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/udeb.list... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-s390x/Packages.gz... -Downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease retrying... -Error downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS: HTTP code 404 while fetching http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS retrying... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Giving up on http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-s390x/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST.udebs +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/MD5SUMS +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/SHA256SUMS +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/generic/debian.exec +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/generic/initrd.debian +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/generic/kernel.debian +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/generic/parmfile.debian +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/installer-s390x/current/images/udeb.list +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/binary-s390x/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS Mirror `stretch` has been successfully updated. Packages filtered: 49256 -> 1. -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/InRelease... -Retrying 0 http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS... -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/Release.gpg -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/binary-s390x/Packages.gz -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MANIFEST.udebs -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/MD5SUMS -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/SHA256SUMS -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/debian.exec -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/initrd.debian -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/kernel.debian -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/generic/parmfile.debian -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/main/installer-s390x/current/images/udeb.list -Success downloading http://cdn-fastly.deb.debian.org/debian/dists/stretch/non-free/binary-s390x/Packages.gz +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease... +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/non-free/installer-s390x/current/images/SHA256SUMS... +gpgv: issuer "debian-release@lists.debian.org" +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " gpgv: Good signature from "Debian Stable Release Key (9/stretch) " -gpgv: RSA key ID B7D453EC -gpgv: RSA key ID 22F3D138 -gpgv: RSA key ID 1A7B6500 -gpgv: RSA key ID 386FA1D9 \ No newline at end of file +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror24Test_gold b/system/t04_mirror/UpdateMirror24Test_gold index 34c99295..e8ec96b9 100644 --- a/system/t04_mirror/UpdateMirror24Test_gold +++ b/system/t04_mirror/UpdateMirror24Test_gold @@ -2,109 +2,70 @@ Applying filter... Building download queue... +Download Error: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease +Download Error: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS Download queue: 37 items (166.14 MiB) Downloading & parsing package files... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/Release... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/Release.gpg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/binary-amd64/Packages.bz2... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST.udebs... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS.gpg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/debian-cd_info.tar.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/initrd.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/vmlinuz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/xen/xm-debian.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/boot.img.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/initrd.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/vmlinuz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/boot.img.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/mini.iso... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/netboot.tar.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/adtxt.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/exithelp.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f1.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f10.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f2.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f3.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f4.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f5.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f6.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f7.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f8.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f9.txt... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/menu.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/prompt.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/rqtxt.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/splash.png... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/stdmenu.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/syslinux.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/txt.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/vesamenu.c32... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/initrd.gz... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/linux... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/pxelinux.0... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/xen/xm-debian.cfg... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/udeb.list... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/binary-amd64/Packages.bz2... -Downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS... -Error downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease: HTTP code 404 while fetching http://us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease retrying... -Error downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS: HTTP code 404 while fetching http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS retrying... -Giving up on http://us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease... -Giving up on http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS... +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/Release +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/Release.gpg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST.udebs +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS.gpg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/debian-cd_info.tar.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/initrd.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/vmlinuz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/xen/xm-debian.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/boot.img.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/initrd.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/vmlinuz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/boot.img.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/mini.iso +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/netboot.tar.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/adtxt.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/exithelp.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f1.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f10.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f2.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f3.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f4.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f5.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f6.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f7.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f8.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f9.txt +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/menu.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/prompt.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/rqtxt.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/splash.png +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/stdmenu.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/syslinux.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/txt.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/vesamenu.c32 +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/initrd.gz +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/linux +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/pxelinux.0 +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/xen/xm-debian.cfg +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/udeb.list +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS Mirror `trusty` has been successfully updated. Packages filtered: 8616 -> 1. -Retrying 0 http://us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease... -Retrying 0 http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS... -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/Release -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/Release.gpg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/binary-amd64/Packages.bz2 -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/MANIFEST.udebs -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/SHA256SUMS.gpg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/debian-cd_info.tar.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/initrd.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/vmlinuz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/cdrom/xen/xm-debian.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/boot.img.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/initrd.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/hd-media/vmlinuz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/boot.img.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/mini.iso -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/netboot.tar.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/adtxt.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/exithelp.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f1.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f10.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f2.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f3.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f4.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f5.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f6.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f7.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f8.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/f9.txt -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/menu.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/prompt.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/rqtxt.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/splash.png -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/stdmenu.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/syslinux.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/txt.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/boot-screens/vesamenu.c32 -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/initrd.gz -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/linux -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64/pxelinux.0 -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/xen/xm-debian.cfg -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/udeb.list -Success downloading http://us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/binary-amd64/Packages.bz2 +Retrying 0 http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/InRelease... +Retrying 0 http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/dists/trusty/restricted/installer-amd64/current/images/SHA256SUMS... +gpgv: using DSA key 40976EAF437D05B5 +gpgv: using DSA key 40976EAF437D05B5 +gpgv: using RSA key 3B4FE6ACC0B21F32 +gpgv: using RSA key 3B4FE6ACC0B21F32 gpgv: Good signature from "Ubuntu Archive Automatic Signing Key (2012) " gpgv: Good signature from "Ubuntu Archive Automatic Signing Key (2012) " gpgv: Good signature from "Ubuntu Archive Automatic Signing Key " gpgv: Good signature from "Ubuntu Archive Automatic Signing Key " -gpgv: DSA key ID 437D05B5 -gpgv: RSA key ID C0B21F32 -gpgv: DSA key ID 437D05B5 -gpgv: RSA key ID C0B21F32 \ No newline at end of file +gpgv: Signature made Thu May 8 14:20:33 2014 UTC +gpgv: Signature made Thu May 8 14:20:33 2014 UTC +gpgv: Signature made Tue Apr 15 22:05:21 2014 UTC +gpgv: Signature made Tue Apr 15 22:05:21 2014 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror25Test_gold b/system/t04_mirror/UpdateMirror25Test_gold new file mode 100644 index 00000000..41b197ca --- /dev/null +++ b/system/t04_mirror/UpdateMirror25Test_gold @@ -0,0 +1,22 @@ + +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.gz +Download Error: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.xz +Downloading & parsing package files... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.xz +ERROR: unable to update: HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.gz +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.xz +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages... +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.gz... +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/main/binary-i386/Packages.xz... +gpgv: using RSA key 379483D8B60160B155B372DDAA8E81B4331F7F50 +gpgv: using RSA key 5237CEEEF212F3D51C74ABE0112695A0E562B32A +gpgv: Good signature from "Debian Security Archive Automatic Signing Key (10/buster) " +gpgv: Good signature from "Debian Security Archive Automatic Signing Key (9/stretch) " +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC +gpgv: Signature made Sat Feb 18 04:22:45 2023 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror26Test_gold b/system/t04_mirror/UpdateMirror26Test_gold new file mode 100644 index 00000000..aa6d212e --- /dev/null +++ b/system/t04_mirror/UpdateMirror26Test_gold @@ -0,0 +1,33 @@ + + +Applying filter... +Building download queue... +Download queue: 1 items (3.35 KiB) +Downloading & parsing package files... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb +Mirror `grab` has been successfully updated. +Packages filtered: 50604 -> 1. +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +gpgv: issuer "debian-release@lists.debian.org" +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 +gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " +gpgv: Good signature from "Debian Stable Release Key (9/stretch) " +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror27Test_gold b/system/t04_mirror/UpdateMirror27Test_gold new file mode 100644 index 00000000..677e80cb --- /dev/null +++ b/system/t04_mirror/UpdateMirror27Test_gold @@ -0,0 +1,39 @@ + + server returned 404 Not Found +Applying filter... +Building download queue... +Download queue: 2 items (6.70 KiB) +Downloading & parsing package files... +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/Release.gpg +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-amd64/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/main/binary-i386/Packages.gz +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_amd64.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb +Downloading: http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_i386.deb +ERROR: unable to update: download errors: +Packages filtered: 76844 -> 2. +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/dists/stretch/InRelease +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_amd64.deb +Retrying 0 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/pool/main/b/boost-defaults/libboost-program-options-dev_1.62.0.1_amd64.deb +gpgv: issuer "debian-release@lists.debian.org" +gpgv: using RSA key 0146DC6D4A0B2914BDED34DB648ACFD622F3D138 +gpgv: using RSA key 067E3C456BAE240ACEE88F6FEF0F382A1A7B6500 +gpgv: using RSA key 16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC +gpgv: using RSA key A7236886F3CCCAAD148A27F80E98404D386FA1D9 +gpgv: Good signature from "Debian Archive Automatic Signing Key (10/buster) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (11/bullseye) " +gpgv: Good signature from "Debian Archive Automatic Signing Key (9/stretch) " +gpgv: Good signature from "Debian Stable Release Key (9/stretch) " +gpgv: Signature made Sat Aug 14 07:43:24 2021 UTC +gpgv: Signature made Sat Aug 14 07:43:25 2021 UTC +gpgv: Signature made Sat Aug 14 08:26:43 2021 UTC +gpgv: Signature made Sat Aug 14 08:46:19 2021 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror3Test_gold b/system/t04_mirror/UpdateMirror3Test_gold index cc9a36e1..cdb53260 100644 --- a/system/t04_mirror/UpdateMirror3Test_gold +++ b/system/t04_mirror/UpdateMirror3Test_gold @@ -1,8 +1,7 @@ -Downloading ${url}dists/hardy/Release... -Success downloading ${url}dists/hardy/Release +Downloading: ${url}dists/hardy/Release Downloading & parsing package files... -Downloading ${url}dists/hardy/main/binary-amd64/Packages... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages: ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d" retrying... +Downloading: ${url}dists/hardy/main/binary-amd64/Packages +Error (retrying): ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d" Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages ERROR: unable to update: ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d" diff --git a/system/t04_mirror/UpdateMirror4Test_gold b/system/t04_mirror/UpdateMirror4Test_gold index d8ba9728..b661f866 100644 --- a/system/t04_mirror/UpdateMirror4Test_gold +++ b/system/t04_mirror/UpdateMirror4Test_gold @@ -1,19 +1,17 @@ -Downloading ${url}dists/hardy/Release... -Success downloading ${url}dists/hardy/Release +Downloading: ${url}dists/hardy/Release Downloading & parsing package files... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.bz2 retrying... +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.bz2 +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.bz2 Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.gz: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.gz retrying... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.bz2 +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.gz +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.gz Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.gz... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.gz... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.xz... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.xz: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.xz retrying... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.gz +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.xz +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.xz Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.xz... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.xz... -Downloading ${url}dists/hardy/main/binary-amd64/Packages... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.xz +Downloading: ${url}dists/hardy/main/binary-amd64/Packages WARNING: ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d" -Success downloading ${url}dists/hardy/main/binary-amd64/Packages ERROR: unable to update: malformed stanza syntax diff --git a/system/t04_mirror/UpdateMirror5Test_gold b/system/t04_mirror/UpdateMirror5Test_gold index 61d8087c..315f6201 100644 --- a/system/t04_mirror/UpdateMirror5Test_gold +++ b/system/t04_mirror/UpdateMirror5Test_gold @@ -1,13 +1,11 @@ -Downloading ${url}dists/hardy/Release... -Success downloading ${url}dists/hardy/Release +Downloading: ${url}dists/hardy/Release Downloading & parsing package files... -Downloading ${url}dists/hardy/main/binary-amd64/Packages... -Success downloading ${url}dists/hardy/main/binary-amd64/Packages +Downloading: ${url}dists/hardy/main/binary-amd64/Packages Building download queue... Download queue: 1 items (30 B) -Downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb... -Error downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3" retrying... +Downloading: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb +Error (retrying): ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3" Retrying 0 ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb... -Giving up on ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb... +Download Error: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb ERROR: unable to update: download errors: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3" diff --git a/system/t04_mirror/UpdateMirror6Test_gold b/system/t04_mirror/UpdateMirror6Test_gold index cd5b73c4..84cb9694 100644 --- a/system/t04_mirror/UpdateMirror6Test_gold +++ b/system/t04_mirror/UpdateMirror6Test_gold @@ -1,24 +1,21 @@ -Downloading ${url}dists/hardy/Release... -Success downloading ${url}dists/hardy/Release +Downloading: ${url}dists/hardy/Release Downloading & parsing package files... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.bz2 retrying... +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.bz2 +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.bz2 Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.bz2... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.gz: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.gz retrying... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.bz2 +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.gz +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.gz Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.gz... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.gz... -Downloading ${url}dists/hardy/main/binary-amd64/Packages.xz... -Error downloading ${url}dists/hardy/main/binary-amd64/Packages.xz: HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.xz retrying... +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.gz +Downloading: ${url}dists/hardy/main/binary-amd64/Packages.xz +Error (retrying): HTTP code 404 while fetching ${url}dists/hardy/main/binary-amd64/Packages.xz Retrying 0 ${url}dists/hardy/main/binary-amd64/Packages.xz... -Giving up on ${url}dists/hardy/main/binary-amd64/Packages.xz... -Downloading ${url}dists/hardy/main/binary-amd64/Packages... -Success downloading ${url}dists/hardy/main/binary-amd64/Packages +Download Error: ${url}dists/hardy/main/binary-amd64/Packages.xz +Downloading: ${url}dists/hardy/main/binary-amd64/Packages Building download queue... Download queue: 1 items (30 B) -Downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb... +Downloading: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb WARNING: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3" -Success downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb Mirror `failure` has been successfully updated. diff --git a/system/t04_mirror/UpdateMirror7Test_gold b/system/t04_mirror/UpdateMirror7Test_gold index 1f2a4b27..14090853 100644 --- a/system/t04_mirror/UpdateMirror7Test_gold +++ b/system/t04_mirror/UpdateMirror7Test_gold @@ -1,169 +1,100 @@ Building download queue... -Download queue: 78 items (200.63 MiB) +Download queue: 89 items (158.97 MiB) Downloading & parsing package files... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-boot_1.3-20-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-15-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-16-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.6-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb... +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/InRelease +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-2~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core-dbgsym_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core-dbgsym_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-dev_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-html_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-boot_1.3-28.1-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class-dbgsym_7.3-22-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class-dbgsym_7.3-22-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster-dbgsym_2.1.4-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster-dbgsym_2.1.4-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster_2.1.4-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster_2.1.4-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-coda_0.19-4-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-codetools_0.2-19-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign-dbgsym_0.8.85-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign-dbgsym_0.8.85-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign_0.8.85-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign_0.8.85-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth-dbgsym_2.23-22-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth-dbgsym_2.23-22-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth_2.23-22-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth_2.23-22-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice-dbgsym_0.22-5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice-dbgsym_0.22-5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice_0.22-5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice_0.22-5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass-dbgsym_7.3-60-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass-dbgsym_7.3-60-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix-dbgsym_1.6-1.1-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix-dbgsym_1.6-1.1-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix_1.6-1.1-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix_1.6-1.1-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv-dbgsym_1.9-0-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv-dbgsym_1.9-0-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv_1.9-0-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv_1.9-0-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme-dbgsym_3.1.163-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme-dbgsym_3.1.163-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme_3.1.163-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme_3.1.163-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet-dbgsym_7.3-19-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet-dbgsym_7.3-19-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart-dbgsym_4.1.21-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart-dbgsym_4.1.21-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart_4.1.21-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart_4.1.21-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial-dbgsym_7.3-17-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial-dbgsym_7.3-17-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival-dbgsym_3.5-7-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival-dbgsym_3.5-7-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival_3.5-7-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival_3.5-7-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-html_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-info_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-pdf_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib-dbgsym_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib-dbgsym_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-recommended_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-data_0.7.5-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_i386.deb Mirror `flat` has been successfully updated. -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-boot_1.3-20-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-15-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-16-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.6-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb -gpgv: aka "Johannes Ranke " -gpgv: Good signature from "Johannes Ranke (Wissenschaftlicher Berater) " -gpgv: RSA key ID 115C3D8A \ No newline at end of file +gpgv: using RSA key 7BA040A510E4E66ED3743EC1B8F25A8A73EACF41 +gpgv: Good signature from "Johannes Ranke " +gpgv: Signature made Thu Nov 2 07:43:52 2023 UTC \ No newline at end of file diff --git a/system/t04_mirror/UpdateMirror8Test_gold b/system/t04_mirror/UpdateMirror8Test_gold index a299fe9d..30dbccb9 100644 --- a/system/t04_mirror/UpdateMirror8Test_gold +++ b/system/t04_mirror/UpdateMirror8Test_gold @@ -1,22 +1,17 @@ -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Error downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease: HTTP code 404 while fetching http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease retrying... -Retrying 0 http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Giving up on http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg -gpgv: RSA key ID 3B1F56C0 +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease +Error (retrying): HTTP code 404 while fetching http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease +Retrying 0 http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease... +Download Error: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/InRelease +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/Release.gpg +gpgv: Signature made Mon Oct 22 13:19:50 2012 UTC +gpgv: using RSA key A5279A973B1F56C0 gpgv: Good signature from "Launchpad sim" Downloading & parsing package files... -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-amd64/Packages.bz2... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-amd64/Packages.bz2 -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-armel/Packages.bz2... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-armel/Packages.bz2 -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-i386/Packages.bz2... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-i386/Packages.bz2 -Downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-powerpc/Packages.bz2... -Success downloading http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-powerpc/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-amd64/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-armel/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-i386/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/dists/maverick/main/binary-powerpc/Packages.bz2 Building download queue... Download queue: 0 items (0 B) diff --git a/system/t04_mirror/UpdateMirror9Test_gold b/system/t04_mirror/UpdateMirror9Test_gold index 84d8e129..1d898874 100644 --- a/system/t04_mirror/UpdateMirror9Test_gold +++ b/system/t04_mirror/UpdateMirror9Test_gold @@ -1,343 +1,163 @@ Building download queue... -Download queue: 164 items (278.49 MiB) +Download queue: 151 items (213.34 MiB) Downloading & parsing package files... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Sources.bz2... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20-2~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15-2~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15-3~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15-3~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35-1~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-boot_1.3-20-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-15-2~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-16-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.6-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.2-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.3-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15-1~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13-1~jessiecran.0.diff.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5.orig.tar.gz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3-1~jessiecran.0.debian.tar.xz... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3-1~jessiecran.0.dsc... -Downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3.orig.tar.gz... +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/InRelease +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Packages.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/Sources.bz2 +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/boot_1.3-28.1-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/boot_1.3-28.1-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/boot_1.3-28.1.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/cluster_2.1.4-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/cluster_2.1.4-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/cluster_2.1.4.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/codetools_0.2-19-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/codetools_0.2-19-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/codetools_0.2-19.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/foreign_0.8.85-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/foreign_0.8.85-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/foreign_0.8.85.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/kernsmooth_2.23-22-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/kernsmooth_2.23-22-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/kernsmooth_2.23-22.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/lattice_0.22-5-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/lattice_0.22-5-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/lattice_0.22-5.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-2~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-2~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18-2~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/littler_0.3.18.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/mgcv_1.9-0-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/mgcv_1.9-0-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/mgcv_1.9-0.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/nlme_3.1.163-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/nlme_3.1.163-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/nlme_3.1.163.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2-dbgsym_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/python3-rpy2_3.5.12-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core-dbgsym_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core-dbgsym_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-core_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-dev_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base-html_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base_4.3.2-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base_4.3.2-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-base_4.3.2.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-boot_1.3-28.1-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class-dbgsym_7.3-22-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class-dbgsym_7.3-22-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-class_7.3-22.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster-dbgsym_2.1.4-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster-dbgsym_2.1.4-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster_2.1.4-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-cluster_2.1.4-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-coda_0.19-4-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-coda_0.19-4-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-coda_0.19-4-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-coda_0.19-4.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-codetools_0.2-19-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign-dbgsym_0.8.85-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign-dbgsym_0.8.85-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign_0.8.85-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-foreign_0.8.85-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth-dbgsym_2.23-22-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth-dbgsym_2.23-22-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth_2.23-22-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-kernsmooth_2.23-22-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice-dbgsym_0.22-5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice-dbgsym_0.22-5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice_0.22-5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-lattice_0.22-5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler-dbgsym_0.3.18-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-littler_0.3.18-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass-dbgsym_7.3-60-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass-dbgsym_7.3-60-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mass_7.3-60.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix-dbgsym_1.6-1.1-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix-dbgsym_1.6-1.1-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix_1.6-1.1-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-matrix_1.6-1.1-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv-dbgsym_1.9-0-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv-dbgsym_1.9-0-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv_1.9-0-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-mgcv_1.9-0-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme-dbgsym_3.1.163-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme-dbgsym_3.1.163-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme_3.1.163-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nlme_3.1.163-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet-dbgsym_7.3-19-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet-dbgsym_7.3-19-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19-2~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-nnet_7.3-19.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart-dbgsym_4.1.21-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart-dbgsym_4.1.21-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart_4.1.21-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-rpart_4.1.21-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial-dbgsym_7.3-17-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial-dbgsym_7.3-17-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-spatial_7.3-17.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival-dbgsym_3.5-7-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival-dbgsym_3.5-7-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival_3.5-7-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-cran-survival_3.5-7-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-html_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-info_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-doc-pdf_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib-dbgsym_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib-dbgsym_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib_4.3.2-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-mathlib_4.3.2-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/r-recommended_4.3.2-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-data_0.7.5-1~bullseyecran.0_all.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward-dbgsym_0.7.5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_amd64.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5-1~bullseyecran.0_i386.deb +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rkward_0.7.5.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rmatrix_1.6-1.1-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rmatrix_1.6-1.1-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rmatrix_1.6-1.1.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpart_4.1.21-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpart_4.1.21-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpart_4.1.21.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpy2_3.5.12-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpy2_3.5.12-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/rpy2_3.5.12.orig.tar.gz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/survival_3.5-7-1~bullseyecran.0.debian.tar.xz +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/survival_3.5-7-1~bullseyecran.0.dsc +Downloading: http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian/bullseye-cran40/survival_3.5-7.orig.tar.gz Mirror `flat-src` has been successfully updated. -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/InRelease -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Packages.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/Sources.bz2 -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20-2~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/boot_1.3-20.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/cluster_2.0.7-1.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15-2~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-15.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/codetools_0.2-16.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/dh-r_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/foreign_0.8.71.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15-3~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15-3~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/kernsmooth_2.23-15.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35-1~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-35.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/lattice_0.20-38.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.5.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/littler_0.3.6.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-26.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/mgcv_1.8-27.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/nlme_3.1.137.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/pkg-r-autopkgtest_20180403~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/python3-rpy2_2.9.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core-dbg_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-core_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-dev_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base-html_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.2.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-base_3.5.3.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-boot_1.3-20-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-14.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-class_7.3-15.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-cluster_2.0.7-1-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-coda_0.19-1.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-15-2~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-codetools_0.2-16-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-foreign_0.8.71-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-kernsmooth_2.23-15-3~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-35-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-lattice_0.20-38-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-littler_0.3.6-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mass_7.3-51.1.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-matrix_1.2-16-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-26-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-mgcv_1.8-27-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nlme_3.1.137-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-nnet_7.3-12.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rodbc_1.3-15-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-rpart_4.1-13-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11-2~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-spatial_7.3-11.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-cran-survival_2.43-3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-html_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-info_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-doc-pdf_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.2-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-mathlib_3.5.3-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.2-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/r-recommended_3.5.3-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward-data_0.6.5-1~jessiecran.0_all.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_amd64.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5-1~jessiecran.0_i386.deb -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rkward_0.6.5.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-15.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rmatrix_1.2-16.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15-1~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rodbc_1.3-15.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13-1~jessiecran.0.diff.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpart_4.1-13.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/rpy2_2.9.5.orig.tar.gz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3-1~jessiecran.0.debian.tar.xz -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3-1~jessiecran.0.dsc -Success downloading https://cloud.r-project.org/bin/linux/debian/jessie-cran35/survival_2.43-3.orig.tar.gz -gpgv: aka "Johannes Ranke " -gpgv: Good signature from "Johannes Ranke (Wissenschaftlicher Berater) " -gpgv: RSA key ID 115C3D8A \ No newline at end of file +gpgv: using RSA key 7BA040A510E4E66ED3743EC1B8F25A8A73EACF41 +gpgv: Good signature from "Johannes Ranke " +gpgv: Signature made Thu Nov 2 07:43:52 2023 UTC \ No newline at end of file diff --git a/system/t04_mirror/create.py b/system/t04_mirror/create.py index 111af25e..ef3d80f6 100644 --- a/system/t04_mirror/create.py +++ b/system/t04_mirror/create.py @@ -1,4 +1,5 @@ import re +import os from lib import BaseTest @@ -7,7 +8,7 @@ class CreateMirror1Test(BaseTest): """ create mirror: all architectures + all components """ - runCmd = "aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" def check(self): self.check_output() @@ -18,7 +19,7 @@ class CreateMirror2Test(BaseTest): """ create mirror: all architectures and 1 component """ - runCmd = "aptly mirror create --ignore-signatures mirror2 http://cdn-fastly.deb.debian.org/debian/ stretch main" + runCmd = "aptly mirror create --ignore-signatures mirror2 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main" def check(self): self.check_output() @@ -29,7 +30,7 @@ class CreateMirror3Test(BaseTest): """ create mirror: some architectures and 2 components """ - runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror3 http://cdn-fastly.deb.debian.org/debian/ stretch main contrib" + runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror3 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main contrib" def check(self): self.check_output() @@ -42,7 +43,7 @@ class CreateMirror4Test(BaseTest): """ expectedCode = 1 - runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror4 http://cdn-fastly.deb.debian.org/debian/ stretch life" + runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror4 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch life" class CreateMirror5Test(BaseTest): @@ -51,7 +52,7 @@ class CreateMirror5Test(BaseTest): """ expectedCode = 1 - runCmd = "aptly -architectures=i386,nano68 mirror create --ignore-signatures mirror5 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly -architectures=i386,nano68 mirror create --ignore-signatures mirror5 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" class CreateMirror6Test(BaseTest): @@ -59,17 +60,17 @@ class CreateMirror6Test(BaseTest): create mirror: missing release """ expectedCode = 1 - requiresGPG1 = True + requiresGPG2 = True configOverride = {"max-tries": 1} - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror6 http://cdn-fastly.deb.debian.org/debian/ suslik" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror6 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ suslik" class CreateMirror7Test(BaseTest): """ create mirror: architectures fixed via config file """ - runCmd = "aptly mirror create --ignore-signatures mirror7 http://cdn-fastly.deb.debian.org/debian/ stretch main contrib" + runCmd = "aptly mirror create --ignore-signatures mirror7 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main contrib" configOverride = {"architectures": ["i386", "amd64"]} def check(self): @@ -82,9 +83,9 @@ class CreateMirror8Test(BaseTest): create mirror: already exists """ fixtureCmds = [ - "aptly mirror create --ignore-signatures mirror8 http://cdn-fastly.deb.debian.org/debian/ stretch main contrib" + "aptly mirror create --ignore-signatures mirror8 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main contrib" ] - runCmd = "aptly mirror create --ignore-signatures mirror8 http://cdn-fastly.deb.debian.org/debian/ stretch main contrib" + runCmd = "aptly mirror create --ignore-signatures mirror8 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main contrib" expectedCode = 1 @@ -92,9 +93,9 @@ class CreateMirror9Test(BaseTest): """ create mirror: repo with InRelease verification """ - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror9 http://cdn-fastly.deb.debian.org/debian/ stretch-backports" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror9 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch-backports" fixtureGpg = True - requiresGPG1 = True + requiresGPG2 = True def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using|Warning: using insecure memory!\n', '', s) @@ -112,7 +113,7 @@ class CreateMirror10Test(BaseTest): """ create mirror: repo with InRelease verification, failure """ - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror10 http://cdn-fastly.deb.debian.org/debian/ stretch-backports" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror10 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch-backports" fixtureGpg = False gold_processor = BaseTest.expand_environ expectedCode = 1 @@ -126,7 +127,7 @@ class CreateMirror11Test(BaseTest): create mirror: repo with Release + Release.gpg verification """ configOverride = {"max-tries": 1} - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror11 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror11 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" fixtureGpg = True def outputMatchPrepare(self, s): @@ -142,7 +143,7 @@ class CreateMirror12Test(BaseTest): create mirror: repo with Release+Release.gpg verification, failure """ configOverride = {"max-tries": 1} - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror12 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror12 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" fixtureGpg = False gold_processor = BaseTest.expand_environ expectedCode = 1 @@ -155,7 +156,7 @@ class CreateMirror13Test(BaseTest): """ create mirror: skip verification using config file """ - runCmd = "aptly mirror create mirror13 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create mirror13 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" configOverride = {"gpgDisableVerify": True} def check(self): @@ -167,7 +168,7 @@ class CreateMirror14Test(BaseTest): """ create mirror: flat repository """ - runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror14 https://cloud.r-project.org/bin/linux/debian jessie-cran35/" + runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror14 http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/" fixtureGpg = True def outputMatchPrepare(self, s): @@ -186,7 +187,7 @@ class CreateMirror15Test(BaseTest): """ create mirror: flat repository + components """ - runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror14 https://cloud.r-project.org/bin/linux/debian jessie-cran35/ main" + runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror14 http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/ main" expectedCode = 1 @@ -196,14 +197,14 @@ class CreateMirror16Test(BaseTest): """ expectedCode = 1 - runCmd = "aptly -architectures=source mirror create -ignore-signatures mirror16 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly -architectures=source mirror create -ignore-signatures mirror16 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" class CreateMirror17Test(BaseTest): """ create mirror: mirror with sources enabled """ - runCmd = "aptly -architectures=i386 mirror create -ignore-signatures -with-sources mirror17 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly -architectures=i386 mirror create -ignore-signatures -with-sources mirror17 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" def check(self): self.check_output() @@ -221,7 +222,11 @@ class CreateMirror18Test(BaseTest): "ppaCodename": "maverick", } - runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror18 ppa:gladky-anton/gnuplot" + fixtureCmds = [ + "gpg --no-default-keyring --keyring=ppa.gpg --keyserver=hkp://keyserver.ubuntu.com:80 --recv-keys 5BFCD481D86D5824470E469F9000B1C3A01F726C 02219381E9161C78A46CB2BFA5279A973B1F56C0", + f"chmod 400 {os.path.join(os.environ['HOME'], '.gnupg/ppa.gpg')}" + ] + runCmd = "aptly mirror create -keyring=ppa.gpg mirror18 ppa:gladky-anton/gnuplot" def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using', '', s) @@ -237,7 +242,7 @@ class CreateMirror19Test(BaseTest): """ fixtureGpg = True - runCmd = "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources mirror19 http://security.debian.org/ stretch/updates main" + runCmd = "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources mirror19 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using', '', s) @@ -258,7 +263,7 @@ class CreateMirror20Test(BaseTest): fixtureGpg = True configOverride = {"max-tries": 1} - runCmd = "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources mirror20 http://security.debian.org/ stretch/updates main" + runCmd = "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources mirror20 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" environmentOverride = {"HTTP_PROXY": "127.0.0.1:3137"} expectedCode = 1 @@ -270,8 +275,8 @@ class CreateMirror20Test(BaseTest): ).replace( 'proxyconnect tcp', 'http: error connecting to proxy http://127.0.0.1:3137' ).replace( - 'Get http://security.debian.org/dists/stretch/updates/Release:', - 'Get "http://security.debian.org/dists/stretch/updates/Release":' + 'Get http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release:', + 'Get "http://repo.aptly.info/system-tests/archive.debian.org/debian-security/dists/stretch/updates/Release":' ) @@ -280,7 +285,7 @@ class CreateMirror21Test(BaseTest): create mirror: flat repository in subdir """ configOverride = {"max-tries": 1} - runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror21 http://pkg.jenkins-ci.org/debian-stable binary/" + runCmd = "aptly mirror create -keyring=aptlytest.gpg mirror21 http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable binary/" fixtureGpg = True def outputMatchPrepare(self, s): @@ -302,7 +307,7 @@ class CreateMirror22Test(BaseTest): """ create mirror: mirror with filter """ - runCmd = "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' mirror22 http://security.debian.org/ stretch/updates main" + runCmd = "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' mirror22 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" def check(self): def removeDates(s): @@ -317,7 +322,7 @@ class CreateMirror23Test(BaseTest): """ create mirror: mirror with wrong filter """ - runCmd = "aptly mirror create -ignore-signatures -filter='nginx | ' mirror23 http://security.debian.org/ stretch/updates main" + runCmd = "aptly mirror create -ignore-signatures -filter='nginx | ' mirror23 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" expectedCode = 1 @@ -325,7 +330,7 @@ class CreateMirror24Test(BaseTest): """ create mirror: disable config value with option """ - runCmd = "aptly mirror create -ignore-signatures=false -keyring=aptlytest.gpg mirror24 http://security.debian.org/ stretch/updates main" + runCmd = "aptly mirror create -ignore-signatures=false -keyring=aptlytest.gpg mirror24 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" fixtureGpg = True def outputMatchPrepare(self, s): @@ -340,7 +345,7 @@ class CreateMirror25Test(BaseTest): """ create mirror: mirror with udebs enabled """ - runCmd = "aptly -architectures=i386 mirror create -ignore-signatures -with-udebs mirror25 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly -architectures=i386 mirror create -ignore-signatures -with-udebs mirror25 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" def check(self): self.check_output() @@ -351,7 +356,7 @@ class CreateMirror26Test(BaseTest): """ create mirror: flat mirror with udebs """ - runCmd = "aptly mirror create -keyring=aptlytest.gpg -with-udebs mirror26 http://pkg.jenkins-ci.org/debian-stable binary/" + runCmd = "aptly mirror create -keyring=aptlytest.gpg -with-udebs mirror26 http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable binary/" fixtureGpg = True expectedCode = 1 @@ -360,7 +365,7 @@ class CreateMirror27Test(BaseTest): """ create mirror: component with slashes, no stripping """ - runCmd = "aptly mirror create --ignore-signatures mirror27 https://mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu wheezy openmanage/740" + runCmd = "aptly mirror create --ignore-signatures mirror27 http://repo.aptly.info/system-tests/mirror.chpc.utah.edu/pub/linux.dell.com/repo/community/ubuntu wheezy openmanage/740" def outputMatchPrepare(self, s): return self.strip_retry_lines(s) @@ -374,19 +379,24 @@ class CreateMirror29Test(BaseTest): """ create mirror: repo with InRelease verification (internal GPG implementation) """ - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror9 http://cdn-fastly.deb.debian.org/debian/ stretch-backports" + fixtureCmds = ["gpg --no-default-keyring --keyring aptlytest.gpg --export-options export-minimal --export -o " + os.path.join( + os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")] + runCmd = "aptly mirror create --keyring=aptlytest-gpg1.gpg mirror9 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch-backports" configOverride = {"gpgProvider": "internal"} fixtureGpg = True def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using', '', s) + def teardown(self): + self.run_cmd(["rm", "-f", os.path.join(os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")]) + class CreateMirror30Test(BaseTest): """ create mirror: repo with InRelease verification, failure (internal GPG implementation) """ - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror10 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror10 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" configOverride = {"gpgProvider": "internal", "max-tries": 1} gold_processor = BaseTest.expand_environ fixtureGpg = False @@ -400,20 +410,25 @@ class CreateMirror31Test(BaseTest): """ create mirror: repo with Release + Release.gpg verification (internal GPG implementation) """ - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror11 http://cdn-fastly.deb.debian.org/debian/ stretch" + fixtureCmds = ["gpg --no-default-keyring --keyring aptlytest.gpg --export-options export-minimal --export -o " + os.path.join( + os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")] + runCmd = "aptly mirror create --keyring=aptlytest-gpg1.gpg mirror11 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" configOverride = {"gpgProvider": "internal", "max-tries": 1} fixtureGpg = True def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using', '', s) + def teardown(self): + self.run_cmd(["rm", "-f", os.path.join(os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")]) + class CreateMirror32Test(BaseTest): """ create mirror: repo with Release + Release.gpg verification (gpg2) """ configOverride = {"max-tries": 1} - runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror32 http://cdn-fastly.deb.debian.org/debian/ stretch" + runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror32 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch" fixtureGpg = True requiresGPG2 = True @@ -425,3 +440,17 @@ class CreateMirror32Test(BaseTest): def check(self): self.check_output() self.check_cmd_output("aptly mirror show mirror32", "mirror_show") + + +class CreateMirror33Test(BaseTest): + """ + create mirror: repo with only InRelease file but no verification + """ + configOverride = {"max-tries": 1} + runCmd = "aptly mirror create -ignore-signatures mirror33 http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64 ./" + fixtureGpg = False + requiresGPG2 = False + + def check(self): + self.check_output() + self.check_cmd_output("aptly mirror show mirror33", "mirror_show") diff --git a/system/t04_mirror/drop.py b/system/t04_mirror/drop.py index 36a16f6d..99248a82 100644 --- a/system/t04_mirror/drop.py +++ b/system/t04_mirror/drop.py @@ -6,7 +6,7 @@ class DropMirror1Test(BaseTest): drop mirror: regular list """ fixtureCmds = [ - "aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch", + "aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch", ] runCmd = "aptly mirror drop mirror1" diff --git a/system/t04_mirror/edit.py b/system/t04_mirror/edit.py index ad274a68..09a5b18f 100644 --- a/system/t04_mirror/edit.py +++ b/system/t04_mirror/edit.py @@ -1,4 +1,5 @@ import re + from lib import BaseTest @@ -48,7 +49,7 @@ class EditMirror5Test(BaseTest): edit mirror: remove filter """ fixtureCmds = [ - "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' mirror5 http://security.debian.org/ stretch/updates main", + "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' mirror5 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main", ] runCmd = "aptly mirror edit -filter= mirror5" @@ -65,7 +66,7 @@ class EditMirror6Test(BaseTest): edit mirror: change architectures """ fixtureCmds = [ - "aptly mirror create -ignore-signatures -architectures=amd64 mirror6 http://cdn-fastly.deb.debian.org/debian stretch main" + "aptly mirror create -ignore-signatures -architectures=amd64 mirror6 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main" ] runCmd = "aptly mirror edit -ignore-signatures -architectures=amd64,i386 mirror6" @@ -79,7 +80,7 @@ class EditMirror7Test(BaseTest): edit mirror: change architectures to missing archs """ fixtureCmds = [ - "aptly mirror create -ignore-signatures -architectures=amd64 stretch http://cdn-fastly.deb.debian.org/debian stretch main" + "aptly mirror create -ignore-signatures -architectures=amd64 stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main" ] runCmd = "aptly mirror edit -ignore-signatures -architectures=amd64,x56 stretch" expectedCode = 1 @@ -101,7 +102,7 @@ class EditMirror9Test(BaseTest): """ edit mirror: flat mirror with udebs """ - fixtureCmds = ["aptly mirror create -keyring=aptlytest.gpg mirror9 http://pkg.jenkins-ci.org/debian-stable binary/"] + fixtureCmds = ["aptly mirror create -keyring=aptlytest.gpg mirror9 http://repo.aptly.info/system-tests/pkg.jenkins.io/debian-stable binary/"] fixtureGpg = True runCmd = "aptly mirror edit -with-udebs mirror9" expectedCode = 1 @@ -111,6 +112,5 @@ class EditMirror10Test(BaseTest): """ edit mirror: change archive url """ - requiresFTP = True - fixtureCmds = ["aptly mirror create -ignore-signatures mirror10 ftp://ftp.ru.debian.org/debian stretch main"] - runCmd = "aptly mirror edit -ignore-signatures -archive-url ftp://ftp.ch.debian.org/debian mirror10" + fixtureCmds = ["aptly mirror create -ignore-signatures mirror10 http://repo.aptly.info/system-tests/ftp.ru.debian.org/debian bookworm main"] + runCmd = "aptly mirror edit -ignore-signatures -archive-url http://repo.aptly.info/system-tests/ftp.ch.debian.org/debian mirror10" diff --git a/system/t04_mirror/list.py b/system/t04_mirror/list.py index 7b02e288..2422b3c0 100644 --- a/system/t04_mirror/list.py +++ b/system/t04_mirror/list.py @@ -1,16 +1,17 @@ -from lib import BaseTest import re +from lib import BaseTest + class ListMirror1Test(BaseTest): """ list mirrors: regular list """ fixtureCmds = [ - "aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch", - "aptly mirror create -with-sources --ignore-signatures mirror2 http://cdn-fastly.deb.debian.org/debian/ stretch contrib", - "aptly -architectures=i386 mirror create --ignore-signatures mirror3 http://cdn-fastly.deb.debian.org/debian/ stretch non-free", - "aptly mirror create -ignore-signatures mirror4 http://download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./", + "aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch", + "aptly mirror create -with-sources --ignore-signatures mirror2 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch contrib", + "aptly -architectures=i386 mirror create --ignore-signatures mirror3 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch non-free", + "aptly mirror create -ignore-signatures mirror4 http://repo.aptly.info/system-tests/download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./", ] runCmd = "aptly mirror list" @@ -49,10 +50,10 @@ class ListMirror6Test(BaseTest): list mirrors: regular list """ fixtureCmds = [ - "aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch", - "aptly mirror create -with-sources --ignore-signatures mirror2 http://cdn-fastly.deb.debian.org/debian/ stretch contrib", - "aptly -architectures=i386 mirror create --ignore-signatures mirror3 http://cdn-fastly.deb.debian.org/debian/ stretch non-free", - "aptly mirror create -ignore-signatures mirror4 http://download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./", + "aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch", + "aptly mirror create -with-sources --ignore-signatures mirror2 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch contrib", + "aptly -architectures=i386 mirror create --ignore-signatures mirror3 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch non-free", + "aptly mirror create -ignore-signatures mirror4 http://repo.aptly.info/system-tests/download.opensuse.org/repositories/Apache:/MirrorBrain/Debian_9.0/ ./", ] runCmd = "aptly mirror list -json" diff --git a/system/t04_mirror/show.py b/system/t04_mirror/show.py index ce1d25d4..98e7cbb2 100644 --- a/system/t04_mirror/show.py +++ b/system/t04_mirror/show.py @@ -1,12 +1,13 @@ -from lib import BaseTest import re +from lib import BaseTest + class ShowMirror1Test(BaseTest): """ show mirror: regular mirror """ - fixtureCmds = ["aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch"] + fixtureCmds = ["aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch"] runCmd = "aptly mirror show mirror1" @@ -34,19 +35,19 @@ class ShowMirror4Test(BaseTest): show mirror: mirror with filter """ fixtureCmds = [ - "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' -filter-with-deps=true mirror4 http://security.debian.org/ stretch/updates main" + "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' -filter-with-deps=true mirror4 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" ] runCmd = "aptly mirror show mirror4" def outputMatchPrepare(self, s): - return re.sub(r"(Date|Valid-Until): [,0-9:+A-Za-z -]+\n", "", s) + return re.sub(r"(Date): [,0-9:+A-Za-z -]+\n", "", s) class ShowMirror5Test(BaseTest): """ show mirror: regular mirror """ - fixtureCmds = ["aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch"] + fixtureCmds = ["aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch"] runCmd = "aptly mirror show -json mirror1" def outputMatchPrepare(_, s): @@ -74,7 +75,7 @@ class ShowMirror8Test(BaseTest): show mirror: mirror with filter """ fixtureCmds = [ - "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' -filter-with-deps=true mirror4 http://security.debian.org/ stretch/updates main" + "aptly mirror create -ignore-signatures -filter='nginx | Priority (required)' -filter-with-deps=true mirror4 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" ] runCmd = "aptly mirror show -json mirror4" diff --git a/system/t04_mirror/update.py b/system/t04_mirror/update.py index 1e99d4b7..fb44dd7e 100644 --- a/system/t04_mirror/update.py +++ b/system/t04_mirror/update.py @@ -1,8 +1,9 @@ -import string -import re -import os -import shutil import inspect +import os +import re +import shutil +import string + from lib import BaseTest @@ -21,7 +22,7 @@ class UpdateMirror1Test(BaseTest): sortOutput = True longTest = False fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish https://packagecloud.io/varnishcache/varnish30/debian/ wheezy main", + "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/ wheezy main", ] runCmd = "aptly mirror update --ignore-signatures varnish" outputMatchPrepare = filterOutRedirects @@ -114,7 +115,7 @@ class UpdateMirror7Test(BaseTest): sortOutput = True fixtureGpg = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg -architectures=amd64 flat https://cloud.r-project.org/bin/linux/debian jessie-cran35/", + "aptly mirror create --keyring=aptlytest.gpg -architectures=amd64 flat http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/", ] runCmd = "aptly mirror update --keyring=aptlytest.gpg flat" outputMatchPrepare = filterOutSignature @@ -129,7 +130,7 @@ class UpdateMirror8Test(BaseTest): fixtureGpg = True fixturePool = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg gnuplot-maverick-src http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick", + "aptly mirror create --keyring=aptlytest.gpg gnuplot-maverick-src http://repo.aptly.info/system-tests/ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick", ] runCmd = "aptly mirror update --keyring=aptlytest.gpg gnuplot-maverick-src" outputMatchPrepare = filterOutSignature @@ -142,7 +143,7 @@ class UpdateMirror9Test(BaseTest): sortOutput = True fixtureGpg = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg -with-sources flat-src https://cloud.r-project.org/bin/linux/debian jessie-cran35/", + "aptly mirror create --keyring=aptlytest.gpg -with-sources flat-src http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/", ] runCmd = "aptly mirror update --keyring=aptlytest.gpg flat-src" outputMatchPrepare = filterOutSignature @@ -155,13 +156,13 @@ class UpdateMirror10Test(BaseTest): sortOutput = True fixtureGpg = True fixtureCmds = [ - "aptly mirror create -keyring=aptlytest.gpg -with-sources -filter='!(Name (% r-*)), !($$PackageType (source))' flat-src https://cloud.r-project.org/bin/linux/debian jessie-cran35/", + "aptly mirror create -keyring=aptlytest.gpg -with-sources -filter='!(Name (% r-*)), !($$PackageType (source))' flat-src http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/", ] runCmd = "aptly mirror update --keyring=aptlytest.gpg flat-src" outputMatchPrepare = filterOutSignature -class UpdateMirror11Test(BaseTest): +class UpdateMirror11FTPTest(BaseTest): """ update mirrors: update over FTP """ @@ -172,7 +173,7 @@ class UpdateMirror11Test(BaseTest): requiresFTP = True fixtureCmds = [ "aptly mirror create -keyring=aptlytest.gpg -filter='Priority (required), Name (% s*)' " - "-architectures=i386 stretch-main https://snapshot.debian.org/archive/debian/20220201T025006Z/ stretch main", + "-architectures=i386 stretch-main http://repo.aptly.info/system-tests/snapshot.debian.org/archive/debian/20220201T025006Z/ stretch main", ] outputMatchPrepare = filterOutSignature runCmd = "aptly mirror update -keyring=aptlytest.gpg stretch-main" @@ -187,7 +188,7 @@ class UpdateMirror12Test(BaseTest): longTest = False fixtureGpg = True fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://cdn-fastly.deb.debian.org/debian/ stretch main non-free", + "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main non-free", ] runCmd = "aptly mirror update -keyring=aptlytest.gpg stretch" outputMatchPrepare = filterOutSignature @@ -200,7 +201,7 @@ class UpdateMirror13Test(BaseTest): sortOutput = True longTest = False fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish https://packagecloud.io/varnishcache/varnish30/debian/ wheezy main", + "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/ wheezy main", ] runCmd = "aptly mirror update --ignore-signatures --skip-existing-packages varnish" outputMatchPrepare = filterOutRedirects @@ -213,7 +214,7 @@ class UpdateMirror14Test(BaseTest): sortOutput = True longTest = False fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish https://packagecloud.io/varnishcache/varnish30/debian/ wheezy main", + "aptly -architectures=i386,amd64 mirror create --ignore-signatures varnish http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/ wheezy main", "aptly mirror update --ignore-signatures --skip-existing-packages varnish" ] runCmd = "aptly mirror update --ignore-signatures --skip-existing-packages varnish" @@ -281,7 +282,7 @@ class UpdateMirror17Test(BaseTest): sortOutput = True longTest = False fixtureCmds = [ - "aptly mirror create -ignore-signatures -architectures=i386 -filter=libboost-program-options-dev stretch http://cdn-fastly.deb.debian.org/debian stretch main", + "aptly mirror create -ignore-signatures -architectures=i386 -filter=libboost-program-options-dev stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main", ] runCmd = "aptly mirror update -ignore-signatures stretch" @@ -308,7 +309,7 @@ class UpdateMirror18Test(BaseTest): sortOutput = True longTest = False fixtureCmds = [ - "aptly mirror create -ignore-signatures -architectures=i386 -filter=libboost-program-options-dev stretch http://cdn-fastly.deb.debian.org/debian stretch main", + "aptly mirror create -ignore-signatures -architectures=i386 -filter=libboost-program-options-dev stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main", ] runCmd = "aptly mirror update -ignore-signatures stretch" configOverride = {'skipLegacyPool': True} @@ -337,7 +338,7 @@ class UpdateMirror19Test(BaseTest): longTest = False fixtureGpg = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg pagerduty https://packages.pagerduty.com/pdagent deb/" + "aptly mirror create --keyring=aptlytest.gpg pagerduty http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent deb/" ] runCmd = "aptly mirror update --keyring=aptlytest.gpg pagerduty" outputMatchPrepare = filterOutSignature @@ -352,13 +353,18 @@ class UpdateMirror20Test(BaseTest): """ sortOutput = True fixtureGpg = True - fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg -architectures=amd64 --filter='r-cran-class' flat https://cloud.r-project.org/bin/linux/debian jessie-cran35/", - ] configOverride = {"gpgProvider": "internal"} - runCmd = "aptly mirror update --keyring=aptlytest.gpg flat" + fixtureCmds = [ + "gpg --no-default-keyring --keyring aptlytest.gpg --export -o " + os.path.join( + os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg"), + "aptly mirror create --keyring=aptlytest-gpg1.gpg -architectures=amd64 --filter='r-cran-class' flat http://repo.aptly.info/system-tests/cloud.r-project.org/bin/linux/debian bullseye-cran40/", + ] + runCmd = "aptly mirror update --keyring=aptlytest-gpg1.gpg flat" outputMatchPrepare = filterOutSignature + def teardown(self): + self.run_cmd(["rm", "-f", os.path.join(os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")]) + class UpdateMirror21Test(BaseTest): """ @@ -368,14 +374,19 @@ class UpdateMirror21Test(BaseTest): configOverride = {"gpgProvider": "internal", "max-tries": 1} fixtureGpg = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg pagerduty https://packages.pagerduty.com/pdagent deb/" + "gpg --no-default-keyring --keyring aptlytest.gpg --export -o " + os.path.join( + os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg"), + "aptly mirror create --keyring=aptlytest-gpg1.gpg pagerduty http://repo.aptly.info/system-tests/packages.pagerduty.com/pdagent deb/" ] - runCmd = "aptly mirror update --keyring=aptlytest.gpg pagerduty" + runCmd = "aptly mirror update --keyring=aptlytest-gpg1.gpg pagerduty" outputMatchPrepare = filterOutSignature def output_processor(self, output): return "\n".join(line for line in self.ensure_utf8(output).split("\n") if ".deb" not in line) + def teardown(self): + self.run_cmd(["rm", "-f", os.path.join(os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")]) + class UpdateMirror22Test(BaseTest): """ @@ -384,13 +395,18 @@ class UpdateMirror22Test(BaseTest): configOverride = {"gpgProvider": "internal"} fixtureGpg = True fixtureCmds = [ - "aptly mirror create --keyring=aptlytest.gpg --filter=nomatch libnvidia-container https://nvidia.github.io/libnvidia-container/ubuntu16.04/amd64 ./" + "gpg --no-default-keyring --keyring aptlytest.gpg --export -o " + os.path.join( + os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg"), + "aptly mirror create --keyring=aptlytest-gpg1.gpg --filter=nomatch libnvidia-container http://repo.aptly.info/system-tests/nvidia.github.io/libnvidia-container/stable/ubuntu16.04/amd64 ./" ] - runCmd = "aptly mirror update --keyring=aptlytest.gpg libnvidia-container" + runCmd = "aptly mirror update --keyring=aptlytest-gpg1.gpg libnvidia-container" def outputMatchPrepare(self, s): return re.sub(r'Signature made .* using|Packages filtered: .* -> 0.', '', s) + def teardown(self): + self.run_cmd(["rm", "-f", os.path.join(os.environ["HOME"], ".gnupg/aptlytest-gpg1.gpg")]) + class UpdateMirror23Test(BaseTest): """ @@ -401,7 +417,7 @@ class UpdateMirror23Test(BaseTest): longTest = False fixtureGpg = True fixtureCmds = [ - "aptly -architectures=s390x mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer stretch http://cdn-fastly.deb.debian.org/debian/ stretch main non-free", + "aptly -architectures=s390x mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main non-free", ] runCmd = "aptly mirror update -keyring=aptlytest.gpg stretch" outputMatchPrepare = filterOutSignature @@ -416,7 +432,53 @@ class UpdateMirror24Test(BaseTest): longTest = False fixtureGpg = True fixtureCmds = [ - "aptly -architectures=amd64 mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer trusty http://us.archive.ubuntu.com/ubuntu/ trusty main restricted", + "aptly -architectures=amd64 mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer trusty http://repo.aptly.info/system-tests/us.archive.ubuntu.com/ubuntu/ trusty main restricted", ] runCmd = "aptly mirror update -keyring=aptlytest.gpg trusty" outputMatchPrepare = filterOutSignature + + +class UpdateMirror25Test(BaseTest): + """ + update mirrors: mirror with / in distribution + """ + configOverride = {"max-tries": 1} + sortOutput = True + longTest = False + fixtureGpg = True + fixtureCmds = [ + "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources mirror19 http://repo.aptly.info/system-tests/archive.debian.org/debian-security/ stretch/updates main" + ] + runCmd = "aptly mirror update -keyring=aptlytest.gpg mirror19" + outputMatchPrepare = filterOutSignature + + +class UpdateMirror26Test(BaseTest): + """ + update mirrors: regular update, grab downloader + """ + configOverride = {"downloader": "grab"} + sortOutput = True + longTest = False + fixtureGpg = True + fixtureCmds = [ + "aptly mirror create -architectures=i386 -keyring=aptlytest.gpg -filter=libboost-program-options-dev grab http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main", + ] + runCmd = "aptly mirror update -downloader=grab -keyring=aptlytest.gpg grab" + outputMatchPrepare = filterOutRedirects + + +class UpdateMirror27Test(BaseTest): + """ + update mirrors: failing update, grab downloader + """ + configOverride = {"downloader": "grab"} + sortOutput = True + longTest = False + fixtureGpg = True + fixtureCmds = [ + "aptly mirror create -architectures=amd64,i386 -keyring=aptlytest.gpg -filter=libboost-program-options-dev grab-fail http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian stretch main", + ] + runCmd = "aptly mirror update -downloader=grab -keyring=aptlytest.gpg grab-fail" + outputMatchPrepare = filterOutRedirects + expectedCode = 1 diff --git a/system/t05_snapshot/VerifySnapshot4Test_gold b/system/t05_snapshot/VerifySnapshot4Test_gold index 1d6c02ce..3d5499ab 100644 --- a/system/t05_snapshot/VerifySnapshot4Test_gold +++ b/system/t05_snapshot/VerifySnapshot4Test_gold @@ -1,6 +1,6 @@ Loading packages... Verifying... -Missing dependencies (1737): +Missing dependencies (1741): 915resolution [i386] 9fonts [i386] abakus [i386] @@ -74,6 +74,7 @@ Missing dependencies (1737): big-blast [i386] bigdft [i386] bigsdb [i386] + bind [i386] bioclipse [i386] bioimagesuite [i386] bioimagexd [i386] @@ -204,6 +205,7 @@ Missing dependencies (1737): elmer-doc [i386] elph [i386] emacs-wiki [i386] + emacs22 [i386] emacs23-common-non-dfsg [i386] emacspeak-ss [i386] embassy [i386] @@ -574,6 +576,7 @@ Missing dependencies (1737): kbackgammon [i386] kbdcontrol [i386] kchart [i386] + kde [i386] kde-icons-crystal [i386] kde-icons-oxygen [i386] kde-l10n (>= 4:4.8.4) [i386] @@ -688,7 +691,6 @@ Missing dependencies (1737): libdeal.ii-dev [i386] libdigest-cmac-perl [i386] libdrmaa1.0 [i386] - libdspam7-drv (= 3.10.1+dfsg-11) [i386] libdvdcss [i386] libdvdcss-dev [i386] libdvdcss2 [i386] @@ -1641,6 +1643,7 @@ Missing dependencies (1737): ttf-larabie-deco [i386] ttf-larabie-straight [i386] ttf-mscorefonts-installer [i386] + ttf-thryomanes [i386] ttf-ubuntu-font-family (>= 0.80-0ubuntu1~medium) [i386] ttf2pt1 [i386] tuxpaint (= 1:0.9.21) [i386] @@ -1722,6 +1725,7 @@ Missing dependencies (1737): xmind [i386] xnat [i386] xorsa [i386] + xpdf-reader [i386] xsidplay [i386] xtranslate [i386] xul-ext-gnome-keyring [i386] diff --git a/system/t05_snapshot/VerifySnapshot5Test_gold b/system/t05_snapshot/VerifySnapshot5Test_gold index 39e0af1c..9f14d4f5 100644 --- a/system/t05_snapshot/VerifySnapshot5Test_gold +++ b/system/t05_snapshot/VerifySnapshot5Test_gold @@ -1,6 +1,6 @@ Loading packages... Verifying... -Missing dependencies (1617): +Missing dependencies (1621): 915resolution [i386] 9fonts [i386] abakus [i386] @@ -71,6 +71,7 @@ Missing dependencies (1617): big-blast [i386] bigdft [i386] bigsdb [i386] + bind [i386] bioclipse [i386] bioimagesuite [i386] bioimagexd [i386] @@ -187,6 +188,7 @@ Missing dependencies (1617): elexis [i386] elph [i386] emacs-wiki [i386] + emacs22 [i386] emacspeak-ss [i386] embassy [i386] embassy-phylip [i386] @@ -513,6 +515,7 @@ Missing dependencies (1617): kbackgammon [i386] kbdcontrol [i386] kchart [i386] + kde [i386] kde-icons-crystal [i386] kde-icons-oxygen [i386] kde-l10n (>= 4:4.8.4) [i386] @@ -624,7 +627,6 @@ Missing dependencies (1617): libdeal.ii-dev [i386] libdigest-cmac-perl [i386] libdrmaa1.0 [i386] - libdspam7-drv (= 3.10.1+dfsg-11) [i386] libdvdcss [i386] libdvdcss-dev [i386] libdvdcss2 [i386] @@ -1532,6 +1534,7 @@ Missing dependencies (1617): tripal [i386] trnascan-se [i386] tscope [i386] + ttf-thryomanes [i386] ttf-ubuntu-font-family (>= 0.80-0ubuntu1~medium) [i386] ttf2pt1 [i386] tuxpaint (= 1:0.9.21) [i386] @@ -1603,6 +1606,7 @@ Missing dependencies (1617): xmind [i386] xnat [i386] xorsa [i386] + xpdf-reader [i386] xsidplay [i386] xtranslate [i386] xul-ext-gnome-keyring [i386] diff --git a/system/t05_snapshot/VerifySnapshot6Test_gold b/system/t05_snapshot/VerifySnapshot6Test_gold index f4083476..b8574e7d 100644 --- a/system/t05_snapshot/VerifySnapshot6Test_gold +++ b/system/t05_snapshot/VerifySnapshot6Test_gold @@ -1,6 +1,6 @@ Loading packages... Verifying... -Missing dependencies (3781): +Missing dependencies (3787): 915resolution [amd64] 915resolution [i386] 9fonts [amd64] @@ -51,6 +51,8 @@ Missing dependencies (3781): angband-audio [i386] aolserver-doc (>= 4.0.1-1) [amd64] aolserver-doc (>= 4.0.1-1) [i386] + apache [amd64] + apache [i386] apache-ssl [amd64] apache-ssl [i386] ape [amd64] @@ -159,6 +161,8 @@ Missing dependencies (3781): bigdft [i386] bigsdb [amd64] bigsdb [i386] + bind [amd64] + bind [i386] bioclipse [amd64] bioclipse [i386] bioimagesuite [amd64] @@ -454,6 +458,8 @@ Missing dependencies (3781): elph [i386] emacs-wiki [amd64] emacs-wiki [i386] + emacs22 [amd64] + emacs22 [i386] emacs23-common-non-dfsg [amd64] emacs23-common-non-dfsg [i386] emacspeak-ss [amd64] @@ -1207,8 +1213,6 @@ Missing dependencies (3781): jabber [i386] jamnntpd [amd64] jamnntpd [i386] - java-gcj-compat (>= 1.0.69) [amd64] - java-gcj-compat (>= 1.0.69) [i386] jbibtex [amd64] jbibtex [i386] jbibtex-bin [amd64] @@ -1258,6 +1262,8 @@ Missing dependencies (3781): kbdcontrol [i386] kchart [amd64] kchart [i386] + kde [amd64] + kde [i386] kde-i18n-he [amd64] kde-i18n-he [i386] kde-icons-crystal [amd64] @@ -1518,8 +1524,6 @@ Missing dependencies (3781): libdigest-cmac-perl [i386] libdrmaa1.0 [amd64] libdrmaa1.0 [i386] - libdspam7-drv (= 3.10.1+dfsg-11) [amd64] - libdspam7-drv (= 3.10.1+dfsg-11) [i386] libdvdcss [amd64] libdvdcss [i386] libdvdcss-dev [amd64] @@ -1598,8 +1602,6 @@ Missing dependencies (3781): libint [i386] libjai-imageio-core-java [amd64] libjai-imageio-core-java [i386] - libjakarta-poi-java (>= 3.2) [amd64] - libjakarta-poi-java (>= 3.2) [i386] libjavascript-perl [amd64] libjavascript-perl [i386] libjdom-java [amd64] @@ -2184,6 +2186,8 @@ Missing dependencies (3781): mesquite [i386] metadisorder [amd64] metadisorder [i386] + metamail [amd64] + metamail [i386] metarep [amd64] metarep [i386] mga-vid-module [amd64] @@ -2301,8 +2305,6 @@ Missing dependencies (3781): mummergpu [i386] murasaki [amd64] murasaki [i386] - musixlyr (>= 1.10-4) [amd64] - musixlyr (>= 1.10-4) [i386] musmap [amd64] musmap [i386] mview [amd64] @@ -2948,8 +2950,6 @@ Missing dependencies (3781): python-celementtree [i386] python-clips [amd64] python-clips [i386] - python-ctypes (>= 1.0.1) [amd64] - python-ctypes (>= 1.0.1) [i386] python-dev-all (>= 2.6) [amd64] python-dev-all (>= 2.6) [i386] python-elemental [amd64] @@ -3498,6 +3498,8 @@ Missing dependencies (3781): tc-utils [i386] tempo [amd64] tempo [i386] + tetex-bin [amd64] + tetex-bin [i386] tetra [amd64] tetra [i386] texinfo-doc-nonfree [amd64] @@ -3578,6 +3580,8 @@ Missing dependencies (3781): ttf-larabie-straight [i386] ttf-mscorefonts-installer [amd64] ttf-mscorefonts-installer [i386] + ttf-thryomanes [amd64] + ttf-thryomanes [i386] ttf-ubuntu-font-family (>= 0.80-0ubuntu1~medium) [amd64] ttf-ubuntu-font-family (>= 0.80-0ubuntu1~medium) [i386] ttf2pt1 [amd64] @@ -3746,6 +3750,8 @@ Missing dependencies (3781): xnat [i386] xorsa [amd64] xorsa [i386] + xpdf-reader [amd64] + xpdf-reader [i386] xsidplay [amd64] xsidplay [i386] xtranslate [amd64] diff --git a/system/t05_snapshot/VerifySnapshot7Test_gold b/system/t05_snapshot/VerifySnapshot7Test_gold index b5df842d..85e3ce21 100644 --- a/system/t05_snapshot/VerifySnapshot7Test_gold +++ b/system/t05_snapshot/VerifySnapshot7Test_gold @@ -1,6 +1,6 @@ Loading packages... Verifying... -Missing dependencies (677): +Missing dependencies (625): abrowser [amd64] abrowser [i386] apache [amd64] @@ -96,8 +96,6 @@ Missing dependencies (677): firefox [i386] freebsd-net-tools [amd64] freebsd-net-tools [i386] - fvwm-gnome (>= 1:2.5.13) [amd64] - fvwm-gnome (>= 1:2.5.13) [i386] gcc-mingw-w64 (<< 4.6.3-3+4) [amd64] gcc-mingw-w64 (<< 4.6.3-3+4) [i386] gdm [amd64] @@ -108,8 +106,6 @@ Missing dependencies (677): ghostcript-x (= 9.05~dfsg-6.3+deb7u1) [i386] gij [amd64] gij [i386] - git-core (<= 1:1.7.0.4-1) [amd64] - git-core (<= 1:1.7.0.4-1) [i386] gkrellm2 [amd64] gkrellm2 [i386] gnome-themes-more [amd64] @@ -118,8 +114,6 @@ Missing dependencies (677): gnus [i386] graphicsmagick-im-compat [amd64] graphicsmagick-im-compat [i386] - grep-dctrl (>= 0.11) [amd64] - grep-dctrl (>= 0.11) [i386] gstreamer0.10-plugins-good (<= 0.10.28-2) [amd64] gstreamer0.10-plugins-good (<= 0.10.28-2) [i386] gstreamer0.10-videomixer2 [amd64] @@ -168,8 +162,6 @@ Missing dependencies (677): isdnutils [i386] java-6-runtime [amd64] java-6-runtime [i386] - java-gcj-compat (>= 1.0.77-4) [amd64] - java-gcj-compat (>= 1.0.77-4) [i386] java7-sdk [amd64] java7-sdk [i386] joystick (<< 20051019-6) [amd64] @@ -298,18 +290,8 @@ Missing dependencies (677): libdc1394-dev [i386] libdvdplay0 [amd64] libdvdplay0 [i386] - libemail-mime-creator-perl (>= 1.453) [amd64] - libemail-mime-creator-perl (>= 1.453) [i386] - libemail-mime-modifier-perl (>= 1.441) [amd64] - libemail-mime-modifier-perl (>= 1.441) [i386] libesd-alsa0 (>= 0.2.35) [amd64] libesd-alsa0 (>= 0.2.35) [i386] - libextutils-install-perl (>= 1.52) [amd64] - libextutils-install-perl (>= 1.52) [i386] - libfile-path-perl (>= 2.06) [amd64] - libfile-path-perl (>= 2.06) [i386] - libfile-temp-perl (>= 0.19) [amd64] - libfile-temp-perl (>= 0.19) [i386] libgd-noxpm-perl [amd64] libgd-noxpm-perl [i386] libgd2-dev [amd64] @@ -320,38 +302,20 @@ Missing dependencies (677): libgnomeprint-data [i386] libgtk2.0-dev (<< 2.21) [amd64] libgtk2.0-dev (<< 2.21) [i386] - libhaml-ruby (<< 3.1) [amd64] - libhaml-ruby (<< 3.1) [i386] libicu36-dev [amd64] libicu36-dev [i386] - libio-compress-bzip2-perl (>= 2.008) [amd64] - libio-compress-bzip2-perl (>= 2.008) [i386] - libio-compress-zlib-perl (>= 2.011) [amd64] - libio-compress-zlib-perl (>= 2.011) [i386] - libio-zlib-perl (>= 1.04) [amd64] - libio-zlib-perl (>= 1.04) [i386] libjasper-1.701-dev [amd64] libjasper-1.701-dev [i386] libjibx-java (<< 1.2) [amd64] libjibx-java (<< 1.2) [i386] - liblocale-maketext-simple-perl (>= 0.19) [amd64] - liblocale-maketext-simple-perl (>= 0.19) [i386] libmaildir4 (= 4:4.4.11.1+l10n-3+b1) [amd64] libmaildir4 (= 4:4.4.11.1+l10n-3+b1) [i386] - libmime-perl (>= 5.108) [amd64] - libmime-perl (>= 5.108) [i386] libmodule-metatadata-perl [amd64] libmodule-metatadata-perl [i386] - libmodule-pluggable-perl (>= 3.9) [amd64] - libmodule-pluggable-perl (>= 3.9) [i386] libmotif-dev [amd64] libmotif-dev [i386] - libnet-perl (>= 1.12) [amd64] - libnet-perl (>= 1.12) [i386] libparent (>= 0.223) [amd64] libparent (>= 0.223) [i386] - libparent-perl (>= 0.221) [amd64] - libparent-perl (>= 0.221) [i386] libpng2-dev [amd64] libpng2-dev [i386] libreadline5-dev [amd64] @@ -364,8 +328,6 @@ Missing dependencies (677): libsvn-core-perl [i386] libswt-mozilla-gtk-3-jni [amd64] libswt-mozilla-gtk-3-jni [i386] - libtest-harness-perl (= 3.23-1) [amd64] - libtest-harness-perl (= 3.23-1) [i386] libwww-perl (<< 6) [amd64] libwww-perl (<< 6) [i386] libzephyr4-krb (= 3.0.2-2) [amd64] @@ -460,14 +422,8 @@ Missing dependencies (677): postgresql-client-8.3 [i386] puredata (<< 0.43) [amd64] puredata (<< 0.43) [i386] - pykickstart (>= 0.96) [amd64] - pykickstart (>= 0.96) [i386] python-celementtree [amd64] python-celementtree [i386] - python-codespeak-lib (<< 1.0) [amd64] - python-codespeak-lib (<< 1.0) [i386] - python-ctypes (>= 1.0.0) [amd64] - python-ctypes (>= 1.0.0) [i386] python-elementtree (>= 1.2) [amd64] python-elementtree (>= 1.2) [i386] python-elementtree [amd64] @@ -494,8 +450,6 @@ Missing dependencies (677): python-psycopg (<< 1.1.21) [i386] python-psycopg (>= 1.1.21-14) [amd64] python-psycopg (>= 1.1.21-14) [i386] - python-pynast (>= 1.1) [amd64] - python-pynast (>= 1.1) [i386] python-qt4 (<< 4.7.5) [amd64] python-qt4 (<< 4.7.5) [i386] python-sqlalchemy (<< 0.6.3-2) [amd64] @@ -562,8 +516,6 @@ Missing dependencies (677): urxvt [i386] vidcontrol [amd64] vidcontrol [i386] - w3m-el (>= 1.4.5) [amd64] - w3m-el (>= 1.4.5) [i386] w3m-ssl (>= 0.3) [amd64] w3m-ssl (>= 0.3) [i386] w3mmee (>= 0.3) [amd64] @@ -589,8 +541,6 @@ Missing dependencies (677): wine1.5 [amd64] wine1.5 [i386] wine64-bin (>= 1.4.1-4) [i386] - wish (>= 8.4) [amd64] - wish (>= 8.4) [i386] x-www-browser [amd64] x-www-browser [i386] xcontrib [i386] @@ -626,8 +576,6 @@ Missing dependencies (677): xmessage [i386] xpdf-reader (<< 3.02-2) [amd64] xpdf-reader (<< 3.02-2) [i386] - xpdf-utils (>= 3.02-2) [amd64] - xpdf-utils (>= 3.02-2) [i386] xrandr [amd64] xrandr [i386] xulrunner-1.9 [amd64] diff --git a/system/t05_snapshot/VerifySnapshot8Test_gold b/system/t05_snapshot/VerifySnapshot8Test_gold index 16c7c3a4..c00fe579 100644 --- a/system/t05_snapshot/VerifySnapshot8Test_gold +++ b/system/t05_snapshot/VerifySnapshot8Test_gold @@ -1,10 +1,9 @@ Loading packages... Verifying... -Missing dependencies (32): +Missing dependencies (31): dpkg (>= 1.15.4) [amd64] dpkg (>= 1.15.4) [i386] gnuplot (= 4.6.1-1~maverick2) [source] - gnuplot (= 4.6.1-1~maverick2) [source] install-info [amd64] install-info [i386] libc6 (>= 2.11) [amd64] diff --git a/system/t06_publish/AzurePublish1Test_binary b/system/t06_publish/AzurePublish1Test_binary new file mode 100644 index 00000000..1fd182e4 --- /dev/null +++ b/system/t06_publish/AzurePublish1Test_binary @@ -0,0 +1,27 @@ + + + (name, value) pairs from the user, via conventional methods such as + . + . + Boost version (currently 1.49). + Library to let program developers obtain program options, that is + This package forms part of the Boost C++ Libraries collection. + This package is a dependency package, which depends on Debian's default + command line and config file. +Architecture: i386 +Depends: libboost-program-options1.49-dev +Description: program options library for C++ (default version) +Filename: pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb +Homepage: http://www.boost.org/libs/program_options/ +Installed-Size: 26 +MD5sum: 0035d7822b2f8f0ec4013f270fd650c2 +Maintainer: Debian Boost Team +Package: libboost-program-options-dev +Priority: optional +SHA1: 36895eb64cfe89c33c0a2f7ac2f0c6e0e889e04b +SHA256: c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12 +SHA512: d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c +Section: libdevel +Size: 2738 +Source: boost-defaults +Version: 1.49.0.1 \ No newline at end of file diff --git a/system/t06_publish/AzurePublish1Test_gold b/system/t06_publish/AzurePublish1Test_gold new file mode 100644 index 00000000..b65701eb --- /dev/null +++ b/system/t06_publish/AzurePublish1Test_gold @@ -0,0 +1,13 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: + +Local repo local-repo has been successfully published. +Now you can add following line to apt sources: + deb http://your-server/ maverick main + deb-src http://your-server/ maverick main +Don't forget to add your GPG key to apt with apt-key. + +You can also use `aptly serve` to publish your repositories over HTTP quickly. diff --git a/system/t06_publish/AzurePublish1Test_release b/system/t06_publish/AzurePublish1Test_release new file mode 100644 index 00000000..78154c5b --- /dev/null +++ b/system/t06_publish/AzurePublish1Test_release @@ -0,0 +1,11 @@ +Origin: . maverick +Label: . maverick +Suite: maverick +Codename: maverick +Architectures: i386 +Components: main +Description: Generated by aptly +MD5Sum: +SHA1: +SHA256: +SHA512: diff --git a/system/t06_publish/AzurePublish1Test_sources b/system/t06_publish/AzurePublish1Test_sources new file mode 100644 index 00000000..f561df83 --- /dev/null +++ b/system/t06_publish/AzurePublish1Test_sources @@ -0,0 +1,57 @@ + + + + 22ff26db69b73d3438fdde21ab5ba2f1 3456 pyspi_0.6.1-1.3.diff.gz + 22ff26db69b73d3438fdde21ab5ba2f1 3456 pyspi_0.6.1-1.3.diff.gz + 262cac59a2e81c7f110851ff9670c97ffc3d192d9937b880422a0907f26340d43e7de7e68b904a4fb10bedb02b65c3bd1f7bdd20ea8c4293e690e7a8e0e70ee5 893 pyspi-0.6.1-1.3.stripped.dsc + 289d3aefa970876e9c43686ce2b02f478d7f3ed35a713928464a98d54ae4fca3 893 pyspi-0.6.1-1.3.stripped.dsc + 2e770b28df948f3197ed0b679bdea99f3f2bf745e9ddb440c677df9c3aeaee3c 3456 pyspi_0.6.1-1.3.diff.gz + 2e770b28df948f3197ed0b679bdea99f3f2bf745e9ddb440c677df9c3aeaee3c 3456 pyspi_0.6.1-1.3.diff.gz + 2f5bd47cf38852b6fc927a50f98c1448 893 pyspi-0.6.1-1.3.stripped.dsc + 384b5e94b4113262e41bda1a2563f4f439cb8c97f43e2caefe16d7626718c21b36d3145b915eed24053eaa7fe3b6186494a87a3fcf9627f6e653b54bb3caa897 3456 pyspi_0.6.1-1.3.diff.gz + 384b5e94b4113262e41bda1a2563f4f439cb8c97f43e2caefe16d7626718c21b36d3145b915eed24053eaa7fe3b6186494a87a3fcf9627f6e653b54bb3caa897 3456 pyspi_0.6.1-1.3.diff.gz + 5005fbd1f30637edc1d380b30f45db9b79100d07 893 pyspi-0.6.1-1.3.stripped.dsc + 56c8a9b1f4ab636052be8966690998cbe865cd6c 1782 pyspi_0.6.1-1.3.dsc + 64069ee828c50b1c597d10a3fefbba279f093a4723965388cdd0ac02f029bfb9 29063 pyspi_0.6.1.orig.tar.gz + 64069ee828c50b1c597d10a3fefbba279f093a4723965388cdd0ac02f029bfb9 29063 pyspi_0.6.1.orig.tar.gz + 95a2468e4bbce730ba286f2211fa41861b9f1d90 3456 pyspi_0.6.1-1.3.diff.gz + 95a2468e4bbce730ba286f2211fa41861b9f1d90 3456 pyspi_0.6.1-1.3.diff.gz + 9694b80acc171c0a5bc99f707933864edfce555e 29063 pyspi_0.6.1.orig.tar.gz + 9694b80acc171c0a5bc99f707933864edfce555e 29063 pyspi_0.6.1.orig.tar.gz + b72cb94699298a117b7c82641c68b6fd 1782 pyspi_0.6.1-1.3.dsc + c278f52953203292bcc828bcf05aee456b160f91716f51ec1a1dbbcdb8b08fc29183d0a1135629fc0ebe86a3e84cedc685c3aa1714b70cc5db8877d40e754d7f 29063 pyspi_0.6.1.orig.tar.gz + c278f52953203292bcc828bcf05aee456b160f91716f51ec1a1dbbcdb8b08fc29183d0a1135629fc0ebe86a3e84cedc685c3aa1714b70cc5db8877d40e754d7f 29063 pyspi_0.6.1.orig.tar.gz + d494aaf526f1ec6b02f14c2f81e060a5722d6532ddc760ec16972e45c2625989 1782 pyspi_0.6.1-1.3.dsc + def336bd566ea688a06ec03db7ccf1f4 29063 pyspi_0.6.1.orig.tar.gz + def336bd566ea688a06ec03db7ccf1f4 29063 pyspi_0.6.1.orig.tar.gz + fde06b7dc5762a04986d0669420822f6a1e82b195322ae9cbd2dae40bda557c57ad77fe3546007ea645f801c4cd30ef4eb0e96efb2dee6b71c4c9a187d643683 1782 pyspi_0.6.1-1.3.dsc +Architecture: any +Architecture: any +Binary: python-at-spi +Binary: python-at-spi +Build-Depends: debhelper (>= 5), cdbs, libatspi-dev, python-pyrex, python-support (>= 0.4), python-all-dev, libx11-dev +Build-Depends: debhelper (>= 5), cdbs, libatspi-dev, python-pyrex, python-support (>= 0.4), python-all-dev, libx11-dev +Checksums-Sha1: +Checksums-Sha1: +Checksums-Sha256: +Checksums-Sha256: +Checksums-Sha512: +Checksums-Sha512: +Directory: pool/main/p/pyspi +Directory: pool/main/p/pyspi +Files: +Files: +Format: 1.0 +Format: 1.0 +Homepage: http://people.redhat.com/zcerza/dogtail +Homepage: http://people.redhat.com/zcerza/dogtail +Maintainer: Jose Carlos Garcia Sogo +Maintainer: Jose Carlos Garcia Sogo +Package: pyspi +Package: pyspi +Standards-Version: 3.7.3 +Standards-Version: 3.7.3 +Vcs-Svn: svn://svn.tribulaciones.org/srv/svn/pyspi/trunk +Vcs-Svn: svn://svn.tribulaciones.org/srv/svn/pyspi/trunk +Version: 0.6.1-1.3 +Version: 0.6.1-1.4 \ No newline at end of file diff --git a/system/t06_publish/AzurePublish2Test_binary b/system/t06_publish/AzurePublish2Test_binary new file mode 100644 index 00000000..1fd182e4 --- /dev/null +++ b/system/t06_publish/AzurePublish2Test_binary @@ -0,0 +1,27 @@ + + + (name, value) pairs from the user, via conventional methods such as + . + . + Boost version (currently 1.49). + Library to let program developers obtain program options, that is + This package forms part of the Boost C++ Libraries collection. + This package is a dependency package, which depends on Debian's default + command line and config file. +Architecture: i386 +Depends: libboost-program-options1.49-dev +Description: program options library for C++ (default version) +Filename: pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb +Homepage: http://www.boost.org/libs/program_options/ +Installed-Size: 26 +MD5sum: 0035d7822b2f8f0ec4013f270fd650c2 +Maintainer: Debian Boost Team +Package: libboost-program-options-dev +Priority: optional +SHA1: 36895eb64cfe89c33c0a2f7ac2f0c6e0e889e04b +SHA256: c76b4bd12fd92e4dfe1b55b18a67a669d92f62985d6a96c8a21d96120982cf12 +SHA512: d7302241373da972aa9b9e71d2fd769b31a38f71182aa71bc0d69d090d452c69bb74b8612c002ccf8a89c279ced84ac27177c8b92d20f00023b3d268e6cec69c +Section: libdevel +Size: 2738 +Source: boost-defaults +Version: 1.49.0.1 \ No newline at end of file diff --git a/system/t06_publish/AzurePublish2Test_gold b/system/t06_publish/AzurePublish2Test_gold new file mode 100644 index 00000000..d9fa9ada --- /dev/null +++ b/system/t06_publish/AzurePublish2Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... + +Publish for local repo azure:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/AzurePublish2Test_release b/system/t06_publish/AzurePublish2Test_release new file mode 100644 index 00000000..78154c5b --- /dev/null +++ b/system/t06_publish/AzurePublish2Test_release @@ -0,0 +1,11 @@ +Origin: . maverick +Label: . maverick +Suite: maverick +Codename: maverick +Architectures: i386 +Components: main +Description: Generated by aptly +MD5Sum: +SHA1: +SHA256: +SHA512: diff --git a/system/t06_publish/AzurePublish2Test_sources b/system/t06_publish/AzurePublish2Test_sources new file mode 100644 index 00000000..e69de29b diff --git a/system/t06_publish/AzurePublish3Test_binary b/system/t06_publish/AzurePublish3Test_binary new file mode 100644 index 00000000..aea5c35d --- /dev/null +++ b/system/t06_publish/AzurePublish3Test_binary @@ -0,0 +1,30 @@ + + + . + . + C-like language. Can perform smoothing, spline-fitting, or nonlinear fits, + Data files and self-defined functions can be manipulated by the internal + Gnuplot is a portable command-line driven interactive data and function + This package contains the terminal driver that enables gnuplot to plot + and can work with complex numbers. + for many printers, (La)TeX, (x)fig, Postscript, and so on. The X11-output + gnuplot. + images interactively under X11. Most users will want this, it is however + is packaged in gnuplot-x11. + packaged separately so that low-end systems don't need X installed to use + plotting utility that supports lots of output formats, including drivers +Architecture: i386 +Depends: gnuplot-nox (>= 4.6.1-1~maverick2), libc6 (>= 2.11), libcairo2 (>= 1.6.0), libedit2 (>= 2.5.cvs.20010821-1), libgcc1 (>= 1:4.1.1), libgd2-noxpm (>= 2.0.36~rc1~dfsg) | libgd2-xpm (>= 2.0.36~rc1~dfsg), libglib2.0-0 (>= 2.12.0), liblua5.1-0, libpango1.0-0 (>= 1.14.0), libstdc++6 (>= 4.1.1), libwxbase2.8-0 (>= 2.8.11.0), libwxgtk2.8-0 (>= 2.8.11.0), libx11-6 +Description: Command-line driven interactive plotting program +Filename: pool/main/g/gnuplot/gnuplot-x11_4.6.1-1~maverick2_i386.deb +Installed-Size: 1604 +MD5sum: fcad938905d0ace50a6ce0c73b2c6583 +Maintainer: Debian Science Team +Package: gnuplot-x11 +Priority: optional +Replaces: gnuplot (<< 4.0.0) +SHA1: 02f9a93097a8f798a054e26154dbe5789088c069 +Section: math +Size: 724388 +Source: gnuplot +Version: 4.6.1-1~maverick2 \ No newline at end of file diff --git a/system/t06_publish/AzurePublish3Test_gold b/system/t06_publish/AzurePublish3Test_gold new file mode 100644 index 00000000..fbcd2e79 --- /dev/null +++ b/system/t06_publish/AzurePublish3Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... + +Publish for snapshot azure:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. diff --git a/system/t06_publish/AzurePublish3Test_release b/system/t06_publish/AzurePublish3Test_release new file mode 100644 index 00000000..91ff3759 --- /dev/null +++ b/system/t06_publish/AzurePublish3Test_release @@ -0,0 +1,11 @@ +Origin: LP-PPA-gladky-anton-gnuplot +Label: . maverick +Suite: maverick +Codename: maverick +Architectures: amd64 i386 +Components: main +Description: Generated by aptly +MD5Sum: +SHA1: +SHA256: +SHA512: diff --git a/system/t06_publish/AzurePublish4Test_gold b/system/t06_publish/AzurePublish4Test_gold new file mode 100644 index 00000000..b5d583c1 --- /dev/null +++ b/system/t06_publish/AzurePublish4Test_gold @@ -0,0 +1,4 @@ +Published repositories: + * azure:test1:./maverick [amd64, i386] publishes {main: [local-repo]} + * azure:test1:./xyz [amd64, i386] publishes {main: [local-repo]} + * azure:test1:prefix/maverick [amd64, i386] publishes {main: [local-repo]} diff --git a/system/t06_publish/AzurePublish5Test_gold b/system/t06_publish/AzurePublish5Test_gold new file mode 100644 index 00000000..cadce02c --- /dev/null +++ b/system/t06_publish/AzurePublish5Test_gold @@ -0,0 +1,3 @@ +Cleaning up prefix "." components main... + +Published repository has been removed successfully. diff --git a/system/t06_publish/PublishList5Test_gold b/system/t06_publish/PublishList5Test_gold index 61f468b9..58b5dc05 100644 --- a/system/t06_publish/PublishList5Test_gold +++ b/system/t06_publish/PublishList5Test_gold @@ -6,8 +6,10 @@ "i386" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "maverick", "Label": "", + "MultiDist": false, "NotAutomatic": "", "Origin": "LP-PPA-gladky-anton-gnuplot", "Path": "./maverick", @@ -29,8 +31,10 @@ "amd64" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "wheezy", "Label": "", + "MultiDist": false, "NotAutomatic": "", "Origin": "", "Path": "ppa/smira/wheezy", @@ -53,8 +57,10 @@ "i386" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "maverick", "Label": "", + "MultiDist": false, "NotAutomatic": "", "Origin": "origin1", "Path": "ppa/tr1/maverick", @@ -77,8 +83,10 @@ "i386" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "maverick", "Label": "label1", + "MultiDist": false, "NotAutomatic": "", "Origin": "", "Path": "ppa/tr2/maverick", diff --git a/system/t06_publish/PublishShow3Test_gold b/system/t06_publish/PublishShow3Test_gold index b68fbef1..aefbff7c 100644 --- a/system/t06_publish/PublishShow3Test_gold +++ b/system/t06_publish/PublishShow3Test_gold @@ -5,8 +5,10 @@ "i386" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "maverick", "Label": "", + "MultiDist": false, "NotAutomatic": "", "Origin": "LP-PPA-gladky-anton-gnuplot", "Path": "./maverick", diff --git a/system/t06_publish/PublishShow4Test_gold b/system/t06_publish/PublishShow4Test_gold index 24fe5949..cf95faee 100644 --- a/system/t06_publish/PublishShow4Test_gold +++ b/system/t06_publish/PublishShow4Test_gold @@ -5,8 +5,10 @@ "i386" ], "ButAutomaticUpgrades": "", + "Codename": "", "Distribution": "maverick", "Label": "", + "MultiDist": false, "NotAutomatic": "", "Origin": "LP-PPA-gladky-anton-gnuplot", "Path": "ppa/smira/maverick", diff --git a/system/t06_publish/PublishSnapshot1Test_release_amd64 b/system/t06_publish/PublishSnapshot1Test_release_amd64 index b69b5727..08216879 100644 --- a/system/t06_publish/PublishSnapshot1Test_release_amd64 +++ b/system/t06_publish/PublishSnapshot1Test_release_amd64 @@ -2,5 +2,6 @@ Origin: LP-PPA-gladky-anton-gnuplot Label: . maverick Archive: maverick Suite: maverick +Codename: maverick Architecture: amd64 Component: main diff --git a/system/t06_publish/PublishSnapshot1Test_release_i386 b/system/t06_publish/PublishSnapshot1Test_release_i386 index 484aabc6..c776b4bc 100644 --- a/system/t06_publish/PublishSnapshot1Test_release_i386 +++ b/system/t06_publish/PublishSnapshot1Test_release_i386 @@ -2,5 +2,6 @@ Origin: LP-PPA-gladky-anton-gnuplot Label: . maverick Archive: maverick Suite: maverick +Codename: maverick Architecture: i386 Component: main diff --git a/system/t06_publish/PublishSnapshot35Test_release_udeb_i386 b/system/t06_publish/PublishSnapshot35Test_release_udeb_i386 index e93dcfe6..d50da52d 100644 --- a/system/t06_publish/PublishSnapshot35Test_release_udeb_i386 +++ b/system/t06_publish/PublishSnapshot35Test_release_udeb_i386 @@ -2,5 +2,6 @@ Origin: Debian Label: . stretch Archive: stretch Suite: stretch +Codename: stretch Architecture: i386 Component: main diff --git a/system/t06_publish/PublishSnapshot39Test_release_amd64 b/system/t06_publish/PublishSnapshot39Test_release_amd64 index cfc9b675..669008de 100644 --- a/system/t06_publish/PublishSnapshot39Test_release_amd64 +++ b/system/t06_publish/PublishSnapshot39Test_release_amd64 @@ -2,5 +2,6 @@ Origin: LP-PPA-gladky-anton-gnuplot Label: . maverick Archive: maverick Suite: stable +Codename: maverick Architecture: amd64 Component: main diff --git a/system/t06_publish/PublishSnapshot39Test_release_i386 b/system/t06_publish/PublishSnapshot39Test_release_i386 index a509da19..17bccc9f 100644 --- a/system/t06_publish/PublishSnapshot39Test_release_i386 +++ b/system/t06_publish/PublishSnapshot39Test_release_i386 @@ -2,5 +2,6 @@ Origin: LP-PPA-gladky-anton-gnuplot Label: . maverick Archive: maverick Suite: stable +Codename: maverick Architecture: i386 Component: main diff --git a/system/t06_publish/PublishSnapshot41Test_gold b/system/t06_publish/PublishSnapshot41Test_gold new file mode 100644 index 00000000..06f16c33 --- /dev/null +++ b/system/t06_publish/PublishSnapshot41Test_gold @@ -0,0 +1,14 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: + +Snapshot snap41 has been successfully published. +Please setup your webserver to serve directory '${HOME}/.aptly/public' with autoindexing. +Now you can add following line to apt sources: + deb http://your-server/ buster/updates main + deb-src http://your-server/ buster/updates main +Don't forget to add your GPG key to apt with apt-key. + +You can also use `aptly serve` to publish your repositories over HTTP quickly. diff --git a/system/t06_publish/PublishSwitch12Test_gold b/system/t06_publish/PublishSwitch12Test_gold index 2fb3bcac..8a50172b 100644 --- a/system/t06_publish/PublishSwitch12Test_gold +++ b/system/t06_publish/PublishSwitch12Test_gold @@ -1 +1,8 @@ -ERROR: unable to switch: component c is not in published repository +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components a, c... + +Publish for snapshot ./maverick [i386] publishes {a: [snap2]: Created as empty}, {b: [snap2]: Created as empty}, {c: [snap3]: Created as empty} has been successfully switched to new snapshot. diff --git a/system/t06_publish/PublishSwitch16Test_gold b/system/t06_publish/PublishSwitch16Test_gold new file mode 100644 index 00000000..122b2882 --- /dev/null +++ b/system/t06_publish/PublishSwitch16Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... + +Publish for snapshot ./bookworm (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. diff --git a/system/t06_publish/PublishUpdate14Test_gold b/system/t06_publish/PublishUpdate14Test_gold new file mode 100644 index 00000000..6bd929ca --- /dev/null +++ b/system/t06_publish/PublishUpdate14Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components main... + +Publish for local repo ./bookworm [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/azure.py b/system/t06_publish/azure.py new file mode 100644 index 00000000..962021e1 --- /dev/null +++ b/system/t06_publish/azure.py @@ -0,0 +1,211 @@ +from azure_lib import AzureTest + + +def strip_processor(output): + return '\n'.join( + [ + l + for l in output.split('\n') + if not l.startswith(' ') and not l.startswith('Date:') + ] + ) + + +class AzurePublish1Test(AzureTest): + """ + publish to Azure: from repo + """ + + fixtureCmds = [ + 'aptly repo create -distribution=maverick local-repo', + 'aptly repo add local-repo ${files}', + 'aptly repo remove local-repo libboost-program-options-dev_1.62.0.1_i386', + ] + runCmd = 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo azure:test1:' + + def check(self): + super(AzurePublish1Test, self).check() + + self.check_exists('public/dists/maverick/InRelease') + self.check_exists('public/dists/maverick/Release') + self.check_exists('public/dists/maverick/Release.gpg') + + self.check_exists('public/dists/maverick/main/binary-i386/Packages') + self.check_exists('public/dists/maverick/main/binary-i386/Packages.gz') + self.check_exists('public/dists/maverick/main/binary-i386/Packages.bz2') + self.check_exists('public/dists/maverick/main/source/Sources') + self.check_exists('public/dists/maverick/main/source/Sources.gz') + self.check_exists('public/dists/maverick/main/source/Sources.bz2') + + self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc') + self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz') + self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz') + self.check_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc') + self.check_exists( + 'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb' + ) + + # # verify contents except of sums + self.check_file_contents( + 'public/dists/maverick/Release', 'release', match_prepare=strip_processor + ) + self.check_file_contents( + 'public/dists/maverick/main/source/Sources', + 'sources', + match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))), + ) + self.check_file_contents( + 'public/dists/maverick/main/binary-i386/Packages', + 'binary', + match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))), + ) + + +class AzurePublish2Test(AzureTest): + """ + publish to Azure: publish update removed some packages + """ + + fixtureCmds = [ + 'aptly repo create -distribution=maverick local-repo', + 'aptly repo add local-repo ${files}/', + 'aptly repo remove local-repo libboost-program-options-dev_1.62.0.1_i386', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo azure:test1:', + 'aptly repo remove local-repo pyspi', + ] + runCmd = 'aptly publish update -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec maverick azure:test1:' + + def check(self): + super(AzurePublish2Test, self).check() + + self.check_exists('public/dists/maverick/InRelease') + self.check_exists('public/dists/maverick/Release') + self.check_exists('public/dists/maverick/Release.gpg') + + self.check_exists('public/dists/maverick/main/binary-i386/Packages') + self.check_exists('public/dists/maverick/main/binary-i386/Packages.gz') + self.check_exists('public/dists/maverick/main/binary-i386/Packages.bz2') + self.check_exists('public/dists/maverick/main/source/Sources') + self.check_exists('public/dists/maverick/main/source/Sources.gz') + self.check_exists('public/dists/maverick/main/source/Sources.bz2') + + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc') + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz') + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz') + self.check_not_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc') + self.check_exists( + 'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb' + ) + + # verify contents except of sums + self.check_file_contents( + 'public/dists/maverick/Release', 'release', match_prepare=strip_processor + ) + self.check_file_contents( + 'public/dists/maverick/main/source/Sources', + 'sources', + match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))), + ) + self.check_file_contents( + 'public/dists/maverick/main/binary-i386/Packages', + 'binary', + match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))), + ) + + +class AzurePublish3Test(AzureTest): + """ + publish to Azure: publish switch - removed some packages + """ + + fixtureDB = True + fixturePool = True + fixtureCmds = [ + 'aptly snapshot create snap1 from mirror gnuplot-maverick', + 'aptly snapshot create snap2 empty', + 'aptly snapshot pull -no-deps -architectures=i386,amd64 snap2 snap1 snap3 gnuplot-x11', + 'aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick snap1 azure:test1:', + ] + runCmd = 'aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec maverick azure:test1: snap3' + + def check(self): + super(AzurePublish3Test, self).check() + + self.check_exists('public/dists/maverick/InRelease') + self.check_exists('public/dists/maverick/Release') + self.check_exists('public/dists/maverick/Release.gpg') + + self.check_exists('public/dists/maverick/main/binary-i386/Packages.gz') + self.check_exists('public/dists/maverick/main/binary-i386/Packages.bz2') + self.check_exists('public/dists/maverick/main/binary-amd64/Packages') + self.check_exists('public/dists/maverick/main/binary-amd64/Packages.gz') + self.check_exists('public/dists/maverick/main/binary-amd64/Packages.bz2') + + self.check_exists( + 'public/pool/main/g/gnuplot/gnuplot-x11_4.6.1-1~maverick2_i386.deb' + ) + self.check_exists( + 'public/pool/main/g/gnuplot/gnuplot-x11_4.6.1-1~maverick2_amd64.deb' + ) + self.check_not_exists( + 'public/pool/main/g/gnuplot/gnuplot-nox_4.6.1-1~maverick2_i386.deb' + ) + self.check_not_exists( + 'public/pool/main/g/gnuplot/gnuplot-nox_4.6.1-1~maverick2_amd64.deb' + ) + + # verify contents except of sums + self.check_file_contents( + 'public/dists/maverick/Release', 'release', match_prepare=strip_processor + ) + self.check_file_contents( + 'public/dists/maverick/main/binary-i386/Packages', + 'binary', + match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))), + ) + + +class AzurePublish4Test(AzureTest): + """ + publish to Azure: multiple repos, list + """ + + fixtureCmds = [ + 'aptly repo create -distribution=maverick local-repo', + 'aptly repo add local-repo ${udebs}', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo azure:test1:', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=xyz local-repo azure:test1:', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo azure:test1:prefix', + ] + runCmd = 'aptly publish list' + + +class AzurePublish5Test(AzureTest): + """ + publish to Azure: publish drop - component cleanup + """ + + fixtureCmds = [ + 'aptly repo create local1', + 'aptly repo create local2', + 'aptly repo add local1 ${files}/libboost-program-options-dev_1.49.0.1_i386.deb', + 'aptly repo add local2 ${files}', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=sq1 local1 azure:test1:', + 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=sq2 local2 azure:test1:', + ] + runCmd = 'aptly publish drop sq2 azure:test1:' + + def check(self): + super(AzurePublish5Test, self).check() + + self.check_exists('public/dists/sq1') + self.check_not_exists('public/dists/sq2') + self.check_exists('public/pool/main/') + + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc') + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz') + self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz') + self.check_not_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc') + self.check_exists( + 'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb' + ) diff --git a/system/t06_publish/drop.py b/system/t06_publish/drop.py index 8c4978e7..3c361cc3 100644 --- a/system/t06_publish/drop.py +++ b/system/t06_publish/drop.py @@ -5,6 +5,7 @@ class PublishDrop1Test(BaseTest): """ publish drop: existing snapshot """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -25,6 +26,7 @@ class PublishDrop2Test(BaseTest): """ publish drop: under prefix """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -46,6 +48,7 @@ class PublishDrop3Test(BaseTest): """ publish drop: drop one distribution """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -68,6 +71,7 @@ class PublishDrop4Test(BaseTest): """ publish drop: drop one of components """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -91,6 +95,7 @@ class PublishDrop5Test(BaseTest): """ publish drop: component cleanup """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", @@ -128,6 +133,7 @@ class PublishDrop7Test(BaseTest): """ publish drop: under prefix with trailing & leading slashes """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -149,6 +155,7 @@ class PublishDrop8Test(BaseTest): """ publish drop: skip component cleanup """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", @@ -178,6 +185,7 @@ class PublishDrop9Test(BaseTest): """ publish drop: component cleanup after first cleanup skipped """ + requiresGPG2 = True fixtureCmds = [ "aptly repo create local1", "aptly repo create local2", diff --git a/system/t06_publish/list.py b/system/t06_publish/list.py index d5ad7c1f..408edcb2 100644 --- a/system/t06_publish/list.py +++ b/system/t06_publish/list.py @@ -12,6 +12,7 @@ class PublishList2Test(BaseTest): """ publish list: several repos list """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -30,6 +31,7 @@ class PublishList3Test(BaseTest): """ publish list: several repos list, raw """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ @@ -54,6 +56,7 @@ class PublishList5Test(BaseTest): """ publish list json: several repos list """ + requiresGPG2 = True fixtureDB = True fixturePool = True fixtureCmds = [ diff --git a/system/t06_publish/repo.py b/system/t06_publish/repo.py index fd3409d6..7e4b10c5 100644 --- a/system/t06_publish/repo.py +++ b/system/t06_publish/repo.py @@ -671,12 +671,12 @@ class PublishRepo26Test(BaseTest): """ publish repo: sign with passphrase """ - skipTest = "Failing on CI" fixtureCmds = [ "aptly repo create local-repo", "aptly repo add local-repo ${files}", + "gpg --import --batch --passphrase verysecret ${files}/aptly_passphrase.sec" ] - runCmd = "aptly publish repo -keyring=${files}/aptly_passphrase.pub -secret-keyring=${files}/aptly_passphrase.sec -passphrase=verysecret -distribution=maverick local-repo" + runCmd = "aptly publish repo -batch -keyring=${files}/aptly_passphrase.pub -passphrase=verysecret -distribution=maverick local-repo" gold_processor = BaseTest.expand_environ def outputMatchPrepare(_, s): diff --git a/system/t06_publish/snapshot.py b/system/t06_publish/snapshot.py index 8f4e3088..4514571d 100644 --- a/system/t06_publish/snapshot.py +++ b/system/t06_publish/snapshot.py @@ -1,6 +1,7 @@ -import os import hashlib import inspect +import os + from lib import BaseTest, ungzip_if_required @@ -982,7 +983,7 @@ class PublishSnapshot35Test(BaseTest): configOverride = {"max-tries": 1} fixtureGpg = True fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://cdn-fastly.deb.debian.org/debian/ stretch main non-free", + "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main non-free", "aptly mirror update -keyring=aptlytest.gpg stretch", "aptly snapshot create stretch from mirror stretch", ] @@ -1139,7 +1140,7 @@ class PublishSnapshot37Test(BaseTest): configOverride = {"max-tries": 1} fixtureGpg = True fixtureCmds = [ - "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://cdn-fastly.deb.debian.org/debian/ stretch main non-free", + "aptly -architectures=i386,amd64 mirror create -keyring=aptlytest.gpg -filter='$$Source (gnupg2)' -with-udebs stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main non-free", "aptly mirror update -keyring=aptlytest.gpg stretch", "aptly mirror update -keyring=aptlytest.gpg stretch", "aptly snapshot create stretch from mirror stretch", @@ -1155,7 +1156,7 @@ class PublishSnapshot38Test(BaseTest): configOverride = {"max-tries": 1} fixtureGpg = True fixtureCmds = [ - "aptly -architectures=s390x mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer stretch http://cdn-fastly.deb.debian.org/debian/ stretch main", + "aptly -architectures=s390x mirror create -keyring=aptlytest.gpg -filter='installer' -with-installer stretch http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch main", "aptly mirror update -keyring=aptlytest.gpg stretch", "aptly snapshot create stretch from mirror stretch", ] @@ -1239,3 +1240,107 @@ class PublishSnapshot40Test(BaseTest): self.check_exists('public/dists/maverick/main/binary-amd64/Packages') self.check_exists('public/dists/maverick/main/binary-amd64/Packages.gz') self.check_not_exists('public/dists/maverick/main/binary-amd64/Packages.bz2') + + +class PublishSnapshot41Test(BaseTest): + """ + publish snapshot: mirror with / in distribution + """ + configOverride = {"max-tries": 1} + fixtureGpg = True + fixtureCmds = [ + "aptly -architectures='i386' mirror create -keyring=aptlytest.gpg -with-sources -filter='nginx | Priority (required)'" # continued on next line + " -filter-with-deps=true ps41 http://repo.aptly.info/system-tests/security.debian.org/debian-security buster/updates main", + "aptly mirror update -keyring=aptlytest.gpg ps41", + "aptly snapshot create snap41 from mirror ps41", + ] + runCmd = "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec snap41" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishSnapshot41Test, self).check() + + self.check_exists('public/dists/buster/updates/Release') + self.check_exists('public/dists/buster/updates/Release.gpg') + self.check_exists('public/dists/buster/updates/InRelease') + self.check_exists('public/dists/buster/updates/main/source/Release') + self.check_exists('public/dists/buster/updates/main/source/Sources') + self.check_exists('public/dists/buster/updates/main/source/Sources.gz') + self.check_exists('public/dists/buster/updates/main/source/Sources.bz2') + self.check_exists('public/dists/buster/updates/main/binary-i386/Packages') + self.check_exists('public/dists/buster/updates/main/binary-i386/Packages.gz') + self.check_exists('public/dists/buster/updates/main/binary-i386/Packages.bz2') + self.check_exists('public/dists/buster/updates/main/binary-i386/Release') + self.check_exists('public/dists/buster/updates/main/Contents-i386.gz') + self.check_exists('public/dists/buster/updates/Contents-i386.gz') + self.check_exists('public/pool/main/u/util-linux/bsdutils_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/fdisk_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/libblkid1_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/libfdisk1_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/libmount1_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/libsmartcols1_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/libuuid1_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/mount_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/u/util-linux/util-linux_2.33.1-0.1+deb10u1_i386.deb') + self.check_exists('public/pool/main/d/dpkg/dpkg_1.19.8_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/e2fslibs_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/e2fsprogs_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/libcom-err2_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/libcomerr2_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/libext2fs2_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/e/e2fsprogs/libss2_1.44.5-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/g/gzip/gzip_1.9-3+deb10u1_i386.deb') + self.check_exists('public/pool/main/g/glibc/libc-bin_2.28-10+deb10u2_i386.deb') + self.check_exists('public/pool/main/g/glibc/libc6_2.28-10+deb10u2_i386.deb') + self.check_exists('public/pool/main/g/glibc/multiarch-support_2.28-10+deb10u2_i386.deb') + self.check_exists('public/pool/main/b/bzip2/libbz2-1.0_1.0.6-9.2~deb10u2_i386.deb') + self.check_exists('public/pool/main/f/freetype/libfreetype6_2.9.1-3+deb10u2_i386.deb') + self.check_exists('public/pool/main/libg/libgd2/libgd3_2.2.5-5.2+deb10u1_i386.deb') + self.check_exists('public/pool/main/i/icu/libicu63_63.1-6+deb10u2_i386.deb') + self.check_exists('public/pool/main/l/lz4/liblz4-1_1.8.3-1+deb10u1_i386.deb') + self.check_exists('public/pool/main/x/xz-utils/liblzma5_5.2.4-1+deb10u1_i386.deb') + self.check_exists('public/pool/main/n/ncurses/libncursesw6_6.1+20181013-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/ncurses/libtinfo5_6.1+20181013-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/ncurses/libtinfo6_6.1+20181013-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/ncurses/ncurses-base_6.1+20181013-2+deb10u5_all.deb') + self.check_exists('public/pool/main/n/ncurses/ncurses-bin_6.1+20181013-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-auth-pam_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-cache-purge_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-dav-ext_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-echo_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-fancyindex_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-geoip_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-headers-more-filter_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-image-filter_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-lua_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-ndk_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-perl_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-subs-filter_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-uploadprogress_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-upstream-fair_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-http-xslt-filter_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-mail_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-nchan_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/libnginx-mod-stream_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/nginx_1.14.2-2+deb10u5_all.deb') + self.check_exists('public/pool/main/n/nginx/nginx_1.14.2-2+deb10u5.debian.tar.xz') + self.check_exists('public/pool/main/n/nginx/nginx_1.14.2-2+deb10u5.dsc') + self.check_exists('public/pool/main/n/nginx/nginx_1.14.2.orig.tar.gz') + self.check_exists('public/pool/main/n/nginx/nginx-common_1.14.2-2+deb10u5_all.deb') + self.check_exists('public/pool/main/n/nginx/nginx-extras_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/nginx-full_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/n/nginx/nginx-light_1.14.2-2+deb10u5_i386.deb') + self.check_exists('public/pool/main/o/openssl/libssl1.1_1.1.1n-0+deb10u6_i386.deb') + self.check_exists('public/pool/main/s/systemd/libsystemd0_241-7~deb10u10_i386.deb') + self.check_exists('public/pool/main/s/systemd/libudev1_241-7~deb10u10_i386.deb') + self.check_exists('public/pool/main/t/tiff/libtiff5_4.1.0+git191117-2~deb10u9_i386.deb') + self.check_exists('public/pool/main/t/tar/tar_1.30+dfsg-6+deb10u1_i386.deb') + self.check_exists('public/pool/main/t/tzdata/tzdata_2021a-0+deb10u12_all.deb') + self.check_exists('public/pool/main/libw/libwebp/libwebp6_0.6.1-2+deb10u3_i386.deb') + self.check_exists('public/pool/main/libx/libx11/libx11-6_1.6.7-1+deb10u4_i386.deb') + self.check_exists('public/pool/main/libx/libx11/libx11-data_1.6.7-1+deb10u4_all.deb') + self.check_exists('public/pool/main/libx/libxml2/libxml2_2.9.4+dfsg1-7+deb10u6_i386.deb') + self.check_exists('public/pool/main/libx/libxpm/libxpm4_3.5.12-1+deb10u2_i386.deb') + self.check_exists('public/pool/main/libx/libxslt/libxslt1.1_1.1.32-2.2~deb10u2_i386.deb') + self.check_exists('public/pool/main/libz/libzstd/libzstd1_1.3.8+dfsg-3+deb10u2_i386.deb') + self.check_exists('public/pool/main/z/zlib/zlib1g_1.2.11.dfsg-1+deb10u2_i386.deb') diff --git a/system/t06_publish/switch.py b/system/t06_publish/switch.py index 6a86a3cc..dc777b91 100644 --- a/system/t06_publish/switch.py +++ b/system/t06_publish/switch.py @@ -424,15 +424,22 @@ class PublishSwitch11Test(BaseTest): class PublishSwitch12Test(BaseTest): """ - publish switch: wrong component names + publish switch: add new component to publish """ fixtureCmds = [ "aptly snapshot create snap1 empty", "aptly snapshot create snap2 empty", + "aptly snapshot create snap3 empty", "aptly publish snapshot -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b snap1 snap2", ] - runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=a,c maverick snap2 snap1" - expectedCode = 1 + runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=a,c maverick snap2 snap3" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishSwitch12Test, self).check() + + self.check_exists('public/dists/maverick/a/binary-i386/Packages') + self.check_exists('public/dists/maverick/c/binary-i386/Packages') class PublishSwitch13Test(BaseTest): @@ -574,3 +581,32 @@ class PublishSwitch15Test(BaseTest): self.check_exists('public/dists/maverick/main/binary-amd64/Packages') self.check_exists('public/dists/maverick/main/binary-amd64/Packages.gz') self.check_not_exists('public/dists/maverick/main/binary-amd64/Packages.bz2') + + +class PublishSwitch16Test(BaseTest): + """ + publish switch: -multi-dist + """ + fixtureDB = True + fixturePool = True + fixtureCmds = [ + "aptly snapshot create snap1 from mirror gnuplot-maverick", + "aptly snapshot create snap2 empty", + "aptly snapshot pull -no-deps -architectures=i386,amd64 snap2 snap1 snap3 gnuplot-x11", + "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=bookworm snap1", + ] + runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -multi-dist bookworm snap3" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishSwitch16Test, self).check() + + self.check_exists('public/dists/bookworm/Release') + + self.check_exists('public/dists/bookworm/main/binary-i386/Packages') + self.check_exists('public/dists/bookworm/main/binary-i386/Packages.gz') + + self.check_exists('public/dists/bookworm/main/binary-amd64/Packages') + self.check_exists('public/dists/bookworm/main/binary-amd64/Packages.gz') + + self.check_exists('public/pool/bookworm/main/g/gnuplot/gnuplot-x11_4.6.1-1~maverick2_amd64.deb') diff --git a/system/t06_publish/update.py b/system/t06_publish/update.py index d3cb443f..7757715a 100644 --- a/system/t06_publish/update.py +++ b/system/t06_publish/update.py @@ -462,3 +462,28 @@ class PublishUpdate13Test(BaseTest): self.check_exists('public/dists/maverick/main/binary-i386/Packages') self.check_exists('public/dists/maverick/main/binary-i386/Packages.gz') self.check_not_exists('public/dists/maverick/main/binary-i386/Packages.bz2') + + +class PublishUpdate14Test(BaseTest): + """ + publish update: -multi-dist + """ + fixtureCmds = [ + "aptly repo create local-repo", + "aptly repo add local-repo ${files}/", + "aptly publish repo -keyring=${files}/aptly.pub -distribution=bookworm local-repo", + ] + runCmd = "aptly publish update -keyring=${files}/aptly.pub -multi-dist bookworm" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishUpdate14Test, self).check() + + self.check_exists('public/dists/bookworm/InRelease') + self.check_exists('public/dists/bookworm/Release') + self.check_exists('public/dists/bookworm/Release.gpg') + + self.check_exists('public/dists/bookworm/main/binary-i386/Packages') + self.check_exists('public/dists/bookworm/main/binary-i386/Packages.gz') + + self.check_exists('public/pool/bookworm/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb') diff --git a/system/t07_serve/__init__.py b/system/t07_serve/__init__.py index 457b9f59..1d3d2f7c 100644 --- a/system/t07_serve/__init__.py +++ b/system/t07_serve/__init__.py @@ -1,81 +1,3 @@ """ Testing serving public repo """ - -import http.client -import os -import signal -import subprocess -import shlex -import time - -from lib import BaseTest - - -class RootDirInaccessible(BaseTest): - """ - serve command aborts if rootDir is inaccessible - """ - skipTest = 'User is root' if os.environ['USER'] == 'root' else False - fixtureDB = False - fixturePool = False - - configOverride = { - "rootDir": "/root" # any directory that exists but is not writable - } - - runCmd = "aptly serve -listen=127.0.0.1:8765" - expectedCode = 1 - - -class Serve1Test(BaseTest): - """ - serve public: two publishes, verify HTTP - """ - fixtureDB = True - fixturePool = True - fixtureCmds = [ - "aptly snapshot create snap1 from mirror gnuplot-maverick", - "aptly snapshot create snap2 from mirror gnuplot-maverick-src", - "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec snap1", - "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec snap2 debian", - "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=main,contrib snap1 snap2 multi", - ] - runCmd = "aptly serve -listen=127.0.0.1:8765" - - def run(self): - try: - proc = subprocess.Popen(shlex.split(self.runCmd), stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=0) - - try: - time.sleep(1) - - conn = http.client.HTTPConnection("127.0.0.1", 8765) - conn.request("GET", "/") - r = conn.getresponse() - if r.status != 200: - raise Exception("Expected status 200 != %d" % r.status) - self.http_response = r.read() - - output = os.read(proc.stdout.fileno(), 8192) - - finally: - proc.send_signal(signal.SIGINT) - proc.wait() - - if proc.returncode != -2 and proc.returncode != 2: - raise Exception("exit code %d != %d (output: %s)" % (proc.returncode, -2, output)) - self.output = output - except Exception as e: - raise Exception("Running command %s failed: %s" % (self.runCmd, str(e))) - - def check(self): - self.check_output() - self.verify_match(self.get_gold('http'), self.http_response, match_prepare=lambda s: "\n".join(sorted(s.split("\n")))) - - -class Serve2Test(BaseTest): - """ - serve public: no publishes - """ - runCmd = "aptly serve -listen=127.0.0.1:8765" diff --git a/system/t07_serve/serve.py b/system/t07_serve/serve.py new file mode 100644 index 00000000..4f473f3b --- /dev/null +++ b/system/t07_serve/serve.py @@ -0,0 +1,81 @@ +""" +Testing serving public repo +""" + +import http.client +import os +import signal +import subprocess +import shlex +import time + +from lib import BaseTest + + +class RootDirInaccessible(BaseTest): + """ + serve command aborts if rootDir is inaccessible + """ + skipTest = 'User is root' if os.environ['USER'] == 'root' else False + fixtureDB = False + fixturePool = False + + configOverride = { + "rootDir": "/root" # any directory that exists but is not writable + } + + runCmd = "aptly serve -listen=127.0.0.1:8765" + expectedCode = 1 + + +class Serve1Test(BaseTest): + """ + serve public: two publishes, verify HTTP + """ + fixtureDB = True + fixturePool = True + fixtureCmds = [ + "aptly snapshot create snap1 from mirror gnuplot-maverick", + "aptly snapshot create snap2 from mirror gnuplot-maverick-src", + "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec snap1", + "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec snap2 debian", + "aptly publish snapshot -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=main,contrib snap1 snap2 multi", + ] + runCmd = "../aptly.test serve -listen=127.0.0.1:8765" + + def run(self): + try: + proc = subprocess.Popen(shlex.split(self.runCmd), stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=0) + + try: + time.sleep(1) + + conn = http.client.HTTPConnection("127.0.0.1", 8765) + conn.request("GET", "/") + r = conn.getresponse() + if r.status != 200: + raise Exception("Expected status 200 != %d" % r.status) + self.http_response = r.read() + + output = os.read(proc.stdout.fileno(), 8192) + + finally: + proc.send_signal(signal.SIGINT) + proc.wait() + + if proc.returncode != -2 and proc.returncode != 2: + raise Exception("exit code %d != %d (output: %s)" % (proc.returncode, -2, output)) + self.output = output + except Exception as e: + raise Exception("Running command %s failed: %s" % (self.runCmd, str(e))) + + def check(self): + self.check_output() + self.verify_match(self.get_gold('http'), self.http_response, match_prepare=lambda s: "\n".join(sorted(s.split("\n")))) + + +class Serve2Test(BaseTest): + """ + serve public: no publishes + """ + runCmd = "aptly serve -listen=127.0.0.1:8765" diff --git a/system/t09_repo/AzureRepoTest_gold b/system/t09_repo/AzureRepoTest_gold new file mode 100644 index 00000000..7ddaaa9f --- /dev/null +++ b/system/t09_repo/AzureRepoTest_gold @@ -0,0 +1,5 @@ +Loading packages... +[+] libboost-program-options-dev_1.49.0.1_i386 added +[+] libboost-program-options-dev_1.62.0.1_i386 added +[+] pyspi_0.6.1-1.4_source added +[+] pyspi_0.6.1-1.3_source added diff --git a/system/t09_repo/AzureRepoTest_repo_show b/system/t09_repo/AzureRepoTest_repo_show new file mode 100644 index 00000000..17dbc6ef --- /dev/null +++ b/system/t09_repo/AzureRepoTest_repo_show @@ -0,0 +1,10 @@ +Name: repo +Comment: Repo +Default Distribution: squeeze +Default Component: main +Number of packages: 4 +Packages: + libboost-program-options-dev_1.62.0.1_i386 + libboost-program-options-dev_1.49.0.1_i386 + pyspi_0.6.1-1.4_source + pyspi_0.6.1-1.3_source diff --git a/system/t09_repo/ImportRepo1Test_gold b/system/t09_repo/ImportRepo1Test_gold index c4fa29ca..9e7a9597 100644 --- a/system/t09_repo/ImportRepo1Test_gold +++ b/system/t09_repo/ImportRepo1Test_gold @@ -1,4 +1,13 @@ Loading packages... +[o] nginx-extras_1.2.1-2.2+wheezy2_amd64 imported +[o] nginx-extras_1.2.1-2.2+wheezy2_i386 imported +[o] nginx-full_1.2.1-2.2+wheezy2_amd64 imported +[o] nginx-full_1.2.1-2.2+wheezy2_i386 imported +[o] nginx-light_1.2.1-2.2+wheezy2_amd64 imported +[o] nginx-light_1.2.1-2.2+wheezy2_i386 imported +[o] nginx-naxsi-ui_1.2.1-2.2+wheezy2_all imported +[o] nginx-naxsi_1.2.1-2.2+wheezy2_amd64 imported +[o] nginx-naxsi_1.2.1-2.2+wheezy2_i386 imported [o] nginx_1.2.1-2.2+wheezy2_all imported [o] unpaper_0.4.2-1_amd64 imported \ No newline at end of file diff --git a/system/t09_repo/ImportRepo1Test_repo_show b/system/t09_repo/ImportRepo1Test_repo_show index daf99d40..8b71f6d0 100644 --- a/system/t09_repo/ImportRepo1Test_repo_show +++ b/system/t09_repo/ImportRepo1Test_repo_show @@ -2,11 +2,20 @@ Name: repo1 Comment: Cool Default Distribution: squeeze Default Component: main -Number of packages: 6 +Number of packages: 15 Packages: libboost-program-options-dev_1.62.0.1_i386 libboost-program-options-dev_1.49.0.1_i386 nginx_1.2.1-2.2+wheezy2_all + nginx-extras_1.2.1-2.2+wheezy2_amd64 + nginx-extras_1.2.1-2.2+wheezy2_i386 + nginx-full_1.2.1-2.2+wheezy2_amd64 + nginx-full_1.2.1-2.2+wheezy2_i386 + nginx-light_1.2.1-2.2+wheezy2_amd64 + nginx-light_1.2.1-2.2+wheezy2_i386 + nginx-naxsi_1.2.1-2.2+wheezy2_amd64 + nginx-naxsi_1.2.1-2.2+wheezy2_i386 + nginx-naxsi-ui_1.2.1-2.2+wheezy2_all pyspi_0.6.1-1.4_source pyspi_0.6.1-1.3_source unpaper_0.4.2-1_amd64 diff --git a/system/t09_repo/IncludeRepo13Test_gold b/system/t09_repo/IncludeRepo13Test_gold index 3a048076..410ff1e2 100644 --- a/system/t09_repo/IncludeRepo13Test_gold +++ b/system/t09_repo/IncludeRepo13Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []pgp.Key{"21DBB89C16DB3E6D"}: denied as no rule matches diff --git a/system/t09_repo/IncludeRepo14Test_gold b/system/t09_repo/IncludeRepo14Test_gold index 58285bb6..13bad791 100644 --- a/system/t09_repo/IncludeRepo14Test_gold +++ b/system/t09_repo/IncludeRepo14Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [+] hardlink_0.2.1_source added diff --git a/system/t09_repo/IncludeRepo18Test_gold b/system/t09_repo/IncludeRepo18Test_gold index 58285bb6..13bad791 100644 --- a/system/t09_repo/IncludeRepo18Test_gold +++ b/system/t09_repo/IncludeRepo18Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [+] hardlink_0.2.1_source added diff --git a/system/t09_repo/IncludeRepo19Test_gold b/system/t09_repo/IncludeRepo19Test_gold index 3a048076..410ff1e2 100644 --- a/system/t09_repo/IncludeRepo19Test_gold +++ b/system/t09_repo/IncludeRepo19Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []pgp.Key{"21DBB89C16DB3E6D"}: denied as no rule matches diff --git a/system/t09_repo/IncludeRepo1Test_gold b/system/t09_repo/IncludeRepo1Test_gold index 456eb0b5..13bad791 100644 --- a/system/t09_repo/IncludeRepo1Test_gold +++ b/system/t09_repo/IncludeRepo1Test_gold @@ -1,4 +1,5 @@ -gpgv: Signature made Sun Mar 15 20:36:44 2015 MSK using DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [+] hardlink_0.2.1_source added diff --git a/system/t09_repo/IncludeRepo21Test_gold b/system/t09_repo/IncludeRepo21Test_gold index ab43a776..eee0a5d7 100644 --- a/system/t09_repo/IncludeRepo21Test_gold +++ b/system/t09_repo/IncludeRepo21Test_gold @@ -1,4 +1,4 @@ -[!] unable to process file hardlink_0.2.1_amd64.changes: failed to verify signature: openpgp: invalid signature: hash tag doesn't match +[!] unable to process file hardlink_0.2.1_amd64.changes: failed to verify signature: openpgp: invalid signature: DSA verification failure [!] Some files were skipped due to errors: /01/hardlink_0.2.1_amd64.changes ERROR: some files failed to be added diff --git a/system/t09_repo/IncludeRepo2Test_gold b/system/t09_repo/IncludeRepo2Test_gold index a9f191f2..f4399d73 100644 --- a/system/t09_repo/IncludeRepo2Test_gold +++ b/system/t09_repo/IncludeRepo2Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository my-unstable for changes file hardlink_0.2.1_amd64.changes... [+] hardlink_0.2.1_source added diff --git a/system/t09_repo/IncludeRepo3Test_gold b/system/t09_repo/IncludeRepo3Test_gold index 96cda590..47fd79f8 100644 --- a/system/t09_repo/IncludeRepo3Test_gold +++ b/system/t09_repo/IncludeRepo3Test_gold @@ -1 +1 @@ -ERROR: error parsing -repo template: template: repo:1: unexpected "}" in operand; missing space? +ERROR: error parsing -repo template: template: repo:1: bad character U+007D '}'; missing space? diff --git a/system/t09_repo/IncludeRepo5Test_gold b/system/t09_repo/IncludeRepo5Test_gold index 58285bb6..13bad791 100644 --- a/system/t09_repo/IncludeRepo5Test_gold +++ b/system/t09_repo/IncludeRepo5Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " Loading repository unstable for changes file hardlink_0.2.1_amd64.changes... [+] hardlink_0.2.1_source added diff --git a/system/t09_repo/IncludeRepo6Test_gold b/system/t09_repo/IncludeRepo6Test_gold index 9c02bfa6..162a2090 100644 --- a/system/t09_repo/IncludeRepo6Test_gold +++ b/system/t09_repo/IncludeRepo6Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " [!] unable to process file hardlink_0.2.1_amd64.changes: open /01/hardlink_0.2.1.tar.gz: no such file or directory [!] Some files were skipped due to errors: diff --git a/system/t09_repo/IncludeRepo7Test_gold b/system/t09_repo/IncludeRepo7Test_gold index 2215c9dd..a1af0721 100644 --- a/system/t09_repo/IncludeRepo7Test_gold +++ b/system/t09_repo/IncludeRepo7Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: Good signature from "Aptly Tester (don't use it) " [!] unable to process file hardlink_0.2.1_amd64.changes: checksum mismatch MD5: expected 4efce26825af5842f43961096dd890b3 != obtained 7515e9279fc32d0c89db965f4dfdec8c [!] Some files were skipped due to errors: diff --git a/system/t09_repo/IncludeRepo8Test_gold b/system/t09_repo/IncludeRepo8Test_gold index 1f1e0949..042c53e3 100644 --- a/system/t09_repo/IncludeRepo8Test_gold +++ b/system/t09_repo/IncludeRepo8Test_gold @@ -1,4 +1,5 @@ -gpgv: DSA key ID 16DB3E6D +gpgv: Signature made Sun Mar 15 17:36:44 2015 UTC +gpgv: using DSA key 21DBB89C16DB3E6D gpgv: BAD signature from "Aptly Tester (don't use it) " [!] unable to process file hardlink_0.2.1_amd64.changes: verification of clearsigned file failed: exit status 1 [!] Some files were skipped due to errors: diff --git a/system/t09_repo/azure.py b/system/t09_repo/azure.py new file mode 100644 index 00000000..7506c781 --- /dev/null +++ b/system/t09_repo/azure.py @@ -0,0 +1,42 @@ +from azure_lib import AzureTest + + +class AzureRepoTest(AzureTest): + """ + Azure: add directory to repo + """ + + fixtureCmds = [ + 'aptly repo create -comment=Repo -distribution=squeeze repo', + ] + runCmd = 'aptly repo add repo ${files}' + + use_azure_pool = True + + def prepare(self): + super(AzureRepoTest, self).prepare() + + self.configOverride['packagePoolStorage'] = { + 'azure': self.azure_endpoint, + } + + def check(self): + self.check_output() + self.check_cmd_output('aptly repo show -with-packages repo', 'repo_show') + + # check pool + self.check_exists_azure_only( + 'c7/6b/4bd12fd92e4dfe1b55b18a67a669_libboost-program-options-dev_1.49.0.1_i386.deb' + ) + self.check_exists_azure_only( + '2e/77/0b28df948f3197ed0b679bdea99f_pyspi_0.6.1-1.3.diff.gz' + ) + self.check_exists_azure_only( + 'd4/94/aaf526f1ec6b02f14c2f81e060a5_pyspi_0.6.1-1.3.dsc' + ) + self.check_exists_azure_only( + '64/06/9ee828c50b1c597d10a3fefbba27_pyspi_0.6.1.orig.tar.gz' + ) + self.check_exists_azure_only( + '28/9d/3aefa970876e9c43686ce2b02f47_pyspi-0.6.1-1.3.stripped.dsc' + ) diff --git a/system/t09_repo/cmdimport.py b/system/t09_repo/cmdimport.py index 5a4337ba..e23510db 100644 --- a/system/t09_repo/cmdimport.py +++ b/system/t09_repo/cmdimport.py @@ -83,7 +83,7 @@ class ImportRepo6Test(BaseTest): """ fixtureCmds = [ "aptly repo create -comment=Cool -distribution=squeeze repo1", - "aptly mirror create --ignore-signatures mirror1 http://cdn-fastly.deb.debian.org/debian/ stretch", + "aptly mirror create --ignore-signatures mirror1 http://repo.aptly.info/system-tests/archive.debian.org/debian-archive/debian/ stretch", ] runCmd = "aptly repo import mirror1 repo1 nginx" expectedCode = 1 diff --git a/system/t12_api/docs.py b/system/t12_api/docs.py new file mode 100644 index 00000000..50a7b1cb --- /dev/null +++ b/system/t12_api/docs.py @@ -0,0 +1,17 @@ +from api_lib import APITest + + +class TaskAPITestSwaggerDocs(APITest): + """ + GET /docs + """ + + def check(self): + resp = self.get("/docs/doc.json") + self.check_equal(resp.status_code, 200) + + resp = self.get("/docs/", allow_redirects=False) + self.check_equal(resp.status_code, 301) + + resp = self.get("/docs/index.html") + self.check_equal(resp.status_code, 200) diff --git a/system/t12_api/gpg.py b/system/t12_api/gpg.py index 8fb9a380..305a2b7e 100644 --- a/system/t12_api/gpg.py +++ b/system/t12_api/gpg.py @@ -2,32 +2,47 @@ import inspect import os import subprocess import tempfile +import json from api_lib import APITest def check_gpgkey_exists(gpg_key, keyring): - subprocess.check_call([ + p = subprocess.Popen([ "gpg", "--no-default-keyring", "--keyring", keyring, - "--fingerprint", gpg_key, - ]) + "--fingerprint", gpg_key], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + p.communicate() + if p.returncode != 0: + raise Exception("gpg key does not exists") class GPGAPITestAddKey(APITest): """ POST /gpg/key """ + requiresGPG2 = True + + fixtureCmds = [ + "gpgconf --kill dirmngr", + "gpgconf --launch dirmngr", + "sleep 2" + ] def check(self): with tempfile.NamedTemporaryFile(suffix=".pub") as keyring: gpgkeyid = "9E3E53F19C7DE460" resp = self.post("/api/gpg/key", json={ - "Keyserver": "keyserver.ubuntu.com", + "Keyserver": "hkp://keyserver.ubuntu.com:80", "Keyring": keyring.name, "GpgKeyID": gpgkeyid }) - + if resp.status_code != 200: + output = json.loads(resp.text) + print(f"{output}\n") self.check_equal(resp.status_code, 200) check_gpgkey_exists(gpgkeyid, keyring.name) diff --git a/system/t12_api/metrics.py b/system/t12_api/metrics.py index 829ac390..0b351c0b 100644 --- a/system/t12_api/metrics.py +++ b/system/t12_api/metrics.py @@ -7,6 +7,35 @@ class MetricsEnabledAPITest(APITest): """ def check(self): + d = "libboost-program-options-dev_1.62.0.1" + r = "foo" + f = "libboost-program-options-dev_1.62.0.1_i386.deb" + + self.check_equal(self.upload("/api/files/" + d, f).status_code, 200) + + self.check_equal(self.post("/api/repos", json={ + "Name": r, + "Comment": "test repo", + "DefaultDistribution": r, + "DefaultComponent": "main" + }).status_code, 201) + + self.check_equal(self.post(f"/api/repos/{r}/file/{d}").status_code, 200) + + self.check_equal(self.post("/api/publish/filesystem:apiandserve:", json={ + "SourceKind": "local", + "Sources": [ + { + "Component": "main", + "Name": r + } + ], + "Distribution": r, + "Signing": { + "Skip": True + } + }).status_code, 201) + resp = self.get("/api/metrics") self.check_equal(resp.status_code, 200) @@ -24,3 +53,18 @@ class MetricsEnabledAPITest(APITest): apiRequestsDurationSummary = "# TYPE aptly_api_http_request_duration_seconds summary" self.check_in(apiRequestsDurationSummary, resp.text) + + apiBuildInfoGauge = "# TYPE aptly_build_info gauge" + self.check_in(apiBuildInfoGauge, resp.text) + + apiFilesUploadedCounter = "# TYPE aptly_api_files_uploaded_total counter" + self.check_in(apiFilesUploadedCounter, resp.text) + + apiFilesUploadedCounterValue = "aptly_api_files_uploaded_total{directory=\"libboost-program-options-dev_1.62.0.1\"} 1" + self.check_in(apiFilesUploadedCounterValue, resp.text) + + apiReposPackageCountGauge = "# TYPE aptly_repos_package_count gauge" + self.check_in(apiReposPackageCountGauge, resp.text) + + apiReposPackageCountGaugeValue = "aptly_repos_package_count{component=\"main\",distribution=\"foo\",source=\"[foo:main]\"} 1" + self.check_in(apiReposPackageCountGaugeValue, resp.text) diff --git a/system/t12_api/mirrors.py b/system/t12_api/mirrors.py index 26960d68..6352b2ca 100644 --- a/system/t12_api/mirrors.py +++ b/system/t12_api/mirrors.py @@ -9,7 +9,7 @@ class MirrorsAPITestCreateShow(APITest): def check(self): mirror_name = self.random_name() mirror_desc = {'Name': mirror_name, - 'ArchiveURL': 'http://security.debian.org/debian-security/', + 'ArchiveURL': 'http://repo.aptly.info/system-tests/security.debian.org/debian-security/', 'Architectures': ['amd64'], 'Components': ['main'], 'Distribution': 'buster/updates'} @@ -27,7 +27,7 @@ class MirrorsAPITestCreateShow(APITest): resp = self.get("/api/mirrors/" + mirror_name) self.check_equal(resp.status_code, 200) self.check_subset({'Name': mirror_name, - 'ArchiveRoot': 'http://security.debian.org/debian-security/', + 'ArchiveRoot': 'http://repo.aptly.info/system-tests/security.debian.org/debian-security/', 'Architectures': ['amd64'], 'Components': ['main'], 'Distribution': 'buster/updates'}, resp.json()) @@ -43,8 +43,10 @@ class MirrorsAPITestCreateUpdate(APITest): def check(self): mirror_name = self.random_name() mirror_desc = {'Name': mirror_name, - 'ArchiveURL': 'https://packagecloud.io/varnishcache/varnish30/debian/', + 'ArchiveURL': 'http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/', 'Distribution': 'wheezy', + 'Keyrings': ["aptlytest.gpg"], + 'Architectures': ["amd64"], 'Components': ['main']} mirror_desc['IgnoreSignatures'] = True @@ -56,9 +58,9 @@ class MirrorsAPITestCreateUpdate(APITest): mirror_desc["Name"] = self.random_name() resp = self.put_task("/api/mirrors/" + mirror_name, json=mirror_desc) - self.check_equal(resp.json()["State"], 2) - + self.check_task(resp) _id = resp.json()['ID'] + resp = self.get("/api/tasks/" + str(_id) + "/detail") self.check_equal(resp.status_code, 200) self.check_equal(resp.json()['RemainingDownloadSize'], 0) @@ -67,7 +69,7 @@ class MirrorsAPITestCreateUpdate(APITest): resp = self.get("/api/mirrors/" + mirror_desc["Name"]) self.check_equal(resp.status_code, 200) self.check_subset({'Name': mirror_desc["Name"], - 'ArchiveRoot': 'https://packagecloud.io/varnishcache/varnish30/debian/', + 'ArchiveRoot': 'http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/', 'Distribution': 'wheezy'}, resp.json()) resp = self.get("/api/mirrors/" + mirror_desc["Name"] + "/packages") @@ -81,7 +83,7 @@ class MirrorsAPITestCreateDelete(APITest): def check(self): mirror_name = self.random_name() mirror_desc = {'Name': mirror_name, - 'ArchiveURL': 'https://packagecloud.io/varnishcache/varnish30/debian/', + 'ArchiveURL': 'http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/', 'IgnoreSignatures': True, 'Distribution': 'wheezy', 'Components': ['main']} @@ -90,7 +92,7 @@ class MirrorsAPITestCreateDelete(APITest): self.check_equal(resp.status_code, 201) resp = self.delete_task("/api/mirrors/" + mirror_name) - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) class MirrorsAPITestCreateList(APITest): @@ -104,7 +106,7 @@ class MirrorsAPITestCreateList(APITest): mirror_name = self.random_name() mirror_desc = {'Name': mirror_name, - 'ArchiveURL': 'https://packagecloud.io/varnishcache/varnish30/debian/', + 'ArchiveURL': 'http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/', 'IgnoreSignatures': True, 'Distribution': 'wheezy', 'Components': ['main']} @@ -115,3 +117,38 @@ class MirrorsAPITestCreateList(APITest): resp = self.get("/api/mirrors") self.check_equal(resp.status_code, 200) self.check_equal(len(resp.json()), count + 1) + + +class MirrorsAPITestSkipArchitectureCheck(APITest): + """ + GET /api/mirrors, POST /api/mirrors, GET /api/mirrors + + This tests SkipArchitectureCheck and IgnoreSignatures via API. + The repo to be mirrored requires the SkipArchitectureCheck and SkipComponentCheck in order to be mirrored. + """ + def check(self): + resp = self.get("/api/mirrors") + self.check_equal(resp.status_code, 200) + count = len(resp.json()) + + mirror_name = self.random_name() + mirror_desc = {'Name': mirror_name, + 'ArchiveURL': 'http://repo.aptly.info/system-tests/pkg.duosecurity.com/Debian', + 'Architectures': ['amd64', 'i386'], + 'SkipArchitectureCheck': True, + 'SkipComponentCheck': True, + 'IgnoreSignatures': True, + 'Distribution': 'bookworm', + 'Components': ['main']} + + resp = self.post("/api/mirrors", json=mirror_desc) + self.check_equal(resp.status_code, 201) + + resp = self.get("/api/mirrors") + self.check_equal(resp.status_code, 200) + self.check_equal(len(resp.json()), count + 1) + + mirror_desc = {'Name': mirror_name, + 'IgnoreSignatures': True} + resp = self.put_task("/api/mirrors/" + mirror_name, json=mirror_desc) + self.check_task(resp) diff --git a/system/t12_api/packages.py b/system/t12_api/packages.py index fea11951..86cf6ea1 100644 --- a/system/t12_api/packages.py +++ b/system/t12_api/packages.py @@ -19,12 +19,10 @@ class PackagesAPITestShow(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz").status_code, 200) resp = self.post_task("/api/repos/" + repo_name + "/file/" + d) - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) # get information about package - resp = self.get("/api/packages/" + urllib.parse.quote('Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e')) - self.check_equal(resp.status_code, 200) - self.check_equal(resp.json(), { + pyspi_json = { 'Architecture': 'any', 'Binary': 'python-at-spi', 'Build-Depends': 'debhelper (>= 5), cdbs, libatspi-dev, python-pyrex, python-support (>= 0.4), python-all-dev, libx11-dev', # noqa @@ -41,7 +39,24 @@ class PackagesAPITestShow(APITest): 'ShortKey': 'Psource pyspi 0.6.1-1.3', 'Standards-Version': '3.7.3', 'Vcs-Svn': 'svn://svn.tribulaciones.org/srv/svn/pyspi/trunk', - 'Version': '0.6.1-1.3'}) + 'Version': '0.6.1-1.3' + } + + resp = self.get("/api/packages/" + urllib.parse.quote('Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e')) + self.check_equal(resp.status_code, 200) + self.check_equal(resp.json(), pyspi_json) + + resp = self.get("/api/packages?q=pyspi") + self.check_equal(resp.status_code, 200) + self.check_equal(resp.json(), [pyspi_json["Key"]]) + + resp = self.get("/api/packages?q=pyspi&format=details") + self.check_equal(resp.status_code, 200) + self.check_equal(resp.json(), [pyspi_json]) resp = self.get("/api/packages/" + urllib.parse.quote('Pamd64 no-such-package 1.0 3a8b37cbd9a3559e')) self.check_equal(resp.status_code, 404) + + resp = self.get("/api/packages?q=no-such-package") + self.check_equal(resp.status_code, 200) + self.check_equal(resp.json(), []) diff --git a/system/t12_api/probes.py b/system/t12_api/probes.py new file mode 100644 index 00000000..3c248f14 --- /dev/null +++ b/system/t12_api/probes.py @@ -0,0 +1,27 @@ +from api_lib import APITest + + +class ReadyAPITest(APITest): + """ + GET /ready + """ + + def check(self): + resp = self.get("/api/ready") + self.check_equal(resp.status_code, 200) + + readyStatus = "{\"Status\":\"Aptly is ready\"}" + self.check_equal(readyStatus, resp.text) + + +class HealthyAPITest(APITest): + """ + GET /healthy + """ + + def check(self): + resp = self.get("/api/healthy") + self.check_equal(resp.status_code, 200) + + healthyStatus = "{\"Status\":\"Aptly is healthy\"}" + self.check_equal(healthyStatus, resp.text) diff --git a/system/t12_api/publish.py b/system/t12_api/publish.py index 99f339ed..325802d2 100644 --- a/system/t12_api/publish.py +++ b/system/t12_api/publish.py @@ -1,11 +1,11 @@ -import os import inspect +import os +import threading -from api_lib import APITest +from api_lib import TASK_SUCCEEDED, APITest DefaultSigningOptions = { "Keyring": os.path.join(os.path.dirname(inspect.getsourcefile(APITest)), "files") + "/aptly.pub", - "SecretKeyring": os.path.join(os.path.dirname(inspect.getsourcefile(APITest)), "files") + "/aptly.sec", } @@ -26,11 +26,12 @@ class PublishAPITestRepo(APITest): "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) # publishing under prefix, default distribution prefix = self.random_name() - resp = self.post_task( + task = self.post_task( "/api/publish/" + prefix, json={ "SourceKind": "local", @@ -38,9 +39,11 @@ class PublishAPITestRepo(APITest): "Signing": DefaultSigningOptions, } ) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'Origin': '', @@ -49,13 +52,12 @@ class PublishAPITestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'local', 'Sources': [{'Component': 'main', 'Name': repo_name}], 'Storage': '', 'Suite': ''} - self.check_equal(resp.json()['State'], 2) - all_repos = self.get("/api/publish") self.check_equal(all_repos.status_code, 200) self.check_in(repo_expected, all_repos.json()) @@ -72,7 +74,7 @@ class PublishAPITestRepo(APITest): # publishing under root, custom distribution, architectures distribution = self.random_name() - resp = self.post_task( + task = self.post_task( "/api/publish/:.", json={ "SourceKind": "local", @@ -82,10 +84,11 @@ class PublishAPITestRepo(APITest): "Architectures": ["i386", "amd64"], } ) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo2_expected = { 'AcquireByHash': False, 'Architectures': ['amd64', 'i386'], + 'Codename': '', 'Distribution': distribution, 'Label': '', 'Origin': '', @@ -94,6 +97,7 @@ class PublishAPITestRepo(APITest): 'Path': './' + distribution, 'Prefix': ".", 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'local', 'Sources': [{'Component': 'main', 'Name': repo_name}], 'Storage': '', @@ -120,6 +124,71 @@ class PublishAPITestRepo(APITest): self.check_in(repo2_expected, all_repos.json()) +class PublishAPITestRepoMultiDist(APITest): + """ + Test MultiDist publishing to subdirectory + """ + fixtureGpg = True + + def check(self): + repo_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo_name, "DefaultDistribution": "bookworm"}).status_code, 201) + + d = self.random_name() + self.check_equal(self.upload("/api/files/" + d, + "libboost-program-options-dev_1.49.0.1_i386.deb", "pyspi_0.6.1-1.3.dsc", + "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", + "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) + + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) + + # publishing under prefix, default distribution + prefix = self.random_name() + task = self.post_task( + "/api/publish/" + prefix, + json={ + "SourceKind": "local", + "MultiDist": True, + "Sources": [{"Name": repo_name}], + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + repo_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'bookworm', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'bookworm', + 'Prefix': prefix, + 'SkipContents': False, + 'MultiDist': True, + 'SourceKind': 'local', + 'Sources': [{'Component': 'main', 'Name': repo_name}], + 'Storage': '', + 'Suite': ''} + + all_repos = self.get("/api/publish") + self.check_equal(all_repos.status_code, 200) + self.check_in(repo_expected, all_repos.json()) + + self.check_exists("public/" + prefix + "/dists/bookworm/Release") + self.check_exists("public/" + prefix + + "/dists/bookworm/main/binary-i386/Packages") + self.check_exists("public/" + prefix + + "/dists/bookworm/main/Contents-i386.gz") + self.check_exists("public/" + prefix + + "/dists/bookworm/main/source/Sources") + self.check_exists( + "public/" + prefix + "/pool/bookworm/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") + + class PublishSnapshotAPITest(APITest): """ POST /publish/:prefix (snapshots), GET /publish @@ -135,12 +204,14 @@ class PublishSnapshotAPITest(APITest): self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - self.check_equal(self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) + self.check_task(task) prefix = self.random_name() - resp = self.post_task( + task = self.post_task( "/api/publish/" + prefix, json={ "AcquireByHash": True, @@ -154,9 +225,9 @@ class PublishSnapshotAPITest(APITest): "Label": "fun", } ) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) - _id = resp.json()['ID'] + _id = task.json()['ID'] resp = self.get("/api/tasks/" + str(_id) + "/detail") self.check_equal(resp.json()['RemainingNumberOfPackages'], 0) self.check_equal(resp.json()['TotalNumberOfPackages'], 1) @@ -164,9 +235,11 @@ class PublishSnapshotAPITest(APITest): repo_expected = { 'AcquireByHash': True, 'Architectures': ['i386'], + 'Codename': '', 'Distribution': 'squeeze', 'Label': 'fun', 'Origin': 'earth', + 'MultiDist': False, 'NotAutomatic': 'yes', 'ButAutomaticUpgrades': 'yes', 'Path': prefix + '/' + 'squeeze', @@ -209,10 +282,11 @@ class PublishUpdateAPITestRepo(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) prefix = self.random_name() - resp = self.post_task( + task = self.post_task( "/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], @@ -221,8 +295,7 @@ class PublishUpdateAPITestRepo(APITest): "Signing": DefaultSigningOptions, } ) - - self.check_equal(resp.json()['State'], 2) + self.check_task(task) self.check_not_exists( "public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") @@ -232,23 +305,26 @@ class PublishUpdateAPITestRepo(APITest): d = self.random_name() self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - self.check_equal(self.delete_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) # Update and switch AcquireByHash on. - resp = self.put_task( + task = self.put_task( "/api/publish/" + prefix + "/wheezy", json={ "AcquireByHash": True, "Signing": DefaultSigningOptions, } ) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': True, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'Origin': '', @@ -257,6 +333,7 @@ class PublishUpdateAPITestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'local', 'Sources': [{'Component': 'main', 'Name': repo_name}], 'Storage': '', @@ -274,7 +351,200 @@ class PublishUpdateAPITestRepo(APITest): self.check_not_exists( "public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") - self.check_equal(self.delete_task("/api/publish/" + prefix + "/wheezy").json()['State'], 2) + task = self.delete_task("/api/publish/" + prefix + "/wheezy") + self.check_task(task) + self.check_not_exists("public/" + prefix + "dists/") + + +class PublishUpdateAPIMultiDist(APITest): + """ + Test MultiDist publishing to subdirectory + """ + fixtureGpg = True + + def check(self): + repo_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo_name, "DefaultDistribution": "bookworm"}).status_code, 201) + + d = self.random_name() + self.check_equal( + self.upload("/api/files/" + d, + "pyspi_0.6.1-1.3.dsc", + "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", + "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) + + prefix = self.random_name() + task = self.post_task( + "/api/publish/" + prefix, + json={ + "Architectures": ["i386", "source"], + "SourceKind": "local", + "Sources": [{"Name": repo_name}], + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + + self.check_not_exists( + "public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") + self.check_exists("public/" + prefix + + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") + + d = self.random_name() + self.check_equal(self.upload("/api/files/" + d, + "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) + + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) + + # Update and switch MultiDist on. + task = self.put_task( + "/api/publish/" + prefix + "/bookworm", + json={ + "MultiDist": True, + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + repo_expected = { + 'AcquireByHash': False, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'bookworm', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'bookworm', + 'Prefix': prefix, + 'SkipContents': False, + 'MultiDist': True, + 'SourceKind': 'local', + 'Sources': [{'Component': 'main', 'Name': repo_name}], + 'Storage': '', + 'Suite': ''} + + all_repos = self.get("/api/publish") + self.check_equal(all_repos.status_code, 200) + self.check_in(repo_expected, all_repos.json()) + + self.check_exists( + "public/" + prefix + "/pool/bookworm/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") + self.check_not_exists( + "public/" + prefix + "/pool/bookworm/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") + + task = self.delete_task("/api/publish/" + prefix + "/bookworm") + self.check_task(task) + self.check_not_exists("public/" + prefix + "dists/") + + +class PublishConcurrentUpdateAPITestRepo(APITest): + """ + PUT /publish/:prefix/:distribution (local repos), DELETE /publish/:prefix/:distribution + """ + fixtureGpg = True + + def check(self): + repo_name = self.random_name() + self.check_equal(self.post( + "/api/repos", json={"Name": repo_name, "DefaultDistribution": "wheezy"}).status_code, 201) + + d = self.random_name() + self.check_equal( + self.upload("/api/files/" + d, + "pyspi_0.6.1-1.3.dsc", + "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", + "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) + + prefix = self.random_name() + task = self.post_task( + "/api/publish/" + prefix, + json={ + "Architectures": ["i386", "source"], + "SourceKind": "local", + "Sources": [{"Name": repo_name}], + "Signing": DefaultSigningOptions, + } + ) + self.check_task(task) + + self.check_not_exists( + "public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") + self.check_exists("public/" + prefix + + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") + + d = self.random_name() + self.check_equal(self.upload("/api/files/" + d, + "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) + + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) + + def _do_update(result, index): + resp = self.put_task( + "/api/publish/" + prefix + "/wheezy", + json={ + "AcquireByHash": True, + "Signing": DefaultSigningOptions, + } + ) + try: + self.check_equal(resp.json()['State'], TASK_SUCCEEDED) + except BaseException as e: + result[index] = e + + n_workers = 10 + worker_results = [None] * n_workers + tasks = [threading.Thread(target=_do_update, args=(worker_results, i,)) for i in range(n_workers)] + [task.start() for task in tasks] + [task.join() for task in tasks] + for result in worker_results: + if isinstance(result, BaseException): + raise result + + repo_expected = { + 'AcquireByHash': True, + 'Architectures': ['i386', 'source'], + 'Codename': '', + 'Distribution': 'wheezy', + 'Label': '', + 'Origin': '', + 'NotAutomatic': '', + 'ButAutomaticUpgrades': '', + 'Path': prefix + '/' + 'wheezy', + 'Prefix': prefix, + 'SkipContents': False, + 'MultiDist': False, + 'SourceKind': 'local', + 'Sources': [{'Component': 'main', 'Name': repo_name}], + 'Storage': '', + 'Suite': ''} + + all_repos = self.get("/api/publish") + self.check_equal(all_repos.status_code, 200) + self.check_in(repo_expected, all_repos.json()) + + self.check_exists("public/" + prefix + + "/dists/wheezy/main/binary-i386/by-hash") + + self.check_exists( + "public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") + self.check_not_exists( + "public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") + + task = self.delete_task("/api/publish/" + prefix + "/wheezy") + self.check_task(task) self.check_not_exists("public/" + prefix + "dists/") @@ -295,18 +565,18 @@ class PublishUpdateSkipCleanupAPITestRepo(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) prefix = self.random_name() - resp = self.post_task("/api/publish/" + prefix, + task = self.post_task("/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], "SourceKind": "local", "Sources": [{"Name": repo_name}], "Signing": DefaultSigningOptions, }) - - self.check_equal(resp.json()['State'], 2) + self.check_task(task) self.check_not_exists( "public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") @@ -315,7 +585,7 @@ class PublishUpdateSkipCleanupAPITestRepo(APITest): # Publish two repos, so that deleting one while skipping cleanup will # not delete the whole prefix. - resp = self.post_task("/api/publish/" + prefix, + task = self.post_task("/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], "Distribution": "otherdist", @@ -323,26 +593,28 @@ class PublishUpdateSkipCleanupAPITestRepo(APITest): "Sources": [{"Name": repo_name}], "Signing": DefaultSigningOptions, }) - - self.check_equal(resp.json()['State'], 2) + self.check_task(task) d = self.random_name() self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - self.check_equal(self.delete_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) - resp = self.put_task("/api/publish/" + prefix + "/wheezy", + task = self.put_task("/api/publish/" + prefix + "/wheezy", json={ "Signing": DefaultSigningOptions, "SkipCleanup": True, }) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'Origin': '', @@ -351,6 +623,7 @@ class PublishUpdateSkipCleanupAPITestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'local', 'Sources': [{'Component': 'main', 'Name': repo_name}], 'Storage': '', @@ -365,7 +638,8 @@ class PublishUpdateSkipCleanupAPITestRepo(APITest): self.check_exists("public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") - self.check_equal(self.delete_task("/api/publish/" + prefix + "/wheezy", params={"SkipCleanup": "1"}).json()['State'], 2) + task = self.delete_task("/api/publish/" + prefix + "/wheezy", params={"SkipCleanup": "1"}) + self.check_task(task) self.check_exists("public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") self.check_exists("public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") @@ -387,13 +661,15 @@ class PublishSwitchAPITestRepo(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) snapshot1_name = self.random_name() - self.check_equal(self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot1_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot1_name}) + self.check_task(task) prefix = self.random_name() - resp = self.post_task( + task = self.post_task( "/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], @@ -401,11 +677,12 @@ class PublishSwitchAPITestRepo(APITest): "Sources": [{"Name": snapshot1_name}], "Signing": DefaultSigningOptions, }) + self.check_task(task) - self.check_equal(resp.json()['State'], 2) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'NotAutomatic': '', @@ -414,6 +691,7 @@ class PublishSwitchAPITestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'snapshot', 'Sources': [{'Component': 'main', 'Name': snapshot1_name}], 'Storage': '', @@ -430,25 +708,29 @@ class PublishSwitchAPITestRepo(APITest): d = self.random_name() self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - self.check_equal(self.delete_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) snapshot2_name = self.random_name() - self.check_equal(self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot2_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot2_name}) + self.check_task(task) - resp = self.put_task( + task = self.put_task( "/api/publish/" + prefix + "/wheezy", json={ "Snapshots": [{"Component": "main", "Name": snapshot2_name}], "Signing": DefaultSigningOptions, "SkipContents": True, }) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'Origin': '', @@ -457,6 +739,7 @@ class PublishSwitchAPITestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': True, + 'MultiDist': False, 'SourceKind': 'snapshot', 'Sources': [{'Component': 'main', 'Name': snapshot2_name}], 'Storage': '', @@ -471,7 +754,8 @@ class PublishSwitchAPITestRepo(APITest): self.check_not_exists( "public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") - self.check_equal(self.delete_task("/api/publish/" + prefix + "/wheezy").json()['State'], 2) + task = self.delete_task("/api/publish/" + prefix + "/wheezy") + self.check_task(task) self.check_not_exists("public/" + prefix + "dists/") @@ -492,13 +776,15 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) snapshot1_name = self.random_name() - self.check_equal(self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot1_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot1_name}) + self.check_task(task) prefix = self.random_name() - resp = self.post_task("/api/publish/" + prefix, + task = self.post_task("/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], "SourceKind": "snapshot", @@ -506,10 +792,11 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): "Signing": DefaultSigningOptions, }) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'NotAutomatic': '', @@ -518,6 +805,7 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'snapshot', 'Sources': [{'Component': 'main', 'Name': snapshot1_name}], 'Storage': '', @@ -533,7 +821,7 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): # Publish two snapshots, so that deleting one while skipping cleanup will # not delete the whole prefix. - resp = self.post_task("/api/publish/" + prefix, + task = self.post_task("/api/publish/" + prefix, json={ "Architectures": ["i386", "source"], "Distribution": "otherdist", @@ -542,10 +830,11 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): "Signing": DefaultSigningOptions, }) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'otherdist', 'Label': '', 'NotAutomatic': '', @@ -554,6 +843,7 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): 'Path': prefix + '/' + 'otherdist', 'Prefix': prefix, 'SkipContents': False, + 'MultiDist': False, 'SourceKind': 'snapshot', 'Sources': [{'Component': 'main', 'Name': snapshot1_name}], 'Storage': '', @@ -565,25 +855,29 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): d = self.random_name() self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - self.check_equal(self.delete_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) snapshot2_name = self.random_name() - self.check_equal(self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot2_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot2_name}) + self.check_task(task) - resp = self.put_task("/api/publish/" + prefix + "/wheezy", + task = self.put_task("/api/publish/" + prefix + "/wheezy", json={ "Snapshots": [{"Component": "main", "Name": snapshot2_name}], "Signing": DefaultSigningOptions, "SkipCleanup": True, "SkipContents": True, }) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) repo_expected = { 'AcquireByHash': False, 'Architectures': ['i386', 'source'], + 'Codename': '', 'Distribution': 'wheezy', 'Label': '', 'Origin': '', @@ -592,6 +886,7 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): 'Path': prefix + '/' + 'wheezy', 'Prefix': prefix, 'SkipContents': True, + 'MultiDist': False, 'SourceKind': 'snapshot', 'Sources': [{'Component': 'main', 'Name': snapshot2_name}], 'Storage': '', @@ -604,6 +899,140 @@ class PublishSwitchAPISkipCleanupTestRepo(APITest): self.check_exists("public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") self.check_exists("public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") - self.check_equal(self.delete_task("/api/publish/" + prefix + "/wheezy", params={"SkipCleanup": "1"}).json()['State'], 2) + task = self.delete_task("/api/publish/" + prefix + "/wheezy", params={"SkipCleanup": "1"}) + self.check_task(task) self.check_exists("public/" + prefix + "/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb") self.check_exists("public/" + prefix + "/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc") + + +class ServePublishedListTestRepo(APITest): + """ + GET /repos + """ + + def check(self): + d = "libboost-program-options-dev_1.62.0.1" + r = "bar" + f = "libboost-program-options-dev_1.62.0.1_i386.deb" + + self.check_equal(self.upload("/api/files/" + d, f).status_code, 200) + + self.check_equal(self.post("/api/repos", json={ + "Name": r, + "Comment": "test repo", + "DefaultDistribution": r, + "DefaultComponent": "main" + }).status_code, 201) + + self.check_equal(self.post(f"/api/repos/{r}/file/{d}").status_code, 200) + + self.check_equal(self.post("/api/publish/filesystem:apiandserve:", json={ + "SourceKind": "local", + "Sources": [ + { + "Component": "main", + "Name": r + } + ], + "Distribution": r, + "Signing": { + "Skip": True + } + }).status_code, 201) + + get = self.get("/repos") + expected_content_type = "text/html; charset=utf-8" + if get.headers['content-type'] != expected_content_type: + raise Exception(f"Received content-type {get.headers['content-type']} was not: {expected_content_type}") + + excepted_content = b'
\napiandserve\n
' + if excepted_content != get.content: + raise Exception(f"Expected content {excepted_content} was not: {get.content}") + + +class ServePublishedTestRepo(APITest): + """ + GET /repos/:storage/*pkgPath + """ + + def check(self): + d = self.random_name() + r = self.random_name() + f = "libboost-program-options-dev_1.62.0.1_i386.deb" + + self.check_equal(self.upload("/api/files/" + d, f).status_code, 200) + + self.check_equal(self.post("/api/repos", json={ + "Name": r, + "Comment": "test repo", + "DefaultDistribution": r, + "DefaultComponent": "main" + }).status_code, 201) + + self.check_equal(self.post(f"/api/repos/{r}/file/{d}").status_code, 200) + + self.check_equal(self.post("/api/publish/filesystem:apiandserve:", json={ + "SourceKind": "local", + "Sources": [ + { + "Component": "main", + "Name": r + } + ], + "Distribution": r, + "Signing": { + "Skip": True + } + }).status_code, 201) + + get = self.get(f"/repos/apiandserve/pool/main/b/boost-defaults/{f}") + deb_content_types = [ + "application/x-deb", + "application/x-debian-package", + "application/vnd.debian.binary-package" + ] + if get.headers['content-type'] not in deb_content_types: + raise Exception(f"Received content-type {get.headers['content-type']} not one of expected: {deb_content_types}") + + if len(get.content) != 3428: + raise Exception(f"Expected file size 3428 bytes != {len(get.content)} bytes") + + +class ServePublishedNotFoundTestRepo(APITest): + """ + GET /repos/:storage/*pkgPath + """ + + def check(self): + d = self.random_name() + r = self.random_name() + f = "libboost-program-options-dev_1.62.0.1_i386.deb" + + self.check_equal(self.upload("/api/files/" + d, f).status_code, 200) + + self.check_equal(self.post("/api/repos", json={ + "Name": r, + "Comment": "test repo", + "DefaultDistribution": r, + "DefaultComponent": "main" + }).status_code, 201) + + self.check_equal(self.post(f"/api/repos/{r}/file/{d}").status_code, 200) + + self.check_equal(self.post("/api/publish/filesystem:apiandserve:", json={ + "SourceKind": "local", + "Sources": [ + { + "Component": "main", + "Name": r + } + ], + "Distribution": r, + "Signing": { + "Skip": True + } + }).status_code, 201) + + get = self.get("/repos/apiandserve/pool/main/b/boost-defaults/i-dont-exist") + if get.status_code != 404: + raise Exception(f"Expected status 404 != {get.status_code}") diff --git a/system/t12_api/repos.py b/system/t12_api/repos.py index 46ab03dd..8cc8e4e5 100644 --- a/system/t12_api/repos.py +++ b/system/t12_api/repos.py @@ -1,4 +1,5 @@ from api_lib import APITest + from .publish import DefaultSigningOptions @@ -40,7 +41,8 @@ class ReposAPITestCreateIndexDelete(APITest): names = [repo["Name"] for repo in repos] assert repo_name in names - self.check_equal(self.delete_task("/api/repos/" + repo_name).json()['State'], 2) + resp = self.delete_task("/api/repos/" + repo_name) + self.check_task(resp) self.check_equal(self.delete("/api/repos/" + repo_name).status_code, 404) self.check_equal(self.get("/api/repos/" + repo_name).status_code, 404) @@ -60,25 +62,32 @@ class ReposAPITestCreateIndexDelete(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz").status_code, 200) resp = self.post_task("/api/repos/" + repo_name + "/file/" + d) - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/snapshots", json={"Name": repo_name}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/snapshots", json={"Name": repo_name}) + self.check_task(task) - self.check_equal(self.post_task("/api/publish", - json={ - "SourceKind": "local", - "Sources": [{"Name": repo_name}], - "Signing": DefaultSigningOptions, - }).json()['State'], 2) + resp = self.post_task("/api/publish", + json={ + "SourceKind": "local", + "Sources": [{"Name": repo_name}], + "Signing": DefaultSigningOptions, + }) + self.check_task(resp) # repo is not deletable while it is published - self.check_equal(self.delete_task("/api/repos/" + repo_name).json()['State'], 3) - self.check_equal(self.delete_task("/api/repos/" + repo_name, params={"force": "1"}).json()['State'], 3) + task = self.delete_task("/api/repos/" + repo_name) + self.check_task_fail(task) + task = self.delete_task("/api/repos/" + repo_name, params={"force": "1"}) + self.check_task_fail(task) # drop published - self.check_equal(self.delete_task("/api/publish//" + distribution).json()['State'], 2) - self.check_equal(self.delete_task("/api/repos/" + repo_name).json()['State'], 3) - self.check_equal(self.delete_task("/api/repos/" + repo_name, params={"force": "1"}).json()['State'], 2) + task = self.delete_task("/api/publish//" + distribution) + self.check_task(task) + task = self.delete_task("/api/repos/" + repo_name) + self.check_task_fail(task) + task = self.delete_task("/api/repos/" + repo_name, params={"force": "1"}) + self.check_task(task) self.check_equal(self.get("/api/repos/" + repo_name).status_code, 404) @@ -96,7 +105,7 @@ class ReposAPITestAdd(APITest): "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz").status_code, 200) resp = self.post_task("/api/repos/" + repo_name + "/file/" + d) - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) resp = self.get("/api/tasks/" + str(resp.json()['ID']) + "/output") self.check_equal(resp.status_code, 200) @@ -124,7 +133,8 @@ class ReposAPITestAddNotFullRemove(APITest): self.check_equal(self.upload("/api/files/" + d, "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "aptly.pub").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) self.check_equal(self.get("/api/repos/" + repo_name + "/packages").json(), ['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e']) self.check_exists("upload/" + d + "/aptly.pub") @@ -144,7 +154,8 @@ class ReposAPITestAddNoRemove(APITest): self.check_equal(self.upload("/api/files/" + d, "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d, params={"noRemove": 1}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d, params={"noRemove": 1}) + self.check_task(task) self.check_equal(self.get("/api/repos/" + repo_name + "/packages").json(), ['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e']) self.check_exists("upload/" + d + "/pyspi_0.6.1-1.3.dsc") @@ -164,7 +175,7 @@ class ReposAPITestAddFile(APITest): "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) resp = self.post_task("/api/repos/" + repo_name + "/file/" + d + "/libboost-program-options-dev_1.49.0.1_i386.deb") - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) resp = self.get("/api/tasks/" + str(resp.json()['ID']) + "/output") self.check_equal(resp.status_code, 200) @@ -196,7 +207,7 @@ class ReposAPITestInclude(APITest): self.check_equal(resp.status_code, 200) resp = self.post_task("/api/repos/" + repo_name + "/include/" + d, params={"ignoreSignature": 1}) - self.check_equal(resp.json()['State'], 2) + self.check_task(resp) resp = self.get("/api/tasks/" + str(resp.json()['ID']) + "/output") self.check_equal(resp.status_code, 200) @@ -224,7 +235,8 @@ class ReposAPITestShowQuery(APITest): "libboost-program-options-dev_1.49.0.1_i386.deb", "pyspi_0.6.1-1.3.dsc", "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages", params={"q": "pyspi"}).json()), ['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89']) @@ -257,13 +269,15 @@ class ReposAPITestAddMultiple(APITest): "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d + "/pyspi_0.6.1-1.3.dsc", - params={"noRemove": 1}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d + "/pyspi_0.6.1-1.3.dsc", + params={"noRemove": 1}) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e']) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d + "/pyspi-0.6.1-1.3.stripped.dsc").json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d + "/pyspi-0.6.1-1.3.stripped.dsc") + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89']) @@ -285,34 +299,39 @@ class ReposAPITestPackagesAddDelete(APITest): "pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz", "pyspi-0.6.1-1.3.stripped.dsc").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89']) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89']) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89', - 'Psource no-such-package 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 3) + task = self.post_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89', + 'Psource no-such-package 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task_fail(task) - self.check_equal(self.delete_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.delete_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e']) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89']}) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages").json()), ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', @@ -323,10 +342,77 @@ class ReposAPITestPackagesAddDelete(APITest): self.check_equal(self.post("/api/repos", json={"Name": repo_name2, "Comment": "fun repo"}).status_code, 201) - self.check_equal(self.post_task("/api/repos/" + repo_name2 + "/packages/", - json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89', - 'Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378']}).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name2 + "/packages/", + json={"PackageRefs": ['Psource pyspi 0.6.1-1.4 f8f1daa806004e89', + 'Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378']}) + self.check_task(task) self.check_equal(sorted(self.get("/api/repos/" + repo_name2 + "/packages").json()), ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89']) + + +class ReposAPITestShowMaxVersion(APITest): + """ + POST /api/repos/:name/file/:dir, GET /api/repos/:name/packages + """ + def check(self): + repo_name = self.random_name() + + self.check_equal(self.post("/api/repos", json={"Name": repo_name, "Comment": "fun repo"}).status_code, 201) + + d = self.random_name() + self.check_equal(self.upload("/api/files/" + d, + "libboost-program-options-dev_1.49.0.1_i386.deb", + "libboost-program-options-dev_1.62.0.1_i386.deb" + ).status_code, 200) + + resp = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(resp) + + resp = self.get("/api/tasks/" + str(resp.json()['ID']) + "/output") + self.check_equal(resp.status_code, 200) + + self.check_in(b"Added: libboost-program-options-dev_1.49.0.1_i386 added, libboost-program-options-dev_1.62.0.1_i386 added", resp.content) + self.check_not_in(b"Removed: ", resp.content) + self.check_not_in(b"Failed files: ", resp.content) + self.check_not_in(b"Warnings: ", resp.content) + + self.check_equal(self.get("/api/repos/" + repo_name + "/packages?maximumVersion=1").json(), ['Pi386 libboost-program-options-dev 1.62.0.1 7760e62f99c551cb']) + + +class ReposAPITestCopyPackage(APITest): + """ + POST /api/repos/:name/copy/:src/:file + """ + def check(self): + pkg_name = "libboost-program-options-dev_1.49.0.1_i386" + + # Creating origin repo + repo1_name = self.random_name() + self.check_equal(self.post("/api/repos", json={"Name": repo1_name, "Comment": "origin repo"}).status_code, 201) + + # Uploading test package + d = self.random_name() + self.check_equal(self.upload(f"/api/files/{d}", f"{pkg_name}.deb").status_code, 200) + resp = self.post_task(f"/api/repos/{repo1_name}/file/{d}") + self.check_task(resp) + + # Creating target repo + repo2_name = self.random_name() + self.check_equal(self.post("/api/repos", json={"Name": repo2_name, "Comment": "target repo"}).status_code, 201) + + # Copy the package + resp = self.post_task(f"/api/repos/{repo2_name}/copy/{repo1_name}/{pkg_name}") + self.check_task(resp) + + # Test bad query + resp = self.post_task(f"/api/repos/{repo2_name}/copy/{repo1_name}/lalala%20%3E%3E") + self.check_task_fail(resp, expected_output="Task failed with error: unable to parse query 'lalala >>': parsing failed: unexpected token >>: expecting end of query") + + # Test non-existing package + resp = self.post_task(f"/api/repos/{repo2_name}/copy/{repo1_name}/lalala") + self.check_task_fail(resp, expected_output="Task failed with error: no package found for filter: 'lalala'") + + self.check_equal(self.get(f"/api/repos/{repo2_name}/packages").json(), + ['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378']) diff --git a/system/t12_api/snapshots.py b/system/t12_api/snapshots.py index 17e67bcf..fb6ba66f 100644 --- a/system/t12_api/snapshots.py +++ b/system/t12_api/snapshots.py @@ -1,4 +1,5 @@ from api_lib import APITest + from .publish import DefaultSigningOptions @@ -6,14 +7,15 @@ class SnapshotsAPITestCreateShowEmpty(APITest): """ GET /api/snapshots/:name, POST /api/snapshots, GET /api/snapshots/:name/packages """ + def check(self): snapshot_name = self.random_name() snapshot_desc = {'Description': 'fun snapshot', 'Name': snapshot_name} # create empty snapshot - resp = self.post_task("/api/snapshots", json=snapshot_desc) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json=snapshot_desc) + self.check_task(task) self.check_subset(snapshot_desc, self.get("/api/snapshots/" + snapshot_name).json()) self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200) @@ -25,8 +27,8 @@ class SnapshotsAPITestCreateShowEmpty(APITest): self.check_equal(self.get("/api/snapshots/" + self.random_name()).status_code, 404) # create snapshot with duplicate name - resp = self.post_task("/api/snapshots", json=snapshot_desc) - self.check_equal(resp.json()['State'], 3) + task = self.post_task("/api/snapshots", json=snapshot_desc) + self.check_task_fail(task) class SnapshotsAPITestCreateFromRefs(APITest): @@ -34,6 +36,7 @@ class SnapshotsAPITestCreateFromRefs(APITest): GET /api/snapshots/:name, POST /api/snapshots, GET /api/snapshots/:name/packages, GET /api/snapshots """ + def check(self): snapshot_name = self.random_name() snapshot_desc = {'Description': 'fun snapshot', @@ -46,8 +49,8 @@ class SnapshotsAPITestCreateFromRefs(APITest): # create empty snapshot empty_snapshot_name = self.random_name() - resp = self.post_task("/api/snapshots", json={"Name": empty_snapshot_name}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json={"Name": empty_snapshot_name}) + self.check_task(task) self.check_equal( self.get("/api/snapshots/" + empty_snapshot_name).json()['Description'], "Created as empty" ) @@ -58,14 +61,15 @@ class SnapshotsAPITestCreateFromRefs(APITest): d = self.random_name() self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) # create snapshot with empty snapshot as source and package snapshot = snapshot_desc.copy() snapshot['PackageRefs'] = ["Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378"] snapshot['SourceSnapshots'] = [empty_snapshot_name] - resp = self.post_task("/api/snapshots", json=snapshot) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json=snapshot) + self.check_task(task) snapshot.pop('SourceSnapshots') snapshot.pop('PackageRefs') resp = self.get("/api/snapshots/" + snapshot_name) @@ -78,10 +82,10 @@ class SnapshotsAPITestCreateFromRefs(APITest): self.check_equal(resp.json(), ["Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378"]) # create snapshot with unreferenced package - resp = self.post_task("/api/snapshots", json={ + task = self.post_task("/api/snapshots", json={ "Name": self.random_name(), "PackageRefs": ["Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378", "Pamd64 no-such-package 1.2 91"]}) - self.check_equal(resp.json()['State'], 3) + self.check_task_fail(task) # list snapshots resp = self.get("/api/snapshots", params={"sort": "time"}) @@ -94,13 +98,14 @@ class SnapshotsAPITestCreateFromRepo(APITest): """ POST /api/repos, POST /api/repos/:name/snapshots, GET /api/snapshots/:name """ + def check(self): repo_name = self.random_name() snapshot_name = self.random_name() self.check_equal(self.post("/api/repos", json={"Name": repo_name}).status_code, 201) - resp = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) + self.check_task(task) self.check_equal([], self.get("/api/snapshots/" + snapshot_name + "/packages", params={"format": "details"}).json()) @@ -109,10 +114,11 @@ class SnapshotsAPITestCreateFromRepo(APITest): self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - resp = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) + self.check_task(task) self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200) self.check_subset({'Architecture': 'i386', @@ -129,26 +135,27 @@ class SnapshotsAPITestCreateFromRepo(APITest): params={"format": "details", "q": "Version (> 0.6.1-1.4)"}).json()[0]) # duplicate snapshot name - resp = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) - self.check_equal(resp.json()['State'], 3) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) + self.check_task_fail(task) class SnapshotsAPITestCreateUpdate(APITest): """ POST /api/snapshots, PUT /api/snapshots/:name, GET /api/snapshots/:name """ + def check(self): snapshot_name = self.random_name() snapshot_desc = {'Description': 'fun snapshot', 'Name': snapshot_name} - resp = self.post_task("/api/snapshots", json=snapshot_desc) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json=snapshot_desc) + self.check_task(task) new_snapshot_name = self.random_name() - resp = self.put_task("/api/snapshots/" + snapshot_name, json={'Name': new_snapshot_name, + task = self.put_task("/api/snapshots/" + snapshot_name, json={'Name': new_snapshot_name, 'Description': 'New description'}) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) resp = self.get("/api/snapshots/" + new_snapshot_name) self.check_equal(resp.status_code, 200) @@ -156,9 +163,9 @@ class SnapshotsAPITestCreateUpdate(APITest): "Description": "New description"}, resp.json()) # duplicate name - resp = self.put_task("/api/snapshots/" + new_snapshot_name, json={'Name': new_snapshot_name, + task = self.put_task("/api/snapshots/" + new_snapshot_name, json={'Name': new_snapshot_name, 'Description': 'New description'}) - self.check_equal(resp.json()['State'], 3) + self.check_task_fail(task) # missing snapshot resp = self.put("/api/snapshots/" + snapshot_name, json={}) @@ -169,35 +176,40 @@ class SnapshotsAPITestCreateDelete(APITest): """ POST /api/snapshots, DELETE /api/snapshots/:name, GET /api/snapshots/:name """ + def check(self): snapshot_name = self.random_name() snapshot_desc = {'Description': 'fun snapshot', 'Name': snapshot_name} # deleting unreferenced snapshot - resp = self.post_task("/api/snapshots", json=snapshot_desc) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json=snapshot_desc) + self.check_task(task) - self.check_equal(self.delete_task("/api/snapshots/" + snapshot_name).json()['State'], 2) + task = self.delete_task("/api/snapshots/" + snapshot_name) + self.check_task(task) self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 404) # deleting referenced snapshot snap1, snap2 = self.random_name(), self.random_name() - self.check_equal(self.post_task("/api/snapshots", json={"Name": snap1}).json()['State'], 2) + task = self.post_task("/api/snapshots", json={"Name": snap1}) + self.check_task(task) self.check_equal( self.post_task( "/api/snapshots", json={"Name": snap2, "SourceSnapshots": [snap1]} ).json()['State'], 2 ) - self.check_equal(self.delete_task("/api/snapshots/" + snap1).json()['State'], 3) + task = self.delete_task("/api/snapshots/" + snap1) + self.check_task_fail(task) self.check_equal(self.get("/api/snapshots/" + snap1).status_code, 200) - self.check_equal(self.delete_task("/api/snapshots/" + snap1, params={"force": "1"}).json()['State'], 2) + task = self.delete_task("/api/snapshots/" + snap1, params={"force": "1"}) + self.check_task(task) self.check_equal(self.get("/api/snapshots/" + snap1).status_code, 404) # deleting published snapshot - resp = self.post_task( + task = self.post_task( "/api/publish", json={ "SourceKind": "snapshot", @@ -207,16 +219,19 @@ class SnapshotsAPITestCreateDelete(APITest): "Signing": DefaultSigningOptions, } ) - self.check_equal(resp.json()['State'], 2) + self.check_task(task) - self.check_equal(self.delete_task("/api/snapshots/" + snap2).json()['State'], 3) - self.check_equal(self.delete_task("/api/snapshots/" + snap2, params={"force": "1"}).json()['State'], 3) + task = self.delete_task("/api/snapshots/" + snap2) + self.check_task_fail(task) + task = self.delete_task("/api/snapshots/" + snap2, params={"force": "1"}) + self.check_task_fail(task) class SnapshotsAPITestSearch(APITest): """ POST /api/snapshots, GET /api/snapshots?sort=name, GET /api/snapshots/:name """ + def check(self): repo_name = self.random_name() @@ -227,10 +242,11 @@ class SnapshotsAPITestSearch(APITest): self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + "/file/" + d) + self.check_task(task) - resp = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name}) + self.check_task(task) resp = self.get("/api/snapshots/" + snapshot_name + "/packages", params={"q": "libboost-program-options-dev", "format": "details"}) @@ -250,6 +266,7 @@ class SnapshotsAPITestDiff(APITest): """ GET /api/snapshot/:name/diff/:name2 """ + def check(self): repos = [self.random_name() for x in range(2)] snapshots = [self.random_name() for x in range(2)] @@ -261,13 +278,14 @@ class SnapshotsAPITestDiff(APITest): self.check_equal(self.upload("/api/files/" + d, "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) - self.check_equal(self.post_task("/api/repos/" + repo_name + "/file/" + d).json()['State'], 2) + task = self.post_task("/api/repos/" + repos[-1] + "/file/" + d) + self.check_task(task) - resp = self.post_task("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshots[0]}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/repos/" + repos[-1] + '/snapshots', json={'Name': snapshots[0]}) + self.check_task(task) - resp = self.post_task("/api/snapshots", json={'Name': snapshots[1]}) - self.check_equal(resp.json()['State'], 2) + task = self.post_task("/api/snapshots", json={'Name': snapshots[1]}) + self.check_task(task) resp = self.get("/api/snapshots/" + snapshots[0] + "/diff/" + snapshots[1]) self.check_equal(resp.status_code, 200) @@ -286,3 +304,250 @@ class SnapshotsAPITestDiff(APITest): resp = self.get("/api/snapshots/" + snapshots[1] + "/diff/" + snapshots[1]) self.check_equal(resp.status_code, 200) self.check_equal(resp.json(), []) + + +class SnapshotsAPITestMerge(APITest): + """ + POST /api/snapshots, POST /api/snapshots/:name/merge, GET /api/snapshots/:name, DELETE /api/snapshots/:name + """ + + def check(self): + sources = [ + {"Description": "fun snapshot", "Name": self.random_name()} + for _ in range(2) + ] + + # create source snapshots + for source in sources: + task = self.post_task("/api/snapshots", json=source) + self.check_task(task) + + # create merge snapshot + merged_name = self.random_name() + task = self.post_task( + f"/api/snapshots/{merged_name}/merge", + json={ + "Sources": [source["Name"] for source in sources], + }, + ) + self.check_task(task) + + # check merge snapshot + resp = self.get(f"/api/snapshots/{merged_name}") + self.check_equal(resp.status_code, 200) + source_list = ", ".join(f"'{source['Name']}'" for source in sources) + self.check_subset( + { + "Name": merged_name, + "Description": f"Merged from sources: {source_list}", + }, + resp.json(), + ) + + # remove merge snapshot + task = self.delete_task(f"/api/snapshots/{merged_name}") + self.check_task(task) + + # create merge snapshot without sources + merged_name = self.random_name() + resp = self.post( + f"/api/snapshots/{merged_name}/merge", json={"Sources": []} + ) + self.check_equal(resp.status_code, 400) + self.check_equal( + resp.json()["error"], "At least one source snapshot is required" + ) + self.check_equal(self.get(f"/api/snapshots/{merged_name}").status_code, 404) + + # create merge snapshot with non-existing source + merged_name = self.random_name() + non_existing_source = self.random_name() + resp = self.post( + f"/api/snapshots/{merged_name}/merge", + json={"Sources": [non_existing_source]}, + ) + self.check_equal( + resp.json()["error"], f"snapshot with name {non_existing_source} not found" + ) + self.check_equal(resp.status_code, 404) + + self.check_equal(self.get(f"/api/snapshots/{merged_name}").status_code, 404) + + # create merge snapshot with used name + merged_name = sources[0]["Name"] + resp = self.post( + f"/api/snapshots/{merged_name}/merge", + json={"Sources": [source["Name"] for source in sources]}, + ) + self.check_equal( + resp.json()["error"], + f"unable to create snapshot: snapshot with name {sources[0]['Name']} already exists", + ) + self.check_equal(resp.status_code, 500) + + # create merge snapshot with "latest" and "no-remove" flags (should fail) + merged_name = self.random_name() + resp = self.post( + f"/api/snapshots/{merged_name}/merge", + json={ + "Sources": [source["Name"] for source in sources], + }, + params={"latest": "1", "no-remove": "1"}, + ) + self.check_equal( + resp.json()["error"], "no-remove and latest are mutually exclusive" + ) + self.check_equal(resp.status_code, 400) + + +class SnapshotsAPITestPull(APITest): + """ + POST /api/snapshots/:name/pull, POST /api/snapshots, GET /api/snapshots/:name/packages?name=:package_name + """ + + def check(self): + repo_with_libboost = self.random_name() + empty_repo = self.random_name() + snapshot_repo_with_libboost = self.random_name() + snapshot_empty_repo = self.random_name() + + # create repo with file in it and snapshot of it + self.check_equal(self.post("/api/repos", json={"Name": repo_with_libboost}).status_code, 201) + + dir_name = self.random_name() + self.check_equal(self.upload(f"/api/files/{dir_name}", + "libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200) + self.check_equal(self.post(f"/api/repos/{repo_with_libboost}/file/{dir_name}").status_code, 200) + + resp = self.post(f"/api/repos/{repo_with_libboost}/snapshots", json={'Name': snapshot_repo_with_libboost}) + self.check_equal(resp.status_code, 201) + + # create empty repo and snapshot of it + self.check_equal(self.post("/api/repos", json={"Name": empty_repo}).status_code, 201) + + resp = self.post(f"/api/repos/{empty_repo}/snapshots", json={'Name': snapshot_empty_repo}) + self.check_equal(resp.status_code, 201) + + # pull libboost from repo_with_libboost to empty_repo, save into snapshot_pull_libboost + snapshot_pull_libboost = self.random_name() + + # dry run first + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull?dry-run=1", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ], + 'Architectures': [ + 'amd64' + 'i386' + ] + }) + self.check_equal(resp.status_code, 200) + + # dry run, all-matches + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull?dry-run=1&all-matches=1", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ], + 'Architectures': [ + 'amd64' + 'i386' + ] + }) + self.check_equal(resp.status_code, 200) + + # missing argument + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + }) + self.check_equal(resp.status_code, 400) + + # dry run, emtpy architectures + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull?dry-run=1", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ], + 'Architectures': [] + }) + self.check_equal(resp.status_code, 500) + + # dry run, non-existing To + resp = self.post("/api/snapshots/asd123/pull", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ] + }) + self.check_equal(resp.status_code, 404) + + # dry run, non-existing source + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull?dry-run=1", json={ + 'Source': "asd123", + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ] + }) + self.check_equal(resp.status_code, 404) + + # snapshot pull + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull", json={ + 'Source': snapshot_repo_with_libboost, + 'Destination': snapshot_pull_libboost, + 'Queries': [ + 'libboost-program-options-dev' + ], + 'Architectures': [ + 'amd64' + 'i386' + ] + }) + self.check_equal(resp.status_code, 201) + self.check_subset({ + 'Name': snapshot_pull_libboost, + 'SourceKind': 'snapshot', + 'Description': f"Pulled into '{snapshot_empty_repo}' with '{snapshot_repo_with_libboost}' as source, pull request was: 'libboost-program-options-dev'", + }, resp.json()) + + # check that snapshot_pull_libboost contains libboost + resp = self.get(f"/api/snapshots/{snapshot_pull_libboost}/packages?name=libboost-program-options-dev") + self.check_equal(resp.status_code, 200) + + # pull from non-existing source + non_existing_source = self.random_name() + destination = self.random_name() + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull", json={ + 'Source': non_existing_source, + 'Destination': destination, + 'Queries': [ + 'Name (~ *)' + ], + 'Architectures': [ + 'all', + ] + }) + self.check_equal(resp.status_code, 404) + self.check_equal(resp.json()['error'], f"snapshot with name {non_existing_source} not found") + + # pull to non-existing snapshot + non_existing_snapshot = self.random_name() + destination = self.random_name() + resp = self.post(f"/api/snapshots/{snapshot_empty_repo}/pull", json={ + 'Source': non_existing_snapshot, + 'Destination': destination, + 'Queries': [ + 'Name (~ *)' + ], + 'Architectures': [ + 'all', + ] + }) + self.check_equal(resp.status_code, 404) + self.check_equal(resp.json()['error'], f"snapshot with name {non_existing_snapshot} not found") diff --git a/system/t12_api/storage.py b/system/t12_api/storage.py new file mode 100644 index 00000000..4f6f3ba0 --- /dev/null +++ b/system/t12_api/storage.py @@ -0,0 +1,11 @@ +from api_lib import APITest + + +class TaskAPITestSwaggerDocs(APITest): + """ + GET /docs + """ + + def check(self): + resp = self.get("/api/storage") + self.check_equal(resp.status_code, 200) diff --git a/system/t12_api/tasks.py b/system/t12_api/tasks.py index 5f184c07..8d393248 100644 --- a/system/t12_api/tasks.py +++ b/system/t12_api/tasks.py @@ -1,4 +1,5 @@ from api_lib import APITest + from .publish import DefaultSigningOptions @@ -9,8 +10,9 @@ class TaskAPITestParallelTasks(APITest): def _create_mirror(self, dist): mirror_name = self.random_name() mirror_desc = {'Name': mirror_name, - 'ArchiveURL': 'https://packagecloud.io/varnishcache/varnish30/debian/', + 'ArchiveURL': 'http://repo.aptly.info/system-tests/packagecloud.io/varnishcache/varnish30/debian/', 'Distribution': dist, + 'Architectures': ["amd64", "i386"], 'Components': ['main']} mirror_desc['IgnoreSignatures'] = True resp = self.post("/api/mirrors", json=mirror_desc) @@ -18,9 +20,9 @@ class TaskAPITestParallelTasks(APITest): resp = self.put("/api/mirrors/" + mirror_name, json=mirror_desc, params={'_async': True}) self.check_equal(resp.status_code, 202) - # check that two mirror updates cannot run at the same time + # check that two mirror updates are queuedd resp2 = self.put("/api/mirrors/" + mirror_name, json=mirror_desc, params={'_async': True}) - self.check_equal(resp2.status_code, 409) + self.check_equal(resp2.status_code, 202) return resp.json()['ID'], mirror_name @@ -47,9 +49,8 @@ class TaskAPITestParallelTasks(APITest): def _wait_for_task(self, task_id): uri = "/api/tasks/%d/wait" % int(task_id) - resp = self.get(uri) - self.check_equal(resp.status_code, 200) - self.check_equal(resp.json()['State'], 2) + task = self.get(uri) + self.check_task(task) def _wait_for_all_tasks(self): resp = self.get("/api/tasks-wait") @@ -75,7 +76,7 @@ class TaskAPITestParallelTasks(APITest): def check(self): publish_task_ids = [] mirror_task_list = [] - for mirror_dist in ['squeeze', 'jessie']: + for mirror_dist in ['squeeze', 'wheezy']: mirror_task_id, mirror_name = self._create_mirror(mirror_dist) mirror_task_list.append((mirror_task_id, mirror_name)) repo_task_id, repo_name = self._create_repo() @@ -101,6 +102,5 @@ class TaskAPITestParallelTasks(APITest): self._wait_for_all_tasks() for publish_task_id in publish_task_ids: - resp = self.get("/api/tasks/%d" % publish_task_id) - self.check_equal(resp.status_code, 200) - self.check_equal(resp.json()['State'], 2) + task = self.get("/api/tasks/%d" % publish_task_id) + self.check_task(task) diff --git a/system/t12_api/unix_socket.py b/system/t12_api/unix_socket.py index b14fe946..075ff688 100644 --- a/system/t12_api/unix_socket.py +++ b/system/t12_api/unix_socket.py @@ -6,19 +6,28 @@ import urllib.parse import urllib.request from lib import BaseTest +from testout import TestOut class UnixSocketAPITest(BaseTest): aptly_server = None socket_path = "/tmp/_aptly_test.sock" base_url = ("unix://%s" % socket_path) + aptly_out = None + debugOutput = True def prepare(self): if self.aptly_server is None: - self.aptly_server = self._start_process("aptly api serve -no-lock -listen=%s" % (self.base_url),) + UnixSocketAPITest.aptly_out = TestOut() + self.aptly_server = self._start_process("aptly api serve -no-lock -listen=%s" % (self.base_url), stdout=UnixSocketAPITest.aptly_out, stderr=UnixSocketAPITest.aptly_out) time.sleep(1) + else: + UnixSocketAPITest.aptly_out.clear() super(UnixSocketAPITest, self).prepare() + def debug_output(self): + return UnixSocketAPITest.aptly_out.get_contents() + def shutdown(self): if self.aptly_server is not None: self.aptly_server.terminate() diff --git a/system/t13_etcd/PublishDrop1TestEtcd_gold b/system/t13_etcd/PublishDrop1TestEtcd_gold new file mode 120000 index 00000000..e96691b2 --- /dev/null +++ b/system/t13_etcd/PublishDrop1TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop2TestEtcd_gold b/system/t13_etcd/PublishDrop2TestEtcd_gold new file mode 120000 index 00000000..e507a299 --- /dev/null +++ b/system/t13_etcd/PublishDrop2TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop3TestEtcd_gold b/system/t13_etcd/PublishDrop3TestEtcd_gold new file mode 120000 index 00000000..b371d5c0 --- /dev/null +++ b/system/t13_etcd/PublishDrop3TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop4TestEtcd_gold b/system/t13_etcd/PublishDrop4TestEtcd_gold new file mode 120000 index 00000000..34a46620 --- /dev/null +++ b/system/t13_etcd/PublishDrop4TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop5TestEtcd_gold b/system/t13_etcd/PublishDrop5TestEtcd_gold new file mode 120000 index 00000000..3ef73804 --- /dev/null +++ b/system/t13_etcd/PublishDrop5TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop6TestEtcd_gold b/system/t13_etcd/PublishDrop6TestEtcd_gold new file mode 120000 index 00000000..471ba43d --- /dev/null +++ b/system/t13_etcd/PublishDrop6TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop6Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop7TestEtcd_gold b/system/t13_etcd/PublishDrop7TestEtcd_gold new file mode 120000 index 00000000..a22742fc --- /dev/null +++ b/system/t13_etcd/PublishDrop7TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop7Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop8TestEtcd_gold b/system/t13_etcd/PublishDrop8TestEtcd_gold new file mode 120000 index 00000000..e20efea8 --- /dev/null +++ b/system/t13_etcd/PublishDrop8TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop8Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishDrop9TestEtcd_gold b/system/t13_etcd/PublishDrop9TestEtcd_gold new file mode 120000 index 00000000..89842314 --- /dev/null +++ b/system/t13_etcd/PublishDrop9TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishDrop9Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList1TestEtcd_gold b/system/t13_etcd/PublishList1TestEtcd_gold new file mode 120000 index 00000000..c9ff7952 --- /dev/null +++ b/system/t13_etcd/PublishList1TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList2TestEtcd_gold b/system/t13_etcd/PublishList2TestEtcd_gold new file mode 120000 index 00000000..383fe5b8 --- /dev/null +++ b/system/t13_etcd/PublishList2TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList3TestEtcd_gold b/system/t13_etcd/PublishList3TestEtcd_gold new file mode 120000 index 00000000..09ac06cf --- /dev/null +++ b/system/t13_etcd/PublishList3TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList4TestEtcd_gold b/system/t13_etcd/PublishList4TestEtcd_gold new file mode 120000 index 00000000..f5b26f53 --- /dev/null +++ b/system/t13_etcd/PublishList4TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/PublishList5TestEtcd_gold b/system/t13_etcd/PublishList5TestEtcd_gold new file mode 120000 index 00000000..eb94ffde --- /dev/null +++ b/system/t13_etcd/PublishList5TestEtcd_gold @@ -0,0 +1 @@ +../t06_publish/PublishList5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror10TestEtcd_gold b/system/t13_etcd/UpdateMirror10TestEtcd_gold new file mode 120000 index 00000000..efa730fa --- /dev/null +++ b/system/t13_etcd/UpdateMirror10TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror10Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror11TestEtcd_gold b/system/t13_etcd/UpdateMirror11TestEtcd_gold new file mode 120000 index 00000000..9fb5a6a7 --- /dev/null +++ b/system/t13_etcd/UpdateMirror11TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror11Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror12TestEtcd_gold b/system/t13_etcd/UpdateMirror12TestEtcd_gold new file mode 120000 index 00000000..653d9a72 --- /dev/null +++ b/system/t13_etcd/UpdateMirror12TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror12Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror13TestEtcd_gold b/system/t13_etcd/UpdateMirror13TestEtcd_gold new file mode 120000 index 00000000..e5f8e8cf --- /dev/null +++ b/system/t13_etcd/UpdateMirror13TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror13Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror14TestEtcd_gold b/system/t13_etcd/UpdateMirror14TestEtcd_gold new file mode 120000 index 00000000..0f7bf746 --- /dev/null +++ b/system/t13_etcd/UpdateMirror14TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror14Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror15TestEtcd_gold b/system/t13_etcd/UpdateMirror15TestEtcd_gold new file mode 120000 index 00000000..bae34dff --- /dev/null +++ b/system/t13_etcd/UpdateMirror15TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror15Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror16TestEtcd_gold b/system/t13_etcd/UpdateMirror16TestEtcd_gold new file mode 120000 index 00000000..edbe7f22 --- /dev/null +++ b/system/t13_etcd/UpdateMirror16TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror16Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror17TestEtcd_gold b/system/t13_etcd/UpdateMirror17TestEtcd_gold new file mode 120000 index 00000000..eb1abbe6 --- /dev/null +++ b/system/t13_etcd/UpdateMirror17TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror17Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror18TestEtcd_gold b/system/t13_etcd/UpdateMirror18TestEtcd_gold new file mode 120000 index 00000000..c0333d25 --- /dev/null +++ b/system/t13_etcd/UpdateMirror18TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror18Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror19TestEtcd_gold b/system/t13_etcd/UpdateMirror19TestEtcd_gold new file mode 120000 index 00000000..a178fe7b --- /dev/null +++ b/system/t13_etcd/UpdateMirror19TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror19Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror1TestEtcd_gold b/system/t13_etcd/UpdateMirror1TestEtcd_gold new file mode 120000 index 00000000..cc5035be --- /dev/null +++ b/system/t13_etcd/UpdateMirror1TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror1Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror20TestEtcd_gold b/system/t13_etcd/UpdateMirror20TestEtcd_gold new file mode 120000 index 00000000..444b11de --- /dev/null +++ b/system/t13_etcd/UpdateMirror20TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror20Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror21TestEtcd_gold b/system/t13_etcd/UpdateMirror21TestEtcd_gold new file mode 120000 index 00000000..bff753d0 --- /dev/null +++ b/system/t13_etcd/UpdateMirror21TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror21Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror22TestEtcd_gold b/system/t13_etcd/UpdateMirror22TestEtcd_gold new file mode 120000 index 00000000..54697e8c --- /dev/null +++ b/system/t13_etcd/UpdateMirror22TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror22Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror23TestEtcd_gold b/system/t13_etcd/UpdateMirror23TestEtcd_gold new file mode 120000 index 00000000..649ac10f --- /dev/null +++ b/system/t13_etcd/UpdateMirror23TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror23Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror24TestEtcd_gold b/system/t13_etcd/UpdateMirror24TestEtcd_gold new file mode 120000 index 00000000..31721619 --- /dev/null +++ b/system/t13_etcd/UpdateMirror24TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror24Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror25TestEtcd_gold b/system/t13_etcd/UpdateMirror25TestEtcd_gold new file mode 120000 index 00000000..a3a057cf --- /dev/null +++ b/system/t13_etcd/UpdateMirror25TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror25Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror2TestEtcd_gold b/system/t13_etcd/UpdateMirror2TestEtcd_gold new file mode 120000 index 00000000..9bf2cf84 --- /dev/null +++ b/system/t13_etcd/UpdateMirror2TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror2Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror3TestEtcd_gold b/system/t13_etcd/UpdateMirror3TestEtcd_gold new file mode 120000 index 00000000..3a18595b --- /dev/null +++ b/system/t13_etcd/UpdateMirror3TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror3Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror4TestEtcd_gold b/system/t13_etcd/UpdateMirror4TestEtcd_gold new file mode 120000 index 00000000..33efda8a --- /dev/null +++ b/system/t13_etcd/UpdateMirror4TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror4Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror5TestEtcd_gold b/system/t13_etcd/UpdateMirror5TestEtcd_gold new file mode 120000 index 00000000..3dd08aed --- /dev/null +++ b/system/t13_etcd/UpdateMirror5TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror5Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror6TestEtcd_gold b/system/t13_etcd/UpdateMirror6TestEtcd_gold new file mode 120000 index 00000000..3ddffa3a --- /dev/null +++ b/system/t13_etcd/UpdateMirror6TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror6Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror7TestEtcd_gold b/system/t13_etcd/UpdateMirror7TestEtcd_gold new file mode 120000 index 00000000..283a8c0c --- /dev/null +++ b/system/t13_etcd/UpdateMirror7TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror7Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror8TestEtcd_gold b/system/t13_etcd/UpdateMirror8TestEtcd_gold new file mode 120000 index 00000000..2cb66953 --- /dev/null +++ b/system/t13_etcd/UpdateMirror8TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror8Test_gold \ No newline at end of file diff --git a/system/t13_etcd/UpdateMirror9TestEtcd_gold b/system/t13_etcd/UpdateMirror9TestEtcd_gold new file mode 120000 index 00000000..4105a0d6 --- /dev/null +++ b/system/t13_etcd/UpdateMirror9TestEtcd_gold @@ -0,0 +1 @@ +../t04_mirror/UpdateMirror9Test_gold \ No newline at end of file diff --git a/system/t13_etcd/__init__.py b/system/t13_etcd/__init__.py new file mode 100644 index 00000000..d3a06023 --- /dev/null +++ b/system/t13_etcd/__init__.py @@ -0,0 +1,3 @@ +""" +Testing aptly with etcd DB +""" diff --git a/system/t13_etcd/install-etcd.sh b/system/t13_etcd/install-etcd.sh new file mode 100755 index 00000000..163a3f85 --- /dev/null +++ b/system/t13_etcd/install-etcd.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# etcd test env +ETCD_VER=v3.5.2 +DOWNLOAD_URL=https://storage.googleapis.com/etcd + +if [ ! -e /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz ]; then + curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz +fi + +mkdir /srv/etcd +tar xf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /srv/etcd --strip-components=1 diff --git a/system/t13_etcd/mirror_update.py b/system/t13_etcd/mirror_update.py new file mode 100644 index 00000000..2e4a04b1 --- /dev/null +++ b/system/t13_etcd/mirror_update.py @@ -0,0 +1,224 @@ +# reuse existing tests: +from t04_mirror.update import UpdateMirror1Test, \ + UpdateMirror2Test, \ + UpdateMirror3Test, \ + UpdateMirror4Test, \ + UpdateMirror5Test, \ + UpdateMirror6Test, \ + UpdateMirror7Test, \ + UpdateMirror8Test, \ + UpdateMirror9Test, \ + UpdateMirror10Test, \ + UpdateMirror12Test, \ + UpdateMirror13Test, \ + UpdateMirror14Test, \ + UpdateMirror17Test, \ + UpdateMirror18Test, \ + UpdateMirror19Test, \ + UpdateMirror20Test, \ + UpdateMirror21Test, \ + UpdateMirror22Test, \ + UpdateMirror23Test, \ + UpdateMirror24Test, \ + UpdateMirror25Test + + +TEST_IGNORE = ["UpdateMirror1Test", + "UpdateMirror2Test", + "UpdateMirror3Test", + "UpdateMirror4Test", + "UpdateMirror5Test", + "UpdateMirror6Test", + "UpdateMirror7Test", + "UpdateMirror8Test", + "UpdateMirror9Test", + "UpdateMirror10Test", + "UpdateMirror12Test", + "UpdateMirror13Test", + "UpdateMirror14Test", + "UpdateMirror17Test", + "UpdateMirror18Test", + "UpdateMirror19Test", + "UpdateMirror20Test", + "UpdateMirror21Test", + "UpdateMirror22Test", + "UpdateMirror23Test", + "UpdateMirror24Test", + "UpdateMirror25Test" + ] + + +class UpdateMirror1TestEtcd(UpdateMirror1Test): + """ + update mirrors: regular update + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror2TestEtcd(UpdateMirror2Test): + """ + update mirrors: no such repo + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror3TestEtcd(UpdateMirror3Test): + """ + update mirrors: wrong checksum in release file + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror4TestEtcd(UpdateMirror4Test): + """ + update mirrors: wrong checksum in release file, but ignore + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror5TestEtcd(UpdateMirror5Test): + """ + update mirrors: wrong checksum in package + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror6TestEtcd(UpdateMirror6Test): + """ + update mirrors: wrong checksum in package, but ignore + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror7TestEtcd(UpdateMirror7Test): + """ + update mirrors: flat repository + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror8TestEtcd(UpdateMirror8Test): + """ + update mirrors: with sources (already in pool) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror9TestEtcd(UpdateMirror9Test): + """ + update mirrors: flat repository + sources + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror10TestEtcd(UpdateMirror10Test): + """ + update mirrors: filtered + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror12TestEtcd(UpdateMirror12Test): + """ + update mirrors: update with udebs + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror13TestEtcd(UpdateMirror13Test): + """ + update mirrors: regular update with --skip-existing-packages option + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror14TestEtcd(UpdateMirror14Test): + """ + update mirrors: regular update with --skip-existing-packages option + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror17TestEtcd(UpdateMirror17Test): + """ + update mirrors: update for mirror but with file in pool on legacy MD5 location + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror18TestEtcd(UpdateMirror18Test): + """ + update mirrors: update for mirror but with file in pool on legacy MD5 location and disabled legacy path support + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror19TestEtcd(UpdateMirror19Test): + """ + update mirrors: correct matching of Release checksums + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror20TestEtcd(UpdateMirror20Test): + """ + update mirrors: flat repository (internal GPG implementation) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror21TestEtcd(UpdateMirror21Test): + """ + update mirrors: correct matching of Release checksums (internal pgp implementation) + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror22TestEtcd(UpdateMirror22Test): + """ + update mirrors: SHA512 checksums only + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror23TestEtcd(UpdateMirror23Test): + """ + update mirrors: update with installer + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror24TestEtcd(UpdateMirror24Test): + """ + update mirrors: update with installer with separate gpg file + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class UpdateMirror25TestEtcd(UpdateMirror25Test): + """ + update mirrors: mirror with / in distribution + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/publish_drop.py b/system/t13_etcd/publish_drop.py new file mode 100644 index 00000000..8f9f60fc --- /dev/null +++ b/system/t13_etcd/publish_drop.py @@ -0,0 +1,92 @@ +# reuse existing tests: +from t06_publish.drop import PublishDrop1Test, \ + PublishDrop2Test, \ + PublishDrop3Test, \ + PublishDrop4Test, \ + PublishDrop5Test, \ + PublishDrop6Test, \ + PublishDrop7Test, \ + PublishDrop8Test, \ + PublishDrop9Test + +TEST_IGNORE = ["PublishDrop1Test", + "PublishDrop2Test", + "PublishDrop3Test", + "PublishDrop4Test", + "PublishDrop5Test", + "PublishDrop6Test", + "PublishDrop7Test", + "PublishDrop8Test", + "PublishDrop9Test"] + + +class PublishDrop1TestEtcd(PublishDrop1Test): + """ + publish drop: existing snapshot + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop2TestEtcd(PublishDrop2Test): + """ + publish drop: under prefix + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop3TestEtcd(PublishDrop3Test): + """ + publish drop: drop one distribution + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop4TestEtcd(PublishDrop4Test): + """ + publish drop: drop one of components + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop5TestEtcd(PublishDrop5Test): + """ + publish drop: component cleanup + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop6TestEtcd(PublishDrop6Test): + """ + publish drop: no publish + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop7TestEtcd(PublishDrop7Test): + """ + publish drop: under prefix with trailing & leading slashes + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop8TestEtcd(PublishDrop8Test): + """ + publish drop: skip component cleanup + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishDrop9TestEtcd(PublishDrop9Test): + """ + publish drop: component cleanup after first cleanup skipped + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/publish_list.py b/system/t13_etcd/publish_list.py new file mode 100644 index 00000000..8825d05e --- /dev/null +++ b/system/t13_etcd/publish_list.py @@ -0,0 +1,48 @@ +# reuse existing tests: +from t06_publish.list import PublishList1Test, \ + PublishList2Test, \ + PublishList3Test, \ + PublishList4Test, \ + PublishList5Test + +TEST_IGNORE = ["PublishList1Test", "PublishList2Test", "PublishList3Test", "PublishList4Test", "PublishList5Test"] + + +class PublishList1TestEtcd(PublishList1Test): + """ + publish list: empty list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList2TestEtcd(PublishList2Test): + """ + publish list: several repos list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList3TestEtcd(PublishList3Test): + """ + publish list: several repos list, raw + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList4TestEtcd(PublishList4Test): + """ + publish list json: empty list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" + + +class PublishList5TestEtcd(PublishList5Test): + """ + publish list json: several repos list + """ + databaseType = "etcd" + databaseUrl = "127.0.0.1:2379" diff --git a/system/t13_etcd/start-etcd.sh b/system/t13_etcd/start-etcd.sh new file mode 100755 index 00000000..ae6c0a45 --- /dev/null +++ b/system/t13_etcd/start-etcd.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ -e /tmp/etcd.pid ]; then + echo etcd already running, killing.. + etcdpid=`cat /tmp/etcd.pid` + kill $etcdpid + sleep 2 +fi + +finish() +{ + if [ -n "$etcdpid" ]; then + echo terminating etcd + kill $etcdpid + fi +} +trap finish INT + +/srv/etcd/etcd --max-request-bytes '1073741824' --data-dir /tmp/etcd-data & +echo $! > /tmp/etcd.pid +etcdpid=`cat /tmp/etcd.pid` +wait $etcdpid +echo etcd terminated diff --git a/system/t13_etcd/test_release b/system/t13_etcd/test_release new file mode 120000 index 00000000..e8d20bcb --- /dev/null +++ b/system/t13_etcd/test_release @@ -0,0 +1 @@ +../t04_mirror/test_release \ No newline at end of file diff --git a/system/t13_etcd/test_release2 b/system/t13_etcd/test_release2 new file mode 120000 index 00000000..a77f3071 --- /dev/null +++ b/system/t13_etcd/test_release2 @@ -0,0 +1 @@ +../t04_mirror/test_release2 \ No newline at end of file diff --git a/system/testout.py b/system/testout.py new file mode 100644 index 00000000..f7dc134d --- /dev/null +++ b/system/testout.py @@ -0,0 +1,23 @@ +import tempfile + + +class TestOut: + def __init__(self): + self.tmp_file = tempfile.NamedTemporaryFile(delete=False) + self.read_pos = 0 + + def fileno(self): + return self.tmp_file.fileno() + + def write(self, text): + self.tmp_file.write(text.encode()) + + def get_contents(self): + self.tmp_file.seek(self.read_pos, 0) + return self.tmp_file.read().decode("utf-8") + + def close(self): + self.tmp_file.close() + + def clear(self): + self.read_pos = self.tmp_file.tell() diff --git a/task/list.go b/task/list.go index 472282b7..3636850c 100644 --- a/task/list.go +++ b/task/list.go @@ -17,6 +17,10 @@ type List struct { // resources currently used by running tasks usedResources *ResourcesSet idCounter int + + queue chan *Task + queueWg *sync.WaitGroup + queueDone chan bool } // NewList creates empty task list @@ -27,13 +31,75 @@ func NewList() *List { wgTasks: make(map[int]*sync.WaitGroup), wg: &sync.WaitGroup{}, usedResources: NewResourcesSet(), + queue: make(chan *Task, 0), + queueWg: &sync.WaitGroup{}, + queueDone: make(chan bool), } + go list.consumer() return list } +// consumer is processing the queue +func (list *List) consumer() { + for { + select { + case task := <-list.queue: + list.Lock() + { + task.State = RUNNING + } + list.Unlock() + + go func() { + retValue, err := task.process(aptly.Progress(task.output), task.detail) + + list.Lock() + { + task.processReturnValue = retValue + task.err = err + if err != nil { + task.output.Printf("Task failed with error: %v", err) + task.State = FAILED + } else { + task.output.Print("Task succeeded") + task.State = SUCCEEDED + } + + list.usedResources.Free(task.resources) + + task.wgTask.Done() + list.wg.Done() + + for _, t := range list.tasks { + if t.State == IDLE { + // check resources + blockingTasks := list.usedResources.UsedBy(t.resources) + if len(blockingTasks) == 0 { + list.usedResources.MarkInUse(task.resources, task) + list.queue <- t + break + } + } + } + } + list.Unlock() + }() + + case <-list.queueDone: + return + } + } +} + +// Stop signals the consumer to stop processing tasks and waits for it to finish +func (list *List) Stop() { + close(list.queueDone) + list.queueWg.Wait() +} + // GetTasks gets complete list of tasks func (list *List) GetTasks() []Task { - var tasks []Task + tasks := []Task{} list.Lock() for _, task := range list.tasks { tasks = append(tasks, *task) @@ -117,60 +183,29 @@ func (list *List) GetTaskReturnValueByID(ID int) (*ProcessReturnValue, error) { return task.processReturnValue, nil } -// RunTaskInBackground creates task and runs it in background. It won't be run and an error -// returned if there are running tasks which are using needed resources already. +// RunTaskInBackground creates task and runs it in background. This will block until the necessary resources +// become available. func (list *List) RunTaskInBackground(name string, resources []string, process Process) (Task, *ResourceConflictError) { list.Lock() defer list.Unlock() - tasks := list.usedResources.UsedBy(resources) - if len(tasks) > 0 { - conflictError := &ResourceConflictError{ - Tasks: tasks, - Message: "Needed resources are used by other tasks.", - } - return Task{}, conflictError - } - list.idCounter++ wgTask := &sync.WaitGroup{} - task := NewTask(process, name, list.idCounter) + task := NewTask(process, name, list.idCounter, resources, wgTask) list.tasks = append(list.tasks, task) list.wgTasks[task.ID] = wgTask - list.usedResources.MarkInUse(resources, task) list.wg.Add(1) - wgTask.Add(1) + task.wgTask.Add(1) - go func() { - - list.Lock() - { - task.State = RUNNING - } - list.Unlock() - - retValue, err := process(aptly.Progress(task.output), task.detail) - - list.Lock() - { - task.processReturnValue = retValue - if err != nil { - task.output.Printf("Task failed with error: %v", err) - task.State = FAILED - } else { - task.output.Print("Task succeeded") - task.State = SUCCEEDED - } - - list.usedResources.Free(resources) - - wgTask.Done() - list.wg.Done() - } - list.Unlock() - }() + // add task to queue for processing if resources are available + // if not, task will be queued by the consumer once resources are available + tasks := list.usedResources.UsedBy(resources) + if len(tasks) == 0 { + list.usedResources.MarkInUse(task.resources, task) + list.queue <- task + } return *task, nil } @@ -207,3 +242,14 @@ func (list *List) WaitForTaskByID(ID int) (Task, error) { wgTask.Wait() return list.GetTaskByID(ID) } + +// GetTaskError returns the Task error for a given id +func (list *List) GetTaskErrorByID(ID int) (error, error) { + task, err := list.GetTaskByID(ID) + + if err != nil { + return nil, err + } + + return task.err, nil +} diff --git a/task/list_test.go b/task/list_test.go index 297e97e2..bf5d3efc 100644 --- a/task/list_test.go +++ b/task/list_test.go @@ -50,4 +50,5 @@ func (s *ListSuite) TestList(c *check.C) { c.Check(detail, check.Equals, "Details") _, deleteErr := list.DeleteTaskByID(task.ID) c.Check(deleteErr, check.IsNil) + list.Stop() } diff --git a/task/output.go b/task/output.go index cd20ff73..f4c5e8f7 100644 --- a/task/output.go +++ b/task/output.go @@ -63,12 +63,12 @@ func (t *Output) Flush() { } // InitBar is needed for progress compatibility -func (t *Output) InitBar(count int64, isBytes bool, barType aptly.BarType) { +func (t *Output) InitBar(_ int64, _ bool, _ aptly.BarType) { // Not implemented } // InitBar publish output specific -func (t *PublishOutput) InitBar(count int64, isBytes bool, barType aptly.BarType) { +func (t *PublishOutput) InitBar(count int64, _ bool, barType aptly.BarType) { t.barType = &barType if barType == aptly.BarPublishGeneratePackageFiles { t.TotalNumberOfPackages = count @@ -88,12 +88,12 @@ func (t *PublishOutput) ShutdownBar() { } // AddBar is needed for progress compatibility -func (t *Output) AddBar(count int) { +func (t *Output) AddBar(_ int) { // Not implemented } // AddBar publish output specific -func (t *PublishOutput) AddBar(count int) { +func (t *PublishOutput) AddBar(_ int) { if t.barType != nil && *t.barType == aptly.BarPublishGeneratePackageFiles { t.RemainingNumberOfPackages-- t.Store(t) @@ -101,7 +101,7 @@ func (t *PublishOutput) AddBar(count int) { } // SetBar sets current position for progress bar -func (t *Output) SetBar(count int) { +func (t *Output) SetBar(_ int) { // Not implemented } @@ -123,5 +123,5 @@ func (t *Output) ColoredPrintf(msg string, a ...interface{}) { // PrintfStdErr does printf but in safe manner to output func (t *Output) PrintfStdErr(msg string, a ...interface{}) { - t.WriteString(msg) + t.WriteString(fmt.Sprintf(msg, a...)) } diff --git a/task/task.go b/task/task.go index 54da0e3c..02aa7037 100644 --- a/task/task.go +++ b/task/task.go @@ -1,6 +1,7 @@ package task import ( + "sync" "sync/atomic" "github.com/aptly-dev/aptly/aptly" @@ -46,20 +47,25 @@ type Task struct { detail *Detail process Process processReturnValue *ProcessReturnValue + err error Name string ID int State State + resources []string + wgTask *sync.WaitGroup } // NewTask creates new task -func NewTask(process Process, name string, ID int) *Task { +func NewTask(process Process, name string, ID int, resources []string, wgTask *sync.WaitGroup) *Task { task := &Task{ - output: NewOutput(), - detail: &Detail{}, - process: process, - Name: name, - ID: ID, - State: IDLE, + output: NewOutput(), + detail: &Detail{}, + process: process, + Name: name, + ID: ID, + State: IDLE, + resources: resources, + wgTask: wgTask, } return task } diff --git a/upload-artifacts.sh b/upload-artifacts.sh deleted file mode 100755 index 3a47db3f..00000000 --- a/upload-artifacts.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh - -set -e - -builds=build/ -packages=${builds}*.deb -folder=`mktemp -u tmp.XXXXXXXXXXXXXXX` -aptly_user="$APTLY_USER" -aptly_password="$APTLY_PASSWORD" -aptly_api="https://aptly-ops.aptly.info" -version=`make version` - -echo "Publishing version '$version' to $1..." - -for file in $packages; do - echo "Uploading $file..." - curl -fsS -X POST -F "file=@$file" -u $aptly_user:$aptly_password ${aptly_api}/api/files/$folder - echo -done - -if [ "$1" = "nightly" ]; then - if echo "$version" | grep -vq "+"; then - # skip nightly when on release tag - exit 0 - fi - - aptly_repository=aptly-nightly - aptly_published=s3:repo.aptly.info:./nightly - - echo "Adding packages to $aptly_repository..." - curl -fsS -X POST -u $aptly_user:$aptly_password ${aptly_api}/api/repos/$aptly_repository/file/$folder - echo - - echo "Updating published repo..." - curl -fsS -X PUT -H 'Content-Type: application/json' --data \ - '{"AcquireByHash": true, "Signing": {"Batch": true, "Keyring": "aptly.repo/aptly.pub", - "secretKeyring": "aptly.repo/aptly.sec", "PassphraseFile": "aptly.repo/passphrase"}}' \ - -u $aptly_user:$aptly_password ${aptly_api}/api/publish/$aptly_published - echo -fi - -if [ "$1" = "release" ]; then - aptly_repository=aptly-release - aptly_snapshot=aptly-$version - aptly_published=s3:repo.aptly.info:./squeeze - - echo "Adding packages to $aptly_repository..." - curl -fsS -X POST -u $aptly_user:$aptly_password ${aptly_api}/api/repos/$aptly_repository/file/$folder - echo - - echo "Creating snapshot $aptly_snapshot from repo $aptly_repository..." - curl -fsS -X POST -u $aptly_user:$aptly_password -H 'Content-Type: application/json' --data \ - "{\"Name\":\"$aptly_snapshot\"}" ${aptly_api}/api/repos/$aptly_repository/snapshots - echo - - echo "Switching published repo to use snapshot $aptly_snapshot..." - curl -fsS -X PUT -H 'Content-Type: application/json' --data \ - "{\"AcquireByHash\": true, \"Snapshots\": [{\"Component\": \"main\", \"Name\": \"$aptly_snapshot\"}], - \"Signing\": {\"Batch\": true, \"Keyring\": \"aptly.repo/aptly.pub\", - \"secretKeyring\": \"aptly.repo/aptly.sec\", \"PassphraseFile\": \"aptly.repo/passphrase\"}}" \ - -u $aptly_user:$aptly_password ${aptly_api}/api/publish/$aptly_published - echo -fi - -curl -fsS -X DELETE -u $aptly_user:$aptly_password ${aptly_api}/api/files/$folder -echo diff --git a/utils/checksum.go b/utils/checksum.go index 0009ea23..6e1a9515 100644 --- a/utils/checksum.go +++ b/utils/checksum.go @@ -42,7 +42,21 @@ func (cksum *ChecksumInfo) Complete() bool { return cksum.MD5 != "" && cksum.SHA1 != "" && cksum.SHA256 != "" && cksum.SHA512 != "" } -// ChecksumsForFile generates size, MD5, SHA1 & SHA256 checksums for given file +// ChecksumsForReader generates size, MD5, SHA1 & SHA256 checksums for the given +// io.Reader +func ChecksumsForReader(rd io.Reader) (ChecksumInfo, error) { + w := NewChecksumWriter() + + _, err := io.Copy(w, rd) + if err != nil { + return ChecksumInfo{}, err + } + + return w.Sum(), nil +} + +// ChecksumsForFile generates size, MD5, SHA1 & SHA256 checksums for the file at +// the given path func ChecksumsForFile(path string) (ChecksumInfo, error) { file, err := os.Open(path) if err != nil { @@ -50,14 +64,7 @@ func ChecksumsForFile(path string) (ChecksumInfo, error) { } defer file.Close() - w := NewChecksumWriter() - - _, err = io.Copy(w, file) - if err != nil { - return ChecksumInfo{}, err - } - - return w.Sum(), nil + return ChecksumsForReader(file) } // ChecksumWriter is a writer that does checksum calculation on the fly passing data diff --git a/utils/checksum_test.go b/utils/checksum_test.go index a29d602f..9e41e487 100644 --- a/utils/checksum_test.go +++ b/utils/checksum_test.go @@ -1,7 +1,6 @@ package utils import ( - "io/ioutil" "os" . "gopkg.in/check.v1" @@ -14,7 +13,7 @@ type ChecksumSuite struct { var _ = Suite(&ChecksumSuite{}) func (s *ChecksumSuite) SetUpTest(c *C) { - s.tempfile, _ = ioutil.TempFile(c.MkDir(), "aptly-test") + s.tempfile, _ = os.CreateTemp(c.MkDir(), "aptly-test") s.tempfile.WriteString(testString) } diff --git a/utils/compress_test.go b/utils/compress_test.go index 1a02b354..e5b42274 100644 --- a/utils/compress_test.go +++ b/utils/compress_test.go @@ -18,7 +18,7 @@ var _ = Suite(&CompressSuite{}) const testString = "Quick brown fox jumps over black dog and runs away... Really far away... who knows?" func (s *CompressSuite) SetUpTest(c *C) { - s.tempfile, _ = ioutil.TempFile(c.MkDir(), "aptly-test") + s.tempfile, _ = os.CreateTemp(c.MkDir(), "aptly-test") s.tempfile.WriteString(testString) } diff --git a/utils/config.go b/utils/config.go index 2b60d6c6..b25ba4ea 100644 --- a/utils/config.go +++ b/utils/config.go @@ -2,8 +2,10 @@ package utils import ( "encoding/json" + "fmt" "os" "path/filepath" + "strings" ) // ConfigStructure is structure of main configuration @@ -24,6 +26,7 @@ type ConfigStructure struct { // nolint: maligned GpgDisableVerify bool `json:"gpgDisableVerify"` GpgProvider string `json:"gpgProvider"` DownloadSourcePackages bool `json:"downloadSourcePackages"` + PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage"` SkipLegacyPool bool `json:"skipLegacyPool"` PpaDistributorID string `json:"ppaDistributorID"` PpaCodename string `json:"ppaCodename"` @@ -32,9 +35,69 @@ type ConfigStructure struct { // nolint: maligned FileSystemPublishRoots map[string]FileSystemPublishRoot `json:"FileSystemPublishEndpoints"` S3PublishRoots map[string]S3PublishRoot `json:"S3PublishEndpoints"` SwiftPublishRoots map[string]SwiftPublishRoot `json:"SwiftPublishEndpoints"` - AzurePublishRoots map[string]AzurePublishRoot `json:"AzurePublishEndpoints"` + AzurePublishRoots map[string]AzureEndpoint `json:"AzurePublishEndpoints"` AsyncAPI bool `json:"AsyncAPI"` EnableMetricsEndpoint bool `json:"enableMetricsEndpoint"` + LogLevel string `json:"logLevel"` + LogFormat string `json:"logFormat"` + ServeInAPIMode bool `json:"serveInAPIMode"` + DatabaseBackend DBConfig `json:"databaseBackend"` + EnableSwaggerEndpoint bool `json:"enableSwaggerEndpoint"` +} + +// DBConfig +type DBConfig struct { + Type string `json:"type"` + URL string `json:"url"` + DbPath string `json:"dbPath"` +} + +type LocalPoolStorage struct { + Path string `json:"path,omitempty"` +} + +type PackagePoolStorage struct { + Local *LocalPoolStorage + Azure *AzureEndpoint +} + +func (pool *PackagePoolStorage) UnmarshalJSON(data []byte) error { + var discriminator struct { + Type string `json:"type"` + } + + if err := json.Unmarshal(data, &discriminator); err != nil { + return err + } + + switch discriminator.Type { + case "azure": + pool.Azure = &AzureEndpoint{} + return json.Unmarshal(data, &pool.Azure) + case "local", "": + pool.Local = &LocalPoolStorage{} + return json.Unmarshal(data, &pool.Local) + default: + return fmt.Errorf("unknown pool storage type: %s", discriminator.Type) + } +} + +func (pool *PackagePoolStorage) MarshalJSON() ([]byte, error) { + var wrapper struct { + Type string `json:"type,omitempty"` + *LocalPoolStorage + *AzureEndpoint + } + + if pool.Azure != nil { + wrapper.Type = "azure" + wrapper.AzureEndpoint = pool.Azure + } else if pool.Local.Path != "" { + wrapper.Type = "local" + wrapper.LocalPoolStorage = pool.Local + } + + return json.Marshal(wrapper) } // FileSystemPublishRoot describes single filesystem publishing entry point @@ -46,20 +109,21 @@ type FileSystemPublishRoot struct { // S3PublishRoot describes single S3 publishing entry point type S3PublishRoot struct { - Region string `json:"region"` - Bucket string `json:"bucket"` - Endpoint string `json:"endpoint"` - AccessKeyID string `json:"awsAccessKeyID"` - SecretAccessKey string `json:"awsSecretAccessKey"` - SessionToken string `json:"awsSessionToken"` - Prefix string `json:"prefix"` - ACL string `json:"acl"` - StorageClass string `json:"storageClass"` - EncryptionMethod string `json:"encryptionMethod"` - PlusWorkaround bool `json:"plusWorkaround"` - DisableMultiDel bool `json:"disableMultiDel"` - ForceSigV2 bool `json:"forceSigV2"` - Debug bool `json:"debug"` + Region string `json:"region"` + Bucket string `json:"bucket"` + Endpoint string `json:"endpoint"` + AccessKeyID string `json:"awsAccessKeyID"` + SecretAccessKey string `json:"awsSecretAccessKey"` + SessionToken string `json:"awsSessionToken"` + Prefix string `json:"prefix"` + ACL string `json:"acl"` + StorageClass string `json:"storageClass"` + EncryptionMethod string `json:"encryptionMethod"` + PlusWorkaround bool `json:"plusWorkaround"` + DisableMultiDel bool `json:"disableMultiDel"` + ForceSigV2 bool `json:"forceSigV2"` + ForceVirtualHostedStyle bool `json:"forceVirtualHostedStyle"` + Debug bool `json:"debug"` } // SwiftPublishRoot describes single OpenStack Swift publishing entry point @@ -77,8 +141,8 @@ type SwiftPublishRoot struct { Container string `json:"container"` } -// AzurePublishRoot describes single Azure publishing entry point -type AzurePublishRoot struct { +// AzureEndpoint describes single Azure publishing entry point +type AzureEndpoint struct { AccountName string `json:"accountName"` AccountKey string `json:"accountKey"` Container string `json:"container"` @@ -102,15 +166,22 @@ var Config = ConfigStructure{ GpgDisableSign: false, GpgDisableVerify: false, DownloadSourcePackages: false, + PackagePoolStorage: PackagePoolStorage{ + Local: &LocalPoolStorage{Path: ""}, + }, SkipLegacyPool: false, PpaDistributorID: "ubuntu", PpaCodename: "", FileSystemPublishRoots: map[string]FileSystemPublishRoot{}, S3PublishRoots: map[string]S3PublishRoot{}, SwiftPublishRoots: map[string]SwiftPublishRoot{}, - AzurePublishRoots: map[string]AzurePublishRoot{}, + AzurePublishRoots: map[string]AzureEndpoint{}, AsyncAPI: false, EnableMetricsEndpoint: false, + LogLevel: "debug", + LogFormat: "default", + ServeInAPIMode: false, + EnableSwaggerEndpoint: false, } // LoadConfig loads configuration from json file @@ -141,3 +212,8 @@ func SaveConfig(filename string, config *ConfigStructure) error { _, err = f.Write(encoded) return err } + +// GetRootDir returns the RootDir with expanded ~ as home directory +func (conf *ConfigStructure) GetRootDir() string { + return strings.Replace(conf.RootDir, "~", os.Getenv("HOME"), 1) +} diff --git a/utils/config_test.go b/utils/config_test.go index 3dc523c4..badff769 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -34,6 +34,8 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { s.config.DatabaseOpenAttempts = 5 s.config.GpgProvider = "gpg" + s.config.PackagePoolStorage.Local = &LocalPoolStorage{"/tmp/aptly-pool"} + s.config.FileSystemPublishRoots = map[string]FileSystemPublishRoot{"test": { RootDir: "/opt/aptly-publish"}} @@ -44,9 +46,12 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { s.config.SwiftPublishRoots = map[string]SwiftPublishRoot{"test": { Container: "repo"}} - s.config.AzurePublishRoots = map[string]AzurePublishRoot{"test": { + s.config.AzurePublishRoots = map[string]AzureEndpoint{"test": { Container: "repo"}} + s.config.LogLevel = "info" + s.config.LogFormat = "json" + err := SaveConfig(configname, &s.config) c.Assert(err, IsNil) @@ -75,6 +80,10 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"gpgDisableVerify\": false,\n"+ " \"gpgProvider\": \"gpg\",\n"+ " \"downloadSourcePackages\": false,\n"+ + " \"packagePoolStorage\": {\n"+ + " \"type\": \"local\",\n"+ + " \"path\": \"/tmp/aptly-pool\"\n"+ + " },\n"+ " \"skipLegacyPool\": false,\n"+ " \"ppaDistributorID\": \"\",\n"+ " \"ppaCodename\": \"\",\n"+ @@ -102,6 +111,7 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " \"plusWorkaround\": false,\n"+ " \"disableMultiDel\": false,\n"+ " \"forceSigV2\": false,\n"+ + " \"forceVirtualHostedStyle\": false,\n"+ " \"debug\": false\n"+ " }\n"+ " },\n"+ @@ -130,7 +140,16 @@ func (s *ConfigSuite) TestSaveConfig(c *C) { " }\n"+ " },\n"+ " \"AsyncAPI\": false,\n"+ - " \"enableMetricsEndpoint\": false\n"+ + " \"enableMetricsEndpoint\": false,\n"+ + " \"logLevel\": \"info\",\n"+ + " \"logFormat\": \"json\",\n"+ + " \"serveInAPIMode\": false,\n"+ + " \"databaseBackend\": {\n"+ + " \"type\": \"\",\n"+ + " \"url\": \"\",\n"+ + " \"dbPath\": \"\"\n" + + " },\n"+ + " \"enableSwaggerEndpoint\": false\n" + "}") } diff --git a/utils/copyfile_test.go b/utils/copyfile_test.go new file mode 100644 index 00000000..cd2b4446 --- /dev/null +++ b/utils/copyfile_test.go @@ -0,0 +1,28 @@ +package utils + +import ( + "os" + "path/filepath" + + . "gopkg.in/check.v1" +) + +type CopyfileSuite struct { + source *os.File + dest string +} + +var _ = Suite(&CopyfileSuite{}) + +func (s *CopyfileSuite) SetUpSuite(c *C) { + s.source, _ = os.CreateTemp(c.MkDir(), "source-file") + s.dest = filepath.Join(filepath.Dir(s.source.Name()), "destination-file") +} + +func (s *CopyfileSuite) TestCopyFile(c *C) { + err := CopyFile(s.source.Name(), s.dest) + c.Check(err, Equals, nil) + + _, err = os.Stat(s.dest) + c.Check(err, Equals, nil) +} diff --git a/utils/logging.go b/utils/logging.go new file mode 100644 index 00000000..592e8f30 --- /dev/null +++ b/utils/logging.go @@ -0,0 +1,65 @@ +package utils + +import ( + "io" + "os" + "strings" + "time" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +type LogWriter struct { + Logger zerolog.Logger +} + +func (lw LogWriter) Write(bs []byte) (int, error) { + return lw.Logger.With().Str("level", "info").Logger().Write(bs) +} + +func SetupJSONLogger(levelStr string, w io.Writer) { + zerolog.MessageFieldName = "message" + zerolog.LevelFieldName = "level" + + var tsHook timestampHook + log.Logger = zerolog.New(w). + Hook(&tsHook). + Level(GetLogLevelOrDebug(levelStr)) +} + +func SetupDefaultLogger(levelStr string) { + zerolog.MessageFieldName = "message" + zerolog.LevelFieldName = "level" + + log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}). + Level(GetLogLevelOrDebug(levelStr)). + With(). + Timestamp(). + Logger() +} + +func GetLogLevelOrDebug(levelStr string) zerolog.Level { + levelStr = strings.ToLower(levelStr) + if levelStr == "warning" { + levelStr = "warn" + } + + var level zerolog.Level + + err := level.UnmarshalText([]byte(levelStr)) + if err == nil { + return level + } + + log.Warn().Msgf("Unknown log level '%s', defaulting to debug", levelStr) + return zerolog.DebugLevel +} + +type timestampHook struct{} + +func (h *timestampHook) Run(e *zerolog.Event, _ zerolog.Level, _ string) { + t := time.Now() + ts := t.Format(time.RFC3339) + e.Str("time", ts) +} diff --git a/utils/utils.go b/utils/utils.go index 598dc7c8..eb9677d3 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -4,21 +4,31 @@ package utils import ( "fmt" "os" + "strings" "golang.org/x/sys/unix" ) // DirIsAccessible verifies that directory exists and is accessible func DirIsAccessible(filename string) error { - _, err := os.Stat(filename) + fileStat, err := os.Stat(filename) if err != nil { if !os.IsNotExist(err) { return fmt.Errorf("error checking directory '%s': %s", filename, err) } } else { - if unix.Access(filename, unix.W_OK) != nil { + if fileStat.Mode().Perm() == 0000 || unix.Access(filename, unix.W_OK) != nil { return fmt.Errorf("'%s' is inaccessible, check access rights", filename) } } return nil } + +// Remove leading '/', remove '..', '$' and '`' +func SanitizePath(path string) (result string) { + result = strings.Replace(path, "..", "", -1) + result = strings.Replace(result, "$", "", -1) + result = strings.Replace(result, "`", "", -1) + result = strings.TrimLeft(result, "/") + return +} diff --git a/utils/utils_test.go b/utils/utils_test.go index 65cd6706..17c46f13 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -1,6 +1,9 @@ package utils import ( + "fmt" + "log" + "os" "testing" . "gopkg.in/check.v1" @@ -10,3 +13,28 @@ import ( func Test(t *testing.T) { TestingT(t) } + +type UtilsSuite struct { + tempfile *os.File +} + +var _ = Suite(&UtilsSuite{}) + +func (s *UtilsSuite) SetUpSuite(c *C) { + s.tempfile, _ = os.CreateTemp(c.MkDir(), "aptly-test-inaccessible") + if err := os.Chmod(s.tempfile.Name(), 0000); err != nil { + log.Fatalln(err) + } +} + +func (s *UtilsSuite) TestDirIsAccessibleNotExist(c *C) { + c.Check(DirIsAccessible("does/not/exist.invalid"), Equals, nil) +} + +func (s *UtilsSuite) TestDirIsAccessibleNotAccessible(c *C) { + accessible := DirIsAccessible(s.tempfile.Name()) + if accessible == nil { + c.Fatalf("Test dir should not be accessible: %s", s.tempfile.Name()) + } + c.Check(accessible.Error(), Equals, fmt.Errorf("'%s' is inaccessible, check access rights", s.tempfile.Name()).Error()) +}