diff --git a/.github/actions/codehealth/action.yml b/.github/actions/codehealth/action.yml new file mode 100644 index 0000000..cf7ab97 --- /dev/null +++ b/.github/actions/codehealth/action.yml @@ -0,0 +1,62 @@ +name: "Verify code health and quality" +description: "Runs build, linters, type, tests, and generates API docs to verify the code is in a good state" + +inputs: + run_tests: + description: "Whether to run tests as part of verification (default: true)" + required: false + default: "true" + +runs: + using: "composite" + steps: + - name: Lint + shell: bash + run: npm run lint + + - name: Typecheck + shell: bash + run: npm run typecheck + + - name: Type Coverage + shell: bash + run: npx type-coverage --at-least 95 + + - name: Initialize CodeQL + uses: 'github/codeql-action/init@1a818fd5f97ed0ee9a823421bd5b171add01227f' # v4.36.2 + with: + languages: ${{ matrix.language }} + # Use 'security-extended' for more comprehensive security checks + # and 'security-and-quality' to include code quality queries. + queries: security-extended,security-and-quality + + - name: Check Action Pinning + shell: bash + run: | + # Install pinact (example via go or download binary) + go install github.com/suzuki-shunsuke/pinact/cmd/pinact@latest + + # Run check on the composite action file + pinact run -check .github/actions/my-composite-action/action.yml + + - name: Build + shell: bash + run: npm run build + + - name: Unit tests + if: ${{ inputs.run_tests == 'true' }} + shell: bash + run: npm run test:unit + + - name: Integration tests + if: ${{ inputs.run_tests == 'true' }} + shell: bash + run: npm run test:integration + + - name: Generate API docs + shell: bash + run: npm run docs:api + + - name: Verify API docs are up to date + shell: bash + run: git diff --exit-code -- docs/api diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml new file mode 100644 index 0000000..0863f70 --- /dev/null +++ b/.github/actions/setup-env/action.yml @@ -0,0 +1,15 @@ +name: "Setup environment" +description: "Checks out code, sets up Node.js, and installs dependencies" + +runs: + using: "composite" + steps: + - name: Setup Node.js + uses: "actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" # v6.4.0 + with: + node-version: 24 + cache: "npm" + + - name: Install dependencies + shell: bash + run: npm ci diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f746458 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,997 @@ +name: CI + +on: + repository_dispatch: + push: + pull_request: + schedule: + - cron: "30 5 * * *" + workflow_dispatch: + inputs: + debug: + description: "Run in debug mode." + type: boolean + required: false + default: true + +env: + DEBUG: ${{ github.event.inputs.debug || false }} +permissions: + security-events: write + +jobs: + verification: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [24] + steps: + - name: Checkout repository + uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + + - name: Setup + uses: ./.github/actions/setup-env + + - name: Check code health + uses: ./.github/actions/codehealth + with: + run_tests: "false" # Run full testing with coverage below + + - name: Run tests with coverage + shell: bash + run: npm test + + - name: Upload coverage info + uses: "codecov/codecov-action@e53489f4d376d79066609109e7a95a29eb3740b1" # v7.0.0 + with: + files: ./coverage/lcov.info + fail_ci_if_error: true + + - name: Annotate coverage on changed files + uses: "jgillick/test-coverage-annotations@74fb1a9d4dbe8048001f4334c60095f65060c62a" # v1.0.3 + with: + access-token: ${{ secrets.GITHUB_TOKEN }} + coverage: ./coverage/coverage-final.json + only-changed-files: true + + # All other jobs should depend on build_binaries (if run) or check_distribute (if not needed) + list_all_versions: + runs-on: ubuntu-latest + name: List all package versions (including deps). + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot=1.3-1 + version: ${{ github.run_id }}-${{ github.run_attempt }}-list_all_versions + debug: ${{ env.DEBUG }} + - name: Verify + if: | + steps.execute.outputs.cache-hit != 'false' || + steps.execute.outputs.all-package-version-list != 'fonts-liberation2=1:2.1.5-3,gir1.2-atk-1.0=2.52.0-1build1,gir1.2-freedesktop=1.80.1-1,gir1.2-gdkpixbuf-2.0=2.42.10+dfsg-3ubuntu3.2,gir1.2-gtk-3.0=3.24.41-4ubuntu1.3,gir1.2-harfbuzz-0.0=8.3.0-2build2,gir1.2-pango-1.0=1.52.1+ds-1build1,graphviz=2.42.2-9ubuntu0.1,libann0=1.1.2+doc-9build1,libblas3=3.12.0-3build1.1,libcdt5=2.42.2-9ubuntu0.1,libcgraph6=2.42.2-9ubuntu0.1,libgts-0.7-5t64=0.7.6+darcs121130-5.2build1,libgts-bin=0.7.6+darcs121130-5.2build1,libgvc6=2.42.2-9ubuntu0.1,libgvpr2=2.42.2-9ubuntu0.1,libharfbuzz-gobject0=8.3.0-2build2,liblab-gamut1=2.42.2-9ubuntu0.1,liblapack3=3.12.0-3build1.1,libpangoxft-1.0-0=1.52.1+ds-1build1,libpathplan4=2.42.2-9ubuntu0.1,python3-cairo=1.25.1-2build2,python3-gi-cairo=3.48.2-1,python3-numpy=1:1.26.4+ds-6ubuntu1,xdot=1.3-1' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + echo "package-version-list = ${{ steps.execute.outputs.package-version-list }}" + echo "all-package-version-list = ${{ steps.execute.outputs.all-package-version-list }}" + echo "diff all-package-version-list" + diff <(echo "${{ steps.execute.outputs.all-package-version-list }}" ) <(echo "fonts-liberation2=1:2.1.5-3,gir1.2-atk-1.0=2.52.0-1build1,gir1.2-freedesktop=1.80.1-1,gir1.2-gdkpixbuf-2.0=2.42.10+dfsg-3ubuntu3.2,gir1.2-gtk-3.0=3.24.41-4ubuntu1.3,gir1.2-harfbuzz-0.0=8.3.0-2build2,gir1.2-pango-1.0=1.52.1+ds-1build1,graphviz=2.42.2-9ubuntu0.1,libann0=1.1.2+doc-9build1,libblas3=3.12.0-3build1.1,libcdt5=2.42.2-9ubuntu0.1,libcgraph6=2.42.2-9ubuntu0.1,libgts-0.7-5t64=0.7.6+darcs121130-5.2build1,libgts-bin=0.7.6+darcs121130-5.2build1,libgvc6=2.42.2-9ubuntu0.1,libgvpr2=2.42.2-9ubuntu0.1,libharfbuzz-gobject0=8.3.0-2build2,liblab-gamut1=2.42.2-9ubuntu0.1,liblapack3=3.12.0-3build1.1,libpangoxft-1.0-0=1.52.1+ds-1build1,libpathplan4=2.42.2-9ubuntu0.1,python3-cairo=1.25.1-2build2,python3-gi-cairo=3.48.2-1,python3-numpy=1:1.26.4+ds-6ubuntu1,xdot=1.3-1") + exit 1 + shell: bash + + list_versions: + runs-on: ubuntu-latest + name: List package versions. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice + version: ${{ github.run_id }}-${{ github.run_attempt }}-list_versions + debug: ${{ env.DEBUG }} + - name: Verify + if: + steps.execute.outputs.cache-hit != 'false' || steps.execute.outputs.package-version-list + != 'rolldice=1.16-1build3,xdot=1.3-1' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + echo "package-version-list = ${{ steps.execute.outputs.package-version-list }}" + echo "diff package-version-list" + diff <(echo "${{ steps.execute.outputs.package-version-list }}" ) <(echo "rolldice=1.16-1build3,xdot=1.3-1") + exit 1 + shell: bash + + standard_workflow_install: + runs-on: ubuntu-latest + name: Standard workflow install package and cache. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice + version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'false' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + standard_workflow_install_with_new_version: + needs: [standard_workflow_install] + runs-on: ubuntu-latest + name: Standard workflow packages with new version. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice + version: ${{ github.run_id }}-${{ github.run_attempt}}-standard_workflow_install_with_new_version + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'false' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + standard_workflow_restore: + needs: [standard_workflow_install] + runs-on: ubuntu-latest + name: Standard workflow restore cached packages. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice + version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'true' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + standard_workflow_restore_with_packages_out_of_order: + needs: [standard_workflow_install] + runs-on: ubuntu-latest + name: Standard workflow restore with packages out of order. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: rolldice xdot + version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'true' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + standard_workflow_add_package: + needs: [standard_workflow_install] + runs-on: ubuntu-latest + name: Standard workflow add another package. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'false' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + standard_workflow_restore_add_package: + needs: [standard_workflow_add_package] + runs-on: ubuntu-latest + name: Standard workflow restore added package. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-standard_workflow + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'true' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + no_packages: + runs-on: ubuntu-latest + name: No packages passed. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: "" + continue-on-error: true + - name: Verify + if: steps.execute.outcome == 'failure' + run: exit 0 + shell: bash + + package_not_found: + runs-on: ubuntu-latest + name: Package not found. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: package_that_doesnt_exist + continue-on-error: true + - name: Verify + if: steps.execute.outcome == 'failure' + run: exit 0 + shell: bash + + version_contains_spaces: + runs-on: ubuntu-latest + name: Version contains spaces. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot + version: 123 abc + debug: ${{ env.DEBUG }} + continue-on-error: true + - name: Verify + if: steps.execute.outcome == 'failure' + run: exit 0 + shell: bash + + regression_36: + runs-on: ubuntu-latest + name: "Reinstall existing package (regression issue #36)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libgtk-3-dev + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_36 + debug: ${{ env.DEBUG }} + + regression_37: + runs-on: ubuntu-latest + name: "Install with reported package dependencies not installed (regression issue #37)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libosmesa6-dev libgl1-mesa-dev python3-tk pandoc git-restore-mtime + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_37 + debug: ${{ env.DEBUG }} + + debug_disabled: + runs-on: ubuntu-latest + name: Debug disabled. + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: xdot + version: ${{ github.run_id }}-${{ github.run_attempt }}-list-all-package-versions + debug: ${{ env.DEBUG }} + + regression_72_1: + runs-on: ubuntu-latest + name: "Cache Java CA certs package v1 (regression issue #72)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: openjdk-11-jre + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_72 + debug: ${{ env.DEBUG }} + + regression_72_2: + runs-on: ubuntu-latest + name: "Cache Java CA certs package v2 (regression issue #72)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: default-jre + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_72 + debug: ${{ env.DEBUG }} + + regression_76: + runs-on: ubuntu-latest + name: "Cache empty archive (regression issue #76)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - run: | + sudo wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null; + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list; + sudo apt-get -qq update; + sudo apt-get install -y intel-oneapi-runtime-libs intel-oneapi-runtime-opencl; + sudo apt-get install -y opencl-headers ocl-icd-opencl-dev; + sudo apt-get install -y libsundials-dev; + - uses: ./ + with: + packages: intel-oneapi-runtime-libs + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_76 + debug: ${{ env.DEBUG }} + + regression_79: + runs-on: ubuntu-latest + name: "Tar error with libboost-dev (regression issue #79)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libboost-dev + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_79 + debug: ${{ env.DEBUG }} + + regression_81: + runs-on: ubuntu-latest + name: "Tar error with alsa-ucm-conf (regression issue #81)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: + libasound2 libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 libcups2 libdrm2 libgbm1 + libnspr4 libnss3 libxcomposite1 libxdamage1 libxfixes3 libxkbcommon0 libxrandr2 + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_81 + debug: ${{ env.DEBUG }} + + regression_84_literal_block_install: + runs-on: ubuntu-latest + name: "Install multiline package listing using literal block style (regression issue #84)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: > + xdot rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_literal_block + debug: ${{ env.DEBUG }} + + regression_84_literal_block_restore: + needs: [regression_84_literal_block_install] + runs-on: ubuntu-latest + name: "Restore multiline package listing using literal block style (regression issue #84)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_literal_block + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'true' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + regression_84_folded_block_install: + runs-on: ubuntu-latest + name: "Install multiline package listing using literal block style (regression issue #84)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: | + xdot \ + rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_folded_block + debug: ${{ env.DEBUG }} + + regression_84_folded_block_restore: + needs: [regression_84_folded_block_install] + runs-on: ubuntu-latest + name: "Restore multiline package listing using literal block style (regression issue #84)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - name: Execute + id: execute + uses: ./ + with: + packages: xdot rolldice distro-info-data + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_84_folded_block + debug: ${{ env.DEBUG }} + - name: Verify + if: steps.execute.outputs.cache-hit != 'true' + run: | + echo "cache-hit = ${{ steps.execute.outputs.cache-hit }}" + exit 1 + shell: bash + + regression_89: + runs-on: ubuntu-latest + name: "Upload logs artifact name (regression issue #89)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libgtk-3-dev:amd64 + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_89 + debug: ${{ env.DEBUG }} + + regression_98: + runs-on: ubuntu-latest + name: "Install error due to SHELLOPTS override (regression issue #98)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: git-restore-mtime libgl1-mesa-dev libosmesa6-dev pandoc + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_98 + debug: ${{ env.DEBUG }} + + regression_106_install: + runs-on: ubuntu-latest + name: "Stale apt repo not finding package on restore, install phase (regression issue #106)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libtk8.6 + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_106 + debug: ${{ env.DEBUG }} + + regression_106_restore: + needs: [regression_106_install] + runs-on: ubuntu-latest + name: "Stale apt repo not finding package on restore, restore phase (regression issue #106)." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libtk8.6 + version: ${{ github.run_id }}-${{ github.run_attempt }}-regression_106 + debug: ${{ env.DEBUG }} + + multi_arch_cache_key: + runs-on: ubuntu-latest + name: "Cache packages with multi-arch cache key." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libfuse2 + version: ${{ github.run_id }}-${{ github.run_attempt }}-multi_arch_cache_key + debug: ${{ env.DEBUG }} + + virtual_package: + runs-on: ubuntu-latest + name: "Cache virtual package." + steps: + - uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: Download build artifacts + uses: "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" # v8.0.1 + with: + pattern: cache-apt-pkgs-* + path: distribute-artifacts + - name: Setup distribute directory + shell: bash + run: | + mkdir -p distribute/X64 distribute/X86 distribute/ARM64 distribute/ARM + for artifact_dir in distribute-artifacts/cache-apt-pkgs-*; do + if [ -d "$artifact_dir" ]; then + arch=$(basename "$artifact_dir" | sed 's/cache-apt-pkgs-\([^-]*\)-.*/\1/') + echo "Copying artifacts for architecture: $arch" + cp -r "$artifact_dir"/* "distribute/$arch/" 2>/dev/null || true + fi + done + ls -la distribute/*/ || true + - uses: ./ + with: + packages: libvips + version: ${{ github.run_id }}-${{ github.run_attempt }}-virtual_package + debug: ${{ env.DEBUG }} diff --git a/.github/workflows/pub_dev_push_event.yml b/.github/workflows/pub_dev_push_event.yml deleted file mode 100644 index 3600112..0000000 --- a/.github/workflows/pub_dev_push_event.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Publish Dev Push Event -on: - workflow_dispatch: - push: - branches: - - dev - -jobs: - publish_event: - runs-on: ubuntu-latest - name: Publish dev push - steps: - - run: | - curl -i \ - -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ secrets.PUBLISH_PUSH_TOKEN }}" \ - https://api.github.com/repos/awalsh128/cache-apt-pkgs-action-ci/dispatches \ - -d '{"event_type":"dev_push"}' diff --git a/.github/workflows/pub_master_push_event.yml b/.github/workflows/pub_master_push_event.yml deleted file mode 100644 index 0339a05..0000000 --- a/.github/workflows/pub_master_push_event.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Publish Master Push Event -on: - workflow_dispatch: - push: - branches: - - master - -jobs: - publish_event: - runs-on: ubuntu-latest - name: Publish master push - steps: - - run: | - curl -i \ - -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ secrets.PUBLISH_PUSH_TOKEN }}" \ - https://api.github.com/repos/awalsh128/cache-apt-pkgs-action-ci/dispatches \ - -d '{"event_type":"master_push"}' diff --git a/.github/workflows/pub_staging_push_event.yml b/.github/workflows/pub_staging_push_event.yml deleted file mode 100644 index 681c5cb..0000000 --- a/.github/workflows/pub_staging_push_event.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Publish Staging Push Event -on: - workflow_dispatch: - push: - branches: - - staging - -jobs: - publish_event: - runs-on: ubuntu-latest - name: Publish staging push - steps: - - run: | - curl -i \ - -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ secrets.PUBLISH_PUSH_TOKEN }}" \ - https://api.github.com/repos/awalsh128/cache-apt-pkgs-action-ci/dispatches \ - -d '{"event_type":"staging_push"}' \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml deleted file mode 100644 index b44cf5f..0000000 --- a/.github/workflows/pull_request.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Pull Request -on: - pull_request: - types: [opened, synchronize] - -permissions: - contents: read - -jobs: - integrate: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version-file: "go.mod" - - - name: Build and test - run: | - go build -v ./... - go test -v ./... - - - name: Lint - uses: golangci/golangci-lint-action@v3 - with: - version: v1.52.2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8fc7e38 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Publish + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + tag: + description: "Release tag (for example v0.2.0)" + required: true + type: string + +jobs: + validate: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [24] + env: + RELEASE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || inputs.tag }} + steps: + - name: Checkout repository + uses: 'actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0' # v7.0.0 + + - name: Setup environment + uses: ./.github/actions/setup-env + + # Preflight checks (validate tag format, version consistency, etc.) + - name: Release preflight (tag/version) + run: npm run release:preflight + + - name: Check code health + uses: ./.github/actions/codehealth + + publish: + runs-on: ubuntu-latest + needs: validate + permissions: + contents: write + id-token: write + steps: + - name: Checkout repository + uses: 'actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0' # v7.0.0 + + - name: Setup environment + uses: ./.github/actions/setup-env + + - name: Build package + run: npm run build + + - name: Resolve npm dist-tag + run: | + TAG="${{ github.ref_type == 'tag' && github.ref_name || inputs.tag }}" + if [[ "$TAG" == *-* ]]; then + echo "NPM_DIST_TAG=next" >> "$GITHUB_ENV" + else + echo "NPM_DIST_TAG=latest" >> "$GITHUB_ENV" + fi + + - name: Generate API docs + run: npm run docs:api + + - name: Publish to npm + run: npm publish --access public --provenance --tag "$NPM_DIST_TAG" + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create GitHub release + uses: 'softprops/action-gh-release@2bb465e97f322d3cb2a965294d483e0d26a67aa9' # v3.0.1 + with: + generate_release_notes: true + tag_name: ${{ github.ref_type == 'tag' && github.ref_name || inputs.tag }} + + - name: Setup Pages + uses: 'actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d' # v6.0.0 + + - name: Upload Pages artifact + uses: 'actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9' # v5.0.0 + with: + path: docs/api + + - name: Deploy to GitHub Pages + id: deployment + uses: 'actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128' # v5.0.0 diff --git a/.gitignore b/.gitignore index cf14f3f..a87e6a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -src/cmd/apt_query/apt_query* \ No newline at end of file +node_modules/ +coverage/ +target/ \ No newline at end of file diff --git a/README.md b/README.md index 81369da..a8fc649 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ This action allows caching of Advanced Package Tool (APT) package dependencies to improve workflow execution time instead of installing the packages on every run. +> [!NOTE] +> The open source projects that I maintain are a labor of love. If you find this useful and want to support open source, **please consider donating and [Buy Me a Coffe](http://buymeacoffee.com/awalsh128)**. + +> [!NOTE] +> Version 2 of the action is now available! See [Version 2 FAQ](V2_FAQ.MD) for more information. + > [!IMPORTANT] > Looking for co-maintainers to help review changes, and investigate issues. I haven't had as much time to stay on top of this action as I would like to and want to make sure it is still responsive and reliable for the community. If you are interested, please reach out. @@ -43,6 +49,58 @@ There are three kinds of version labels you can use. - `package-version-list` - The main requested packages and versions that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. \=,\=\,...). - `all-package-version-list` - All the pulled in packages and versions, including dependencies, that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. \=,\=\,...). +### Security Compliance + +This action runs as a JavaScript GitHub Action on the `node20` runtime and does not require consumers to run `npm install` in their workflow in order to use it. The implementation dependency surface is limited to the action runtime packages declared in `package.json`: `@actions/cache`, `@actions/core`, `tar`, `winston`, and `ts-apt`. + +For workflows with stricter compliance requirements, the main security characteristics are: + +- `packages` should be treated as an allowlisted input in your workflow. Prefer explicit package names and versions where reproducibility matters. +- `version` can be used as a cache namespace so you can intentionally rotate caches when package policy or runner baselines change. +- `empty_packages_behavior` can be left at the default `error` to fail closed when an expected package list is missing. +- `execute_install_scripts` is disabled by default. Enable it only when required, because Debian maintainer scripts execute arbitrary package-provided shell logic during restore. +- `debug` is disabled by default. Enable it only for investigation and review logs before sharing them outside your organization. + +#### Features + +Security-relevant action features: + +- Package inputs are normalized before cache lookup, which reduces accidental cache divergence from ordering, commas, backslashes, or duplicate whitespace in the package list. +- Unpinned package names are resolved to concrete package versions before the cache key is generated, which improves traceability of what was actually cached for a run. +- Cache keys are derived from the normalized package set, the user-provided `version`, and the runner architecture, which helps isolate caches across package changes and incompatible platforms. +- The action rejects invalid boolean inputs and rejects `version` values containing spaces, reducing ambiguous workflow configuration. +- When creating archives, the action records installed package manifests and only archives existing files and symlinks from installed packages, plus maintainer scripts when present. +- The `package-version-list` and `all-package-version-list` outputs can be captured by downstream workflow steps for audit logs, attestation inputs, or compliance reporting. + +#### Usage Recommendations + +For GitHub Actions workflow hardening, prefer the following controls around this action: + +- Pin this action to a major version you trust, or to a full commit SHA for stricter supply chain control. +- Use the minimum required workflow `permissions` instead of broad defaults. +- Run on GitHub-hosted or otherwise trusted runners with controlled APT sources. +- Limit who can modify workflow files and package lists through branch protection and pull request review. +- Review whether cached APT contents are acceptable for your repository's cache retention policy and data handling requirements. + +Example hardened usage: + +```yaml +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: awalsh128/cache-apt-pkgs-action@v2 + with: + packages: curl=8.5.0-2ubuntu10.6 jq=1.7.1-3build1 + version: ubuntu-24.04-v1 + empty_packages_behavior: error + execute_install_scripts: false +``` + ### Cache scopes The cache is scoped to the packages given and the branch. The default branch cache is available to other branches. @@ -78,7 +136,6 @@ jobs: ``` ```yaml - --- install_doxygen_deps: runs-on: ubuntu-latest diff --git a/V2_FAQ.MD b/V2_FAQ.MD new file mode 100644 index 0000000..b64ddd0 --- /dev/null +++ b/V2_FAQ.MD @@ -0,0 +1,27 @@ +# cache-apt-pkgs-action - Version 2 FAQ + +## Why did you create a new version + +### Bash Scripts + +Bash shell scripting grew in complexity and became very unreadable. The action needed higher level language idioms like array and map handling, complex pattern matching, and complex text processing. + +### Language Choice + +Languages like Python, Go, Rust, etc. have performance and writeability trade offs that would greatly improve this action, but ultimately Typescript was chosen because: + +- it is the most performant and well supported for GitHub actions; +- native strongly types libraries for action args and actions like caching; +- provides a balance of code comprehension for contributors and performance; and +- allows for better integration, CI, regression testing, and release workflows. + +## Where did all the APT functionality go? + +Since this has been a complex part of the codebase, I decided to separate the concern as its own library. This can now be found in [npm/ts-apt](https://www.npmjs.com/package/ts-apt). For ease of use there is an option to bring in the workspace for inline source so it can be debugged and then committed to the [ts-apt](http://github.com/awalsh128/ts-apt) repository. + +## How do I start using this? + +> [!IMPORTANT] +> This is still in beta so use at your own risk! + +For now you can use the `v2.*` release tags (pinning also supported). Once this version has had time to soak it will be released as the latest. `v1.*` will still get updates but in maintenance mode. diff --git a/action.yml b/action.yml index 81f6870..7e4fe5b 100644 --- a/action.yml +++ b/action.yml @@ -1,23 +1,23 @@ -name: 'Cache APT Packages' -description: 'Install APT based packages and cache them for future runs.' +name: "Cache APT Packages" +description: "Install APT based packages and cache them for future runs." author: awalsh128 branding: - icon: 'hard-drive' - color: 'green' + icon: "hard-drive" + color: "green" inputs: packages: - description: 'Space delimited list of packages to install. Version can be specified optionally using APT command syntax of = (e.g. xdot=1.2-2).' + description: "Space delimited list of packages to install. Version can be specified optionally using APT command syntax of = (e.g. xdot=1.2-2)." required: true - default: '' + default: "" version: - description: 'Version of cache to load. Each version will have its own cache. Note, all characters except spaces are allowed.' + description: "Version of cache to load. Each version will have its own cache. Note, all characters except spaces are allowed." required: false - default: '' + default: "" execute_install_scripts: - description: 'Execute Debian package pre and post install script upon restore. See README.md caveats for more information.' + description: "Execute Debian package pre and post install script upon restore. See README.md caveats for more information." required: false - default: 'false' + default: "false" empty_packages_behavior: description: > Desired behavior when the provided package list is empty. @@ -27,94 +27,20 @@ inputs: warn: Output a warning without failing the action ignore: Proceed silently without warnings or errors required: false - default: 'error' - refresh: - description: 'OBSOLETE: Refresh is not used by the action, use version instead.' - deprecationMessage: 'Refresh is not used by the action, use version instead.' + default: "error" debug: - description: 'Enable debugging when there are issues with action. Minor performance penalty.' + description: "Enable debugging when there are issues with action. Minor performance penalty." required: false - default: 'false' + default: "false" outputs: cache-hit: - description: 'A boolean value to indicate a cache was found for the packages requested.' - # This compound expression is needed because lhs can be empty. - # Need to output true and false instead of true and nothing. - value: ${{ steps.load-cache.outputs.cache-hit || false }} + description: "A boolean value to indicate a cache was found for the packages requested." package-version-list: - description: 'The main requested packages and versions that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. ::).' - value: ${{ steps.post-cache.outputs.package-version-list }} + description: "The main requested packages and versions that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. ::)." all-package-version-list: - description: 'All the pulled in packages and versions, including dependencies, that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. ::).' - value: ${{ steps.post-cache.outputs.all-package-version-list }} + description: "All the pulled in packages and versions, including dependencies, that are installed. Represented as a comma delimited list with equals delimit on the package version (i.e. ::)." runs: - using: "composite" - steps: - - id: pre-cache - run: | - ${GITHUB_ACTION_PATH}/pre_cache_action.sh \ - ~/cache-apt-pkgs \ - "$VERSION" \ - "$EXEC_INSTALL_SCRIPTS" \ - "$DEBUG" \ - "$PACKAGES" - if [ -f ~/cache-apt-pkgs/cache_key.md5 ]; then - echo "CACHE_KEY=$(cat ~/cache-apt-pkgs/cache_key.md5)" >> $GITHUB_ENV - else - echo "CACHE_KEY=" >> $GITHUB_ENV - fi - shell: bash - env: - VERSION: "${{ inputs.version }}" - EXEC_INSTALL_SCRIPTS: "${{ inputs.execute_install_scripts }}" - EMPTY_PACKAGES_BEHAVIOR: "${{ inputs.empty_packages_behavior }}" - DEBUG: "${{ inputs.debug }}" - PACKAGES: "${{ inputs.packages }}" - - - id: load-cache - if: ${{ env.CACHE_KEY }} - uses: actions/cache/restore@v4 - with: - path: ~/cache-apt-pkgs - key: cache-apt-pkgs_${{ env.CACHE_KEY }} - - - id: post-cache - if: ${{ env.CACHE_KEY }} - run: | - ${GITHUB_ACTION_PATH}/post_cache_action.sh \ - ~/cache-apt-pkgs \ - / \ - "$CACHE_HIT" \ - "$EXEC_INSTALL_SCRIPTS" \ - "$DEBUG" \ - "$PACKAGES" - function create_list { local list=$(cat ~/cache-apt-pkgs/manifest_${1}.log | tr '\n' ','); echo ${list:0:-1}; }; - echo "package-version-list=$(create_list main)" >> $GITHUB_OUTPUT - echo "all-package-version-list=$(create_list all)" >> $GITHUB_OUTPUT - shell: bash - env: - CACHE_HIT: "${{ steps.load-cache.outputs.cache-hit }}" - EXEC_INSTALL_SCRIPTS: "${{ inputs.execute_install_scripts }}" - DEBUG: "${{ inputs.debug }}" - PACKAGES: "${{ inputs.packages }}" - - - id: upload-logs - if: ${{ env.CACHE_KEY && inputs.debug == 'true' }} - uses: actions/upload-artifact@v4 - with: - name: cache-apt-pkgs-logs_${{ env.CACHE_KEY }} - path: ~/cache-apt-pkgs/*.log - - - id: save-cache - if: ${{ env.CACHE_KEY && ! steps.load-cache.outputs.cache-hit }} - uses: actions/cache/save@v4 - with: - path: ~/cache-apt-pkgs - key: ${{ steps.load-cache.outputs.cache-primary-key }} - - - id: clean-cache - run: | - rm -rf ~/cache-apt-pkgs - shell: bash + using: "node20" + main: "dist/index.js" diff --git a/apt_query-arm64 b/apt_query-arm64 deleted file mode 100755 index b0bfb8f..0000000 Binary files a/apt_query-arm64 and /dev/null differ diff --git a/apt_query-x86 b/apt_query-x86 deleted file mode 100755 index 70ec608..0000000 Binary files a/apt_query-x86 and /dev/null differ diff --git a/dev_scripts/lib.sh b/dev_scripts/lib.sh new file mode 100755 index 0000000..2c5abe2 --- /dev/null +++ b/dev_scripts/lib.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +LIB_EXIT_CODE=99 + +####################################### +# Clone a repository and change directory to it. +# Arguments: +# The repository name. +# The directory containing repository to rebase. +# The tag to clone from, otherwise use HEAD. +# Returns: +# 0 if directory was changed, non-zero on error. +####################################### +function clone_repo { + repo_name="${1}" + repo_url="https://github.com/awalsh128/${repo_name}" + repo_dir="${2}" + repo_dir_parent=$(realpath "$(dirname "${repo_dir}")") + wd=$(pwd) + [[ -d ${repo_dir} ]] && rm -fr "${repo_dir}" + cd "${repo_dir_parent}" || exit "${LIB_EXIT_CODE}" + if [[ -n "${3}" ]]; then + git clone -b "${3}" "${repo_url}" + else + git clone "${repo_url}" + fi + cd "${wd}" || exit "${LIB_EXIT_CODE}" +} + +####################################### +# Clone a repository and change directory to it. +# Arguments: +# The repository name. +# The tag to clone from, otherwise use HEAD. +# Returns: +# 0 if directory was changed, non-zero on error. +####################################### +function clone_repo_and_cd { + clone_repo "${1}" "/tmp/${1}" "${2}" + cd "/tmp/${1}" || exit "${LIB_EXIT_CODE}" +} + +####################################### +# Yes or no prompt. +# Arguments: +# Message to display at prompt. +# Returns: +# None +####################################### +function confirm_prompt { + while true; do + read -rp "${1} [Y|n] " response + case ${response} in + [Yy]*) break;; + [Nn]*) exit;; + *) echo "Invalid option selected.";; + esac + done +} + +####################################### +# Validate argument and exit if invalid. +# Arguments: +# Argument to validate. +# Message to display on error. +# Help message. +# Returns: +# None +####################################### +function validate_arg { + if [[ -n "${1}" ]] || [[ -z "${1}" ]]; then + printf "error: %s\n%s\n" "${2}" "${3}" + exit 1 + fi +} + +####################################### +# Print out command usage. +# Arguments: +# Name of command. +# Parameters +# Returns: +# Usage message. +####################################### +function usage { + echo "usage: $(basename "${1}") ${2}" +} \ No newline at end of file diff --git a/dev_scripts/switch_tsapt_local.sh b/dev_scripts/switch_tsapt_local.sh new file mode 100644 index 0000000..c524347 --- /dev/null +++ b/dev_scripts/switch_tsapt_local.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck disable=SC1090 +source "${SCRIPT_DIR}/lib.sh" + +PACKAGE_PATH="${SCRIPT_DIR}/../package.json" +LOCAL_VAL="../../ts-apt" +NPM_VAL="^ts-apt/$(npm view ts-apt version 2> /dev/null | tr -d '\n')" + +if ! grep -q "\"ts-apt\": \"${LOCAL_VAL}\"," "${PACKAGE_PATH}"; then + echo "Switching ts-apt dependency to local path '${LOCAL_VAL}'..." + if [[ ! -d "${SCRIPT_DIR}/../ts-apt" ]]; then + echo "Local ts-apt path '${LOCAL_VAL}' does not exist. Checking out..." + clone_repo "ts-apt" "${SCRIPT_DIR}/../ts-apt" + fi + sed -i "s#\"ts-apt\": \".*\",#\"ts-apt\": \"${LOCAL_VAL}\",#" "${PACKAGE_PATH}" +else + echo "Switching ts-apt dependency to NPM version '${NPM_VAL}'..." + sed -i "s#\"ts-apt\": \".*\",#\"ts-apt\": \"${NPM_VAL}\",#" "${PACKAGE_PATH}" +fi \ No newline at end of file diff --git a/dist/action.d.ts b/dist/action.d.ts new file mode 100644 index 0000000..27e3984 --- /dev/null +++ b/dist/action.d.ts @@ -0,0 +1,53 @@ +import { type PackageManager, type CommandRunner } from "../../ts-apt/dist/index.js"; +import winston from "winston"; +type TarModule = typeof import("tar"); +type EmptyPackageBehavior = "error" | "warn" | "ignore"; +interface PackageName { + readonly name: string; + readonly version?: string; + readonly distro?: string; + serialize(): string; +} +export interface ActionInputs { + readonly packages: string; + readonly version: string; + readonly executeInstallScripts: boolean; + readonly emptyPackagesBehavior: EmptyPackageBehavior; + readonly debug: boolean; +} +export interface ActionOutputs { + readonly cacheHit: boolean; + readonly packageVersionList: string; + readonly allPackageVersionList: string; +} +export declare class ActionPackageName implements PackageName { + readonly name: string; + readonly version?: string | undefined; + constructor(name: string, version?: string | undefined); + serialize(): string; +} +export declare function parseBoolean(value: string, fieldName: string): boolean; +export declare function normalizeInputPackages(inputPackages: string): string[]; +export declare class ActionRunner { + private readonly commandRunner; + private readonly tar; + private readonly logger; + constructor(commandRunner: CommandRunner, tarModule: TarModule, logger: winston.Logger); + parseBoolean(value: string, fieldName: string): boolean; + normalizeInputPackages(inputPackages: string): string[]; + resolvePackageVersion(packageManager: PackageManager, packageName: string): Promise; + normalizePackagesWithVersions(packageManager: PackageManager, inputPackages: string): Promise; + validateEmptyPackages(behavior: EmptyPackageBehavior, packages: string[]): void; + getCacheRoot(): string; + getCacheKey(normalizedPackages: string[], version: string): Promise; + findInstallScript(packageName: string, extension: "preinst" | "postinst", root: string): string | undefined; + tarRelativePath(filePath: string): string; + buildFileListForPackage(packageManager: PackageManager, packageName: string): Promise; + updateAptLists(packageManager: PackageManager): Promise; + packageSpecifierToName(packageSpecifier: string): string; + installAndCachePackages(cacheDir: string, packages: string[], packageManager: PackageManager): Promise; + restorePackages(cacheDir: string, executeInstallScripts: boolean): Promise; + runAction(inputs: ActionInputs): Promise; +} +export declare function runAction(inputs: ActionInputs, logger: winston.Logger): Promise; +export {}; diff --git a/dist/action.js b/dist/action.js new file mode 100644 index 0000000..73141c7 --- /dev/null +++ b/dist/action.js @@ -0,0 +1,265 @@ +import * as cache from "@actions/cache"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { createPackageManager, DefaultCommandRunner, } from "../../ts-apt/dist/index.js"; +import { isAptListsFresh } from "./io.js"; +import { readManifestAsCsv, writeManifest } from "./manifest.js"; +import * as tar from "tar"; +const FORCE_UPDATE_INCREMENT = "3"; +const CACHE_DIRNAME = "cache-apt-pkgs"; +const CACHE_PREFIX = "cache-apt-pkgs_"; +export class ActionPackageName { + name; + version; + constructor(name, version) { + this.name = name; + this.version = version; + } + serialize() { + return this.version ? `${this.name}=${this.version}` : this.name; + } +} +function toPackageName(packageSpecifier) { + const [name, version] = packageSpecifier.split("="); + if (!name) { + throw new Error("Package name cannot be empty."); + } + return new ActionPackageName(name, version); +} +export function parseBoolean(value, fieldName) { + if (value === "true") { + return true; + } + if (value === "false") { + return false; + } + throw new Error(`${fieldName} value '${value}' must be either true or false.`); +} +export function normalizeInputPackages(inputPackages) { + return inputPackages + .replace(/[,\\]/g, " ") + .replace(/\s+/g, " ") + .trim() + .split(" ") + .map((part) => part.trim()) + .filter(Boolean) + .sort((a, b) => a.localeCompare(b)); +} +export class ActionRunner { + commandRunner; + tar; + logger; + constructor(commandRunner, tarModule, logger) { + this.commandRunner = commandRunner; + this.tar = tarModule; + this.logger = logger; + } + parseBoolean(value, fieldName) { + return parseBoolean(value, fieldName); + } + normalizeInputPackages(inputPackages) { + return normalizeInputPackages(inputPackages); + } + async resolvePackageVersion(packageManager, packageName) { + const packageInfo = await packageManager.getPackageInfo([ + toPackageName(packageName), + ]); + const version = packageInfo[0]?.version; + if (!version) { + throw new Error(`Unable to resolve package version for '${packageName}'.`); + } + return version; + } + async normalizePackagesWithVersions(packageManager, inputPackages) { + const raw = this.normalizeInputPackages(inputPackages); + const packages = await Promise.all(raw.map(async (pkg) => { + if (pkg.includes("=")) { + return pkg; + } + return `${pkg}=${await this.resolvePackageVersion(packageManager, pkg)}`; + })); + return packages.sort((a, b) => a.localeCompare(b)); + } + validateEmptyPackages(behavior, packages) { + if (packages.length > 0) { + return; + } + if (behavior === "ignore") { + return; + } + if (behavior === "warn") { + process.stdout.write("::warning::Packages argument is empty.\n"); + return; + } + throw new Error("Packages argument is empty."); + } + getCacheRoot() { + return path.join(os.homedir(), CACHE_DIRNAME); + } + async getCacheKey(normalizedPackages, version) { + const architecture = (await this.commandRunner.run("arch")).stdout.trim(); + let value = `${normalizedPackages.join(" ")} @ ${version} ${FORCE_UPDATE_INCREMENT}`; + if (architecture !== "x86_64") { + value = `${value} ${architecture}`; + } + const hash = crypto.createHash("md5").update(value).digest("hex"); + return `${CACHE_PREFIX}${hash}`; + } + findInstallScript(packageName, extension, root) { + const scriptsDir = path.join(root, "var", "lib", "dpkg", "info"); + if (!fs.existsSync(scriptsDir)) { + return undefined; + } + const pattern = new RegExp(`^${packageName}(:.*)?\\.${extension}$`); + const matches = fs + .readdirSync(scriptsDir) + .filter((entry) => pattern.test(entry)) + .sort((a, b) => a.localeCompare(b)); + const candidate = matches[0]; + if (!candidate) { + return undefined; + } + return path.join(scriptsDir, candidate); + } + tarRelativePath(filePath) { + return filePath.startsWith("/") ? filePath.slice(1) : filePath; + } + async buildFileListForPackage(packageManager, packageName) { + const files = (await packageManager.listInstalledFiles(toPackageName(packageName))) + .filter((filePath) => { + if (!fs.existsSync(filePath)) { + return false; + } + const stat = fs.lstatSync(filePath); + return stat.isFile() || stat.isSymbolicLink(); + }) + .map(this.tarRelativePath); + const preinst = this.findInstallScript(packageName, "preinst", "/"); + const postinst = this.findInstallScript(packageName, "postinst", "/"); + if (preinst) { + files.push(this.tarRelativePath(preinst)); + } + if (postinst) { + files.push(this.tarRelativePath(postinst)); + } + return Array.from(new Set(files)).sort((a, b) => a.localeCompare(b)); + } + async updateAptLists(packageManager) { + if (isAptListsFresh()) { + return; + } + await packageManager.update(); + } + packageSpecifierToName(packageSpecifier) { + return packageSpecifier.split("=")[0] ?? packageSpecifier; + } + async installAndCachePackages(cacheDir, packages, packageManager) { + await this.updateAptLists(packageManager); + writeManifest(path.join(cacheDir, "manifest_main.log"), packages); + const installedPackages = await packageManager.install(packages.map(toPackageName)); + const manifestAll = []; + for (const pkg of installedPackages) { + const packageName = pkg.name; + const packageVersion = pkg.version; + if (!packageName || !packageVersion) { + continue; + } + const archivePath = path.join(cacheDir, `${packageName}=${packageVersion}.tar`); + if (!fs.existsSync(archivePath)) { + const filesToArchive = await this.buildFileListForPackage(packageManager, packageName); + await this.tar.create({ + cwd: "/", + file: archivePath, + portable: false, + preservePaths: false, + follow: false, + noDirRecurse: false, + }, filesToArchive); + } + manifestAll.push(`${packageName}=${packageVersion}`); + } + writeManifest(path.join(cacheDir, "manifest_all.log"), manifestAll); + } + async restorePackages(cacheDir, executeInstallScripts) { + const archives = fs + .readdirSync(cacheDir) + .filter((entry) => entry.endsWith(".tar")) + .sort((a, b) => a.localeCompare(b)); + for (const archive of archives) { + const archivePath = path.join(cacheDir, archive); + await this.tar.extract({ + cwd: "/", + file: archivePath, + preservePaths: true, + }); + if (!executeInstallScripts) { + continue; + } + const packageName = archive.split("=")[0] ?? ""; + if (!packageName) { + continue; + } + const preinst = this.findInstallScript(packageName, "preinst", "/"); + if (preinst) { + this.logger.info(`Running pre-install script for ${packageName}`); + await this.commandRunner.run("sudo", ["sh", "-x", preinst, "install"]); + } + const postinst = this.findInstallScript(packageName, "postinst", "/"); + if (postinst) { + this.logger.info(`Running post-install script for ${packageName}`); + await this.commandRunner.run("sudo", [ + "sh", + "-x", + postinst, + "configure", + ]); + } + } + } + async runAction(inputs) { + if (/\s/.test(inputs.version)) { + throw new Error(`Version value '${inputs.version}' cannot contain spaces.`); + } + const packageInfoManager = await createPackageManager(false); + const normalizedPackages = await this.normalizePackagesWithVersions(packageInfoManager, inputs.packages); + this.validateEmptyPackages(inputs.emptyPackagesBehavior, normalizedPackages); + const cacheDir = this.getCacheRoot(); + fs.mkdirSync(cacheDir, { recursive: true }); + if (normalizedPackages.length === 0) { + writeManifest(path.join(cacheDir, "manifest_main.log"), []); + writeManifest(path.join(cacheDir, "manifest_all.log"), []); + return { + cacheHit: false, + packageVersionList: "", + allPackageVersionList: "", + }; + } + const key = await this.getCacheKey(normalizedPackages, inputs.version); + fs.writeFileSync(path.join(cacheDir, "cache_key.md5"), key.replace(CACHE_PREFIX, ""), "utf8"); + const restoredKey = await cache.restoreCache([cacheDir], key); + const cacheHit = restoredKey === key; + if (cacheHit) { + await this.restorePackages(cacheDir, inputs.executeInstallScripts); + } + else { + const installManager = await createPackageManager(true); + const installTargets = normalizedPackages.map((packageSpecifier) => this.packageSpecifierToName(packageSpecifier)); + await this.installAndCachePackages(cacheDir, installTargets, installManager); + await cache.saveCache([cacheDir], key); + } + return { + cacheHit, + packageVersionList: readManifestAsCsv(path.join(cacheDir, "manifest_main.log")), + allPackageVersionList: readManifestAsCsv(path.join(cacheDir, "manifest_all.log")), + }; + } +} +export async function runAction(inputs, logger) { + const packageManager = (await createPackageManager(true, logger, logger)); + const commandRunner = new DefaultCommandRunner(logger, logger); + const actionRunner = new ActionRunner(commandRunner, tar, logger); + return await actionRunner.runAction(inputs); +} +//# sourceMappingURL=action.js.map \ No newline at end of file diff --git a/dist/action.js.map b/dist/action.js.map new file mode 100644 index 0000000..2318be2 --- /dev/null +++ b/dist/action.js.map @@ -0,0 +1 @@ +{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..4e4f95a --- /dev/null +++ b/dist/index.js @@ -0,0 +1,41 @@ +import * as core from "@actions/core"; +import { parseBoolean, runAction } from "./action.js"; +import winston from "winston"; +function parseEmptyPackagesBehavior(value) { + if (value === "error" || value === "warn" || value === "ignore") { + return value; + } + throw new Error(`empty_packages_behavior value '${value}' must be one of: error, warn, ignore.`); +} +function getInputs() { + const executeInstallScriptsRaw = core.getInput("execute_install_scripts"); + const debugRaw = core.getInput("debug"); + const emptyPackagesBehaviorRaw = core.getInput("empty_packages_behavior") || "error"; + return { + packages: core.getInput("packages", { required: true }), + version: core.getInput("version"), + executeInstallScripts: parseBoolean(executeInstallScriptsRaw, "execute_install_scripts"), + emptyPackagesBehavior: parseEmptyPackagesBehavior(emptyPackagesBehaviorRaw), + debug: parseBoolean(debugRaw, "debug"), + }; +} +async function main() { + try { + const inputs = getInputs(); + const logger = winston.createLogger({ + level: inputs.debug ? "debug" : "info", + format: winston.format.combine(winston.format.colorize(), winston.format.printf(({ level, message }) => `${level}: ${message}`)), + transports: [new winston.transports.Console()], + }); + const outputs = await runAction(inputs, logger); + core.setOutput("cache-hit", String(outputs.cacheHit)); + core.setOutput("package-version-list", outputs.packageVersionList); + core.setOutput("all-package-version-list", outputs.allPackageVersionList); + } + catch (error) { + const message = error instanceof Error ? error.message : String(error); + core.setFailed(message); + } +} +void main(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..07d9c0c --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAqB,MAAM,aAAa,CAAC;AACzE,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,SAAS,0BAA0B,CACjC,KAAa;IAEb,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,KAAK,CACb,kCAAkC,KAAK,wCAAwC,CAChF,CAAC;AACJ,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,wBAAwB,GAAG,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,wBAAwB,GAC5B,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,IAAI,OAAO,CAAC;IAEtD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACvD,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QACjC,qBAAqB,EAAE,YAAY,CACjC,wBAAwB,EACxB,yBAAyB,CAC1B;QACD,qBAAqB,EAAE,0BAA0B,CAAC,wBAAwB,CAAC;QAC3E,KAAK,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YAClC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;YACtC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,KAAK,OAAO,EAAE,CAAC,CACtE;YACD,UAAU,EAAE,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;SAC/C,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEhD,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,SAAS,CAAC,sBAAsB,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACnE,IAAI,CAAC,SAAS,CAAC,0BAA0B,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,KAAK,IAAI,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/io.d.ts b/dist/io.d.ts new file mode 100644 index 0000000..34ad1e5 --- /dev/null +++ b/dist/io.d.ts @@ -0,0 +1,23 @@ +import { type CommandRunner } from "../../ts-apt/dist/index.js"; +export declare function isAptListsFresh(): boolean; +export declare class Package { + readonly name: string; + readonly version: string; + constructor(name: string, version: string); + serialize(): string; +} +export declare class CacheKey { + readonly version: string; + readonly forceUpdateIncrement: string; + readonly arch: string; + readonly normalizedPackages: string[]; + constructor(version: string, forceUpdateIncrement: string, arch: string, normalizedPackages: string[]); + serialize(): string; +} +export declare function deserializeCacheKey(serialized: string): CacheKey; +export declare class Cache { + private readonly cachePath; + private readonly commandRunner; + constructor(cacheDir: string | undefined, commandRunner: CommandRunner); + getKey(normalizedPackages: string[], version: string): Promise; +} diff --git a/dist/io.js b/dist/io.js new file mode 100644 index 0000000..a6ad9cd --- /dev/null +++ b/dist/io.js @@ -0,0 +1,88 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as crypto from "crypto"; +import * as os from "os"; +export function isAptListsFresh() { + const aptListsPath = "/var/lib/apt/lists"; + const maxDepth = 5; + function search(currentPath, currentDepth) { + if (currentDepth > maxDepth) + return false; + try { + const stats = fs.statSync(currentPath); + if (stats.isDirectory()) { + const entries = fs.readdirSync(currentPath); + for (const entry of entries) { + const fullPath = path.join(currentPath, entry); + if (search(fullPath, currentDepth + 1)) { + return true; + } + } + } + else { + return true; + } + } + catch (error) { + // Ignore permission errors or inaccessible paths + } + return false; + } + return search(aptListsPath, 0); +} +export class Package { + name; + version; + constructor(name, version) { + this.name = name; + this.version = version; + } + serialize() { + return `${this.name}@${this.version}`; + } +} +const FORCE_UPDATE_INCREMENT = "4"; +const CACHE_DIRNAME = "cache-apt-pkgs"; +const CACHE_PREFIX = "cache-apt-pkgs_"; +export class CacheKey { + version; + forceUpdateIncrement; + arch; + normalizedPackages; + constructor(version, forceUpdateIncrement, arch, normalizedPackages) { + this.version = version; + this.forceUpdateIncrement = forceUpdateIncrement; + this.arch = arch; + this.normalizedPackages = normalizedPackages; + } + serialize() { + return `${this.version}|${this.forceUpdateIncrement}|${this.arch}|${this.normalizedPackages.join(",")}`; + } +} +export function deserializeCacheKey(serialized) { + const parts = serialized.split("|"); + if (parts.length !== 4) { + throw new Error(`Invalid serialized cache key: ${serialized}`); + } + const [version, forceUpdateIncrement, arch, normalizedPackagesStr] = parts; + const normalizedPackages = normalizedPackagesStr.split(","); + return new CacheKey(version, forceUpdateIncrement, arch, normalizedPackages); +} +export class Cache { + cachePath; + commandRunner; + constructor(cacheDir = CACHE_DIRNAME, commandRunner) { + this.cachePath = path.join(os.homedir(), cacheDir); + this.commandRunner = commandRunner; + } + async getKey(normalizedPackages, version) { + const architecture = await (await this.commandRunner.run("arch")).stdout.trim(); + let value = `${normalizedPackages.join(" ")} @ ${version} ${FORCE_UPDATE_INCREMENT}`; + if (architecture !== "x86_64") { + value = `${value} ${architecture}`; + } + const hash = crypto.createHash("md5").update(value).digest("hex"); + return `${CACHE_PREFIX}${hash}`; + } +} +//# sourceMappingURL=io.js.map \ No newline at end of file diff --git a/dist/io.js.map b/dist/io.js.map new file mode 100644 index 0000000..0330608 --- /dev/null +++ b/dist/io.js.map @@ -0,0 +1 @@ +{"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/manifest.d.ts b/dist/manifest.d.ts new file mode 100644 index 0000000..2ac7c32 --- /dev/null +++ b/dist/manifest.d.ts @@ -0,0 +1,2 @@ +export declare function writeManifest(filePath: string, entries: string[]): void; +export declare function readManifestAsCsv(filePath: string): string; diff --git a/dist/manifest.js b/dist/manifest.js new file mode 100644 index 0000000..fa67408 --- /dev/null +++ b/dist/manifest.js @@ -0,0 +1,17 @@ +import fs from "node:fs"; +export function writeManifest(filePath, entries) { + const normalized = [...entries].filter(Boolean).sort((a, b) => a.localeCompare(b)); + fs.writeFileSync(filePath, normalized.join("\n"), "utf8"); +} +export function readManifestAsCsv(filePath) { + if (!fs.existsSync(filePath)) { + return ""; + } + return fs + .readFileSync(filePath, "utf8") + .split(/\r?\n/) + .map((line) => line.trim()) + .filter(Boolean) + .join(","); +} +//# sourceMappingURL=manifest.js.map \ No newline at end of file diff --git a/dist/manifest.js.map b/dist/manifest.js.map new file mode 100644 index 0000000..5e68b1b --- /dev/null +++ b/dist/manifest.js.map @@ -0,0 +1 @@ +{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAiB;IAC/D,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACnF,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,EAAE;SACN,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC9B,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/dist/shell.d.ts b/dist/shell.d.ts new file mode 100644 index 0000000..dc77c8e --- /dev/null +++ b/dist/shell.d.ts @@ -0,0 +1,9 @@ +import { type SpawnSyncOptions } from "node:child_process"; +export interface CommandResult { + readonly status: number; + readonly stdout: string; + readonly stderr: string; +} +export declare function runCommand(command: string, args?: string[], options?: SpawnSyncOptions): CommandResult; +export declare function runCommandOrThrow(command: string, args?: string[], options?: SpawnSyncOptions): CommandResult; +export declare function fileIsFresh(path: string, withinMinutes: number): boolean; diff --git a/dist/shell.js b/dist/shell.js new file mode 100644 index 0000000..1fcdc0d --- /dev/null +++ b/dist/shell.js @@ -0,0 +1,46 @@ +import { spawnSync } from "node:child_process"; +import fs from "node:fs"; +export function runCommand(command, args = [], options = {}) { + const result = spawnSync(command, args, { + encoding: "utf8", + ...options, + }); + const stdout = typeof result.stdout === "string" + ? result.stdout + : result.stdout + ? result.stdout.toString("utf8") + : ""; + const stderr = typeof result.stderr === "string" + ? result.stderr + : result.stderr + ? result.stderr.toString("utf8") + : ""; + return { + status: result.status ?? 1, + stdout, + stderr, + }; +} +export function runCommandOrThrow(command, args = [], options = {}) { + const result = runCommand(command, args, options); + if (result.status !== 0) { + throw new Error([ + `Command failed: ${command} ${args.join(" ")}`, + `exit: ${result.status}`, + result.stdout ? `stdout:\n${result.stdout.trim()}` : "", + result.stderr ? `stderr:\n${result.stderr.trim()}` : "", + ] + .filter(Boolean) + .join("\n")); + } + return result; +} +export function fileIsFresh(path, withinMinutes) { + if (!fs.existsSync(path)) { + return false; + } + const stat = fs.statSync(path); + const maxAgeMs = withinMinutes * 60 * 1000; + return Date.now() - stat.mtimeMs <= maxAgeMs; +} +//# sourceMappingURL=shell.js.map \ No newline at end of file diff --git a/dist/shell.js.map b/dist/shell.js.map new file mode 100644 index 0000000..48751c0 --- /dev/null +++ b/dist/shell.js.map @@ -0,0 +1 @@ +{"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAyB,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQzB,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,OAAiB,EAAE,EACnB,UAA4B,EAAE;IAE9B,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACtC,QAAQ,EAAE,MAAM;QAChB,GAAG,OAAO;KACX,CAAC,CAAC;IAEH,MAAM,MAAM,GACV,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QAC/B,CAAC,CAAC,MAAM,CAAC,MAAM;QACf,CAAC,CAAC,MAAM,CAAC,MAAM;YACb,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,EAAE,CAAC;IACX,MAAM,MAAM,GACV,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QAC/B,CAAC,CAAC,MAAM,CAAC,MAAM;QACf,CAAC,CAAC,MAAM,CAAC,MAAM;YACb,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,EAAE,CAAC;IAEX,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QAC1B,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,OAAiB,EAAE,EACnB,UAA4B,EAAE;IAE9B,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb;YACE,mBAAmB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAC9C,SAAS,MAAM,CAAC,MAAM,EAAE;YACxB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;YACvD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;SACxD;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,aAAqB;IAC7D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;AAC/C,CAAC"} \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..d6b844b --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,16 @@ +import tsParser from "@typescript-eslint/parser"; + +export default [ + { + ignores: ["dist/**", "node_modules/**", "target/**"], + }, + { + files: ["src/**/*.ts", "test/**/*.ts"], + languageOptions: { + parser: tsParser, + ecmaVersion: "latest", + sourceType: "module", + }, + rules: {}, + }, +]; diff --git a/go.mod b/go.mod deleted file mode 100644 index 5cc8b8b..0000000 --- a/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module awalsh128.com/cache-apt-pkgs-action - -go 1.20 diff --git a/install_and_cache_pkgs.sh b/install_and_cache_pkgs.sh deleted file mode 100755 index b96f969..0000000 --- a/install_and_cache_pkgs.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e - -# Debug mode for diagnosing issues. -# Setup first before other operations. -debug="${2}" -test "${debug}" = "true" && set -x - -# Include library. -script_dir="$(dirname -- "$(realpath -- "${0}")")" -source "${script_dir}/lib.sh" - -# Directory that holds the cached packages. -cache_dir="${1}" - -# List of the packages to use. -input_packages="${@:3}" - -if ! apt-fast --version > /dev/null 2>&1; then - log "Installing apt-fast for optimized installs..." - # Install apt-fast for optimized installs. - /bin/bash -c "$(curl -sL https://raw.githubusercontent.com/ilikenwf/apt-fast/master/quick-install.sh)" - log "done" - - log_empty_line -fi - -log "Updating APT package list..." -if [[ -z "$(find -H /var/lib/apt/lists -maxdepth 0 -mmin -5)" ]]; then - sudo apt-fast update > /dev/null - log "done" -else - log "skipped (fresh within at least 5 minutes)" -fi - -log_empty_line - -packages="$(get_normalized_package_list "${input_packages}")" -package_count=$(wc -w <<< "${packages}") -log "Clean installing and caching ${package_count} package(s)." - -log_empty_line - -manifest_main="" -log "Package list:" -for package in ${packages}; do - manifest_main="${manifest_main}${package}," - log "- ${package}" -done -write_manifest "main" "${manifest_main}" "${cache_dir}/manifest_main.log" - -log_empty_line - -# Strictly contains the requested packages. -manifest_main="" -# Contains all packages including dependencies. -manifest_all="" - -install_log_filepath="${cache_dir}/install.log" - -log "Clean installing ${package_count} packages..." -# Zero interaction while installing or upgrading the system via apt. -sudo DEBIAN_FRONTEND=noninteractive apt-fast --yes install ${packages} > "${install_log_filepath}" -log "done" -log "Installation log written to ${install_log_filepath}" - -log_empty_line - -installed_packages=$(get_installed_packages "${install_log_filepath}") -log "Installed package list:" -for installed_package in ${installed_packages}; do - # Reformat for human friendly reading. - log "- $(echo ${installed_package} | awk -F\= '{print $1" ("$2")"}')" -done - -log_empty_line - -installed_packages_count=$(wc -w <<< "${installed_packages}") -log "Caching ${installed_packages_count} installed packages..." -for installed_package in ${installed_packages}; do - cache_filepath="${cache_dir}/${installed_package}.tar" - - # Sanity test in case APT enumerates duplicates. - if test ! -f "${cache_filepath}"; then - read package_name package_ver < <(get_package_name_ver "${installed_package}") - log " * Caching ${package_name} to ${cache_filepath}..." - - # Pipe all package files (no folders) and installation control data to Tar. - tar -cf "${cache_filepath}" -C / --verbatim-files-from --files-from <( { dpkg -L "${package_name}" && - get_install_script_filepath "" "${package_name}" "preinst" && - get_install_script_filepath "" "${package_name}" "postinst" ;} | - while IFS= read -r f; do test -f "${f}" -o -L "${f}" && get_tar_relpath "${f}"; done ) - - log " done (compressed size $(du -h "${cache_filepath}" | cut -f1))." - fi - - # Comma delimited name:ver pairs in the all packages manifest. - manifest_all="${manifest_all}${package_name}=${package_ver}," -done -log "done (total cache size $(du -h ${cache_dir} | tail -1 | awk '{print $1}'))" - -log_empty_line - -write_manifest "all" "${manifest_all}" "${cache_dir}/manifest_all.log" diff --git a/lib.sh b/lib.sh deleted file mode 100755 index 755d939..0000000 --- a/lib.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash - -# Don't fail on error. We use the exit status as a conditional. -# -# This is the default behavior but can be overridden by the caller in the -# SHELLOPTS env var. -set +e - -############################################################################### -# Execute the Debian install script. -# Arguments: -# Root directory to search from. -# File path to cached package archive. -# Installation script extension (preinst, postinst). -# Parameter to pass to the installation script. -# Returns: -# Filepath of the install script, otherwise an empty string. -############################################################################### -function execute_install_script { - local package_name=$(basename ${2} | awk -F\= '{print $1}') - local install_script_filepath=$(\ - get_install_script_filepath "${1}" "${package_name}" "${3}") - if test ! -z "${install_script_filepath}"; then - log "- Executing ${install_script_filepath}..." - # Don't abort on errors; dpkg-trigger will error normally since it is - # outside its run environment. - sudo sh -x ${install_script_filepath} ${4} || true - log " done" - fi -} - -############################################################################### -# Gets the Debian install script filepath. -# Arguments: -# Root directory to search from. -# Name of the unqualified package to search for. -# Extension of the installation script (preinst, postinst) -# Returns: -# Filepath of the script file, otherwise an empty string. -############################################################################### -function get_install_script_filepath { - # Filename includes arch (e.g. amd64). - local filepath="$(\ - ls -1 ${1}var/lib/dpkg/info/${2}*.${3} 2> /dev/null \ - | grep -E ${2}'(:.*)?.'${3} | head -1 || true)" - test "${filepath}" && echo "${filepath}" -} - -############################################################################### -# Gets a list of installed packages from a Debian package installation log. -# Arguments: -# The filepath of the Debian install log. -# Returns: -# The list of colon delimited action syntax pairs with each pair equals -# delimited. : :... -############################################################################### -function get_installed_packages { - local install_log_filepath="${1}" - local regex="^Unpacking ([^ :]+)([^ ]+)? (\[[^ ]+\]\s)?\(([^ )]+)" - local dep_packages="" - while read -r line; do - # ${regex} should be unquoted since it isn't a literal. - if [[ "${line}" =~ ${regex} ]]; then - dep_packages="${dep_packages}${BASH_REMATCH[1]}=${BASH_REMATCH[4]} " - else - log_err "Unable to parse package name and version from \"${line}\"" - exit 2 - fi - done < <(grep "^Unpacking " ${install_log_filepath}) - if test -n "${dep_packages}"; then - echo "${dep_packages:0:-1}" # Removing trailing space. - else - echo "" - fi -} - -############################################################################### -# Splits a fully action syntax APT package into the name and version. -# Arguments: -# The action syntax equals delimited package pair or just the package name. -# Returns: -# The package name and version pair. -############################################################################### -function get_package_name_ver { - local ORIG_IFS="${IFS}" - IFS=\= read name ver <<< "${1}" - IFS="${ORIG_IFS}" - # If version not found in the fully qualified package value. - if test -z "${ver}"; then - # This is a fallback and should not be used any more as its slow. - log_err "Unexpected version resolution for package '${name}'" - ver="$(apt-cache show ${name} | grep '^Version:' | awk '{print $2}')" - fi - echo "${name}" "${ver}" -} - -############################################################################### -# Sorts given packages by name and split on commas and/or spaces. -# Arguments: -# The comma and/or space delimited list of packages. -# Returns: -# Sorted list of space delimited package name=version pairs. -############################################################################### -function get_normalized_package_list { - # Remove commas, and block scalar folded backslashes, - # extraneous spaces at the middle, beginning and end - # then sort. - local packages=$(echo "${1}" \ - | sed 's/[,\]/ /g; s/\s\+/ /g; s/^\s\+//g; s/\s\+$//g' \ - | sort -t' ') - local script_dir="$(dirname -- "$(realpath -- "${0}")")" - - local architecture=$(dpkg --print-architecture) - if [ "${architecture}" == "arm64" ]; then - ${script_dir}/apt_query-arm64 normalized-list ${packages} - else - ${script_dir}/apt_query-x86 normalized-list ${packages} - fi -} - -############################################################################### -# Gets the relative filepath acceptable by Tar. Just removes the leading slash -# that Tar disallows. -# Arguments: -# Absolute filepath to archive. -# Returns: -# The relative filepath to archive. -############################################################################### -function get_tar_relpath { - local filepath=${1} - if test ${filepath:0:1} = "/"; then - echo "${filepath:1}" - else - echo "${filepath}" - fi -} - -function log { echo "${@}"; } -function log_err { >&2 echo "${@}"; } - -function log_empty_line { echo ""; } - -############################################################################### -# Validates an argument to be of a boolean value. -# Arguments: -# Argument to validate. -# Variable name of the argument. -# Exit code if validation fails. -# Returns: -# Sorted list of space delimited packages. -############################################################################### -function validate_bool { - if test "${1}" != "true" -a "${1}" != "false"; then - log "aborted" - log "${2} value '${1}' must be either true or false (case sensitive)." - exit ${3} - fi -} - -############################################################################### -# Writes the manifest to a specified file. -# Arguments: -# Type of manifest being written. -# List of packages being written to the file. -# File path of the manifest being written. -# Returns: -# Log lines from write. -############################################################################### -function write_manifest { - if [ ${#2} -eq 0 ]; then - log "Skipped ${1} manifest write. No packages to install." - else - log "Writing ${1} packages manifest to ${3}..." - # 0:-1 to remove trailing comma, delimit by newline and sort. - echo "${2:0:-1}" | tr ',' '\n' | sort > ${3} - log "done" - fi -} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c558dd7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3950 @@ +{ + "name": "cache-apt-pkgs-action", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cache-apt-pkgs-action", + "version": "2.0.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@actions/cache": "^6.1.0", + "@actions/core": "^1.11.1", + "tar": "^7.4.3", + "ts-apt": "file:../ts-apt", + "winston": "^3.19.0" + }, + "devDependencies": { + "@types/node": "^22.15.30", + "@typescript-eslint/parser": "^8.46.3", + "eslint": "^9.31.0", + "typescript": "^5.8.3", + "vitest": "^3.2.4" + }, + "engines": { + "node": ">=20" + } + }, + "../ts-apt": { + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "winston": "^3.19.0" + }, + "devDependencies": { + "@devcontainers/cli": "^0.81.1", + "@types/node": "^26.0.1", + "@typescript-eslint/eslint-plugin": "^8.62.0", + "@typescript-eslint/parser": "^8.62.0", + "eslint": "^10.6.0", + "internet-message": "^1.0.0", + "type-coverage": "^2.29.7", + "typedoc": "^0.28.19", + "typescript": "^5.9.3", + "vitest": "^4.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@actions/cache": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-6.1.0.tgz", + "integrity": "sha512-LVqybSbzhBp2uAETOQ3HnVjXA4AcjavgMH+LCr+cjgO+PZfciv/1QAgoW+esXBaAhvDid+vXeV70GGJpAh4V5Q==", + "license": "MIT", + "dependencies": { + "@actions/core": "^3.0.1", + "@actions/exec": "^3.0.0", + "@actions/glob": "^0.6.1", + "@actions/http-client": "^4.0.1", + "@actions/io": "^3.0.2", + "@azure/core-rest-pipeline": "^1.23.0", + "@azure/storage-blob": "^12.31.0", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "semver": "^7.7.4" + } + }, + "node_modules/@actions/cache/node_modules/@actions/core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", + "license": "MIT", + "dependencies": { + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" + } + }, + "node_modules/@actions/cache/node_modules/@actions/exec": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz", + "integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==", + "license": "MIT", + "dependencies": { + "@actions/io": "^3.0.2" + } + }, + "node_modules/@actions/cache/node_modules/@actions/http-client": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^6.23.0" + } + }, + "node_modules/@actions/cache/node_modules/@actions/io": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz", + "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", + "license": "MIT" + }, + "node_modules/@actions/cache/node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "license": "MIT", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "license": "MIT", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/glob": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.6.1.tgz", + "integrity": "sha512-K4+2Ac5ILcf2ySdJCha+Pop9NcKjxqCL4xL4zI50dgB2PbXgC0+AcP011xfH4Of6b4QEJJg8dyZYv7zl4byTsw==", + "license": "MIT", + "dependencies": { + "@actions/core": "^3.0.0", + "minimatch": "^3.0.4" + } + }, + "node_modules/@actions/glob/node_modules/@actions/core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", + "license": "MIT", + "dependencies": { + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" + } + }, + "node_modules/@actions/glob/node_modules/@actions/exec": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz", + "integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==", + "license": "MIT", + "dependencies": { + "@actions/io": "^3.0.2" + } + }, + "node_modules/@actions/glob/node_modules/@actions/http-client": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^6.23.0" + } + }, + "node_modules/@actions/glob/node_modules/@actions/io": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz", + "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", + "license": "MIT" + }, + "node_modules/@actions/glob/node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "license": "MIT" + }, + "node_modules/@azure/core-auth": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.2.tgz", + "integrity": "sha512-1D2LpsU7y9xrqKjdIbsB7PlrRePw0xsVV8p+AKTlzITrWmscajryfJCdDJB/oGwvDI5HmRo04eMMADB67uwAwQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.4.0.tgz", + "integrity": "sha512-f1P96IB399YiN2ARYHP7EpZi3Bf3wH4SN2lGzrw7JVwm7bbsVYtf2iKSBwTywD2P62NOPZGHFSZi+6jjb75JuA==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@azure/core-client": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.24.0.tgz", + "integrity": "sha512-PpLsoDQ3AMmKZ0VU+0GrmqMxgp/sExjlVm4R+nLWngeoEGAzOIPVifaxKGU5gMv+nWELUoHfvrolWD+ZS/nFJg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-xml": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.1.tgz", + "integrity": "sha512-xcNRHqCoSp4AunOALEae6A8f3qATb83gSrm31Iqb01OzblvC3/W/bfXozcq78EzIdzZzuH1bZ2NvRR0TdX709w==", + "license": "MIT", + "dependencies": { + "fast-xml-parser": "^5.5.9", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/storage-blob": { + "version": "12.32.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.32.0.tgz", + "integrity": "sha512-80LzSNnFQye2LCCBFghAJS6jJQJ7N4bfgZ6qDMgVGRtugZ7TLDKQZ2hczMigmZH3jAcMRdma/IygsC5+0gT7Tw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.3", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.19.1", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/core-xml": "^1.4.5", + "@azure/logger": "^1.1.4", + "@azure/storage-common": "^12.4.0", + "events": "^3.0.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/storage-blob/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/storage-common": { + "version": "12.4.1", + "resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.4.1.tgz", + "integrity": "sha512-t14unw/WofGDUi7TKJrsyXyPsN+NLgRm7hMaq0llxNmTIzt7f257+6LE6FKIJPh88zLj6M7LPvzve0fEYg/L3A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-rest-pipeline": "^1.24.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.1.4", + "events": "^3.3.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/storage-common/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", + "license": "MIT", + "dependencies": { + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodable/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "license": "MIT", + "dependencies": { + "color": "^5.0.2", + "text-hex": "1.0.x" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", + "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.6.tgz", + "integrity": "sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og==", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/color": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", + "license": "MIT", + "dependencies": { + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.9.3.tgz", + "integrity": "sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.2.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^1.0.1", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.4.1", + "xml-naming": "^0.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unsafe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-1.0.1.tgz", + "integrity": "sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-expression-matcher": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.1.tgz", + "integrity": "sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strnum": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.17.tgz", + "integrity": "sha512-wPEBwzapC+2PaTYPH6e2L+cNOEE227S47wUYFqlegcs8zlLLmeb9Fcff1HVZY4Fwku/1Eyv38n7GYwB2aaS71g==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-apt": { + "resolved": "../ts-apt", + "link": true + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/winston": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.8", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..bf8e1de --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "cache-apt-pkgs-action", + "version": "2.0.0", + "private": true, + "description": "GitHub Action to install and cache APT packages", + "author": "Andrew Walsh", + "license": "Apache-2.0", + "type": "module", + "engines": { + "node": ">=20" + }, + "scripts": { + "prepare:ts-apt": "cd ../ts-apt && npx tsc -p tsconfig.build.json", + "postinstall": "npm run prepare:ts-apt", + "prelint": "npm run prepare:ts-apt", + "pretypecheck": "npm run prepare:ts-apt", + "pretest": "npm run prepare:ts-apt", + "prebuild": "npm run prepare:ts-apt", + "build": "tsc -p tsconfig.build.json", + "clean": "rm -rf dist coverage", + "lint": "eslint src test --ext .ts", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "vitest run" + }, + "dependencies": { + "@actions/cache": "^6.1.0", + "@actions/core": "^1.11.1", + "tar": "^7.4.3", + "ts-apt": "file:../ts-apt", + "winston": "^3.19.0" + }, + "devDependencies": { + "@types/node": "^22.15.30", + "@typescript-eslint/parser": "^8.46.3", + "eslint": "^9.31.0", + "typescript": "^5.8.3", + "vitest": "^3.2.4" + } +} diff --git a/post_cache_action.sh b/post_cache_action.sh deleted file mode 100755 index f71c336..0000000 --- a/post_cache_action.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e - -# Include library. -script_dir="$(dirname -- "$(realpath -- "${0}")")" -source "${script_dir}/lib.sh" - -# Directory that holds the cached packages. -cache_dir="${1}" - -# Root directory to untar the cached packages to. -# Typically filesystem root '/' but can be changed for testing. -# WARNING: If non-root, this can cause errors during install script execution. -cache_restore_root="${2}" - -# Indicates that the cache was found. -cache_hit="${3}" - -# Cache and execute post install scripts on restore. -execute_install_scripts="${4}" - -# Debug mode for diagnosing issues. -debug="${5}" -test "${debug}" = "true" && set -x - -# List of the packages to use. -packages="${@:6}" - -if test "${cache_hit}" = "true"; then - ${script_dir}/restore_pkgs.sh "${cache_dir}" "${cache_restore_root}" "${execute_install_scripts}" "${debug}" -else - ${script_dir}/install_and_cache_pkgs.sh "${cache_dir}" "${debug}" ${packages} -fi - -log_empty_line diff --git a/pre_cache_action.sh b/pre_cache_action.sh deleted file mode 100755 index 1ed9f5c..0000000 --- a/pre_cache_action.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash - -set -e - -# Include library. -script_dir="$(dirname -- "$(realpath -- "${0}")")" -source "${script_dir}/lib.sh" - -# Debug mode for diagnosing issues. -# Setup first before other operations. -debug="${4}" -validate_bool "${debug}" debug 1 -test ${debug} == "true" && set -x - -# Directory that holds the cached packages. -cache_dir="${1}" - -# Version of the cache to create or load. -version="${2}" - -# Execute post-installation script. -execute_install_scripts="${3}" - -# Debug mode for diagnosing issues. -debug="${4}" - -# List of the packages to use. -input_packages="${@:5}" - -# Trim commas, excess spaces, and sort. -log "Normalizing package list..." -packages="$(get_normalized_package_list "${input_packages}")" -log "done" - -# Create cache directory so artifacts can be saved. -mkdir -p ${cache_dir} - -log "Validating action arguments (version='${version}', packages='${packages}')..."; -if grep -q " " <<< "${version}"; then - log "aborted" - log "Version value '${version}' cannot contain spaces." >&2 - exit 2 -fi - -# Is length of string zero? -if test -z "${packages}"; then - case "$EMPTY_PACKAGES_BEHAVIOR" in - ignore) - exit 0 - ;; - warn) - echo "::warning::Packages argument is empty." - exit 0 - ;; - *) - log "aborted" - log "Packages argument is empty." >&2 - exit 3 - ;; - esac -fi - -validate_bool "${execute_install_scripts}" execute_install_scripts 4 - -log "done" - -log_empty_line - -# Abort on any failure at this point. -set -e - -log "Creating cache key..." - -# Forces an update in cases where an accidental breaking change was introduced -# and a global cache reset is required, or change in cache action requiring reload. -force_update_inc="3" - -# Force a different cache key for different architectures (currently x86_64 and aarch64 are available on GitHub) -cpu_arch="$(arch)" -log "- CPU architecture is '${cpu_arch}'." - -value="${packages} @ ${version} ${force_update_inc}" - -# Don't invalidate existing caches for the standard Ubuntu runners -if [ "${cpu_arch}" != "x86_64" ]; then - value="${value} ${cpu_arch}" - log "- Architecture '${cpu_arch}' added to value." -fi - -log "- Value to hash is '${value}'." - -key="$(echo "${value}" | md5sum | cut -f1 -d' ')" -log "- Value hashed as '${key}'." - -log "done" - -key_filepath="${cache_dir}/cache_key.md5" -echo ${key} > ${key_filepath} -log "Hash value written to ${key_filepath}" diff --git a/restore_pkgs.sh b/restore_pkgs.sh deleted file mode 100755 index 418f9f0..0000000 --- a/restore_pkgs.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -# Fail on any error. -set -e - -# Debug mode for diagnosing issues. -# Setup first before other operations. -debug="${4}" -test ${debug} == "true" && set -x - -# Include library. -script_dir="$(dirname -- "$(realpath -- "${0}")")" -source "${script_dir}/lib.sh" - -# Directory that holds the cached packages. -cache_dir="${1}" - -# Root directory to untar the cached packages to. -# Typically filesystem root '/' but can be changed for testing. -cache_restore_root="${2}" -test -d ${cache_restore_root} || mkdir ${cache_restore_root} - -# Cache and execute post install scripts on restore. -execute_install_scripts="${3}" - -cache_filepaths="$(ls -1 "${cache_dir}" | sort)" -log "Found $(echo ${cache_filepaths} | wc -w) files in the cache." -for cache_filepath in ${cache_filepaths}; do - log "- "$(basename ${cache_filepath})"" -done - -log_empty_line - -log "Reading from main requested packages manifest..." -for logline in $(cat "${cache_dir}/manifest_main.log" | tr ',' '\n' ); do - log "- $(echo "${logline}" | tr ':' ' ')" -done -log "done" - -log_empty_line - -# Only search for archived results. Manifest and cache key also live here. -cached_filepaths=$(ls -1 "${cache_dir}"/*.tar | sort) -cached_filecount=$(echo ${cached_filepaths} | wc -w) - -log "Restoring ${cached_filecount} packages from cache..." -for cached_filepath in ${cached_filepaths}; do - - log "- $(basename "${cached_filepath}") restoring..." - sudo tar -xf "${cached_filepath}" -C "${cache_restore_root}" > /dev/null - log " done" - - # Execute install scripts if available. - if test ${execute_install_scripts} == "true"; then - # May have to add more handling for extracting pre-install script before extracting all files. - # Keeping it simple for now. - execute_install_script "${cache_restore_root}" "${cached_filepath}" preinst install - execute_install_script "${cache_restore_root}" "${cached_filepath}" postinst configure - fi -done -log "done" diff --git a/src/action.ts b/src/action.ts new file mode 100644 index 0000000..8fc6963 --- /dev/null +++ b/src/action.ts @@ -0,0 +1,420 @@ +import cache from "@actions/cache"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { + createPackageManager, + type AptPackageManager, + type PackageManager, + type CommandRunner, + DefaultCommandRunner, +} from "../../ts-apt/dist/index.js"; +import { isAptListsFresh } from "./io.js"; +import { readManifest, writeManifest } from "./manifest.js"; +import * as tar from "tar"; +import winston from "winston"; + +type TarModule = typeof import("tar"); + +type EmptyPackageBehavior = "error" | "warn" | "ignore"; + +export interface ActionInputs { + readonly packages: string; + readonly version: string; + readonly executeInstallScripts: boolean; + readonly emptyPackagesBehavior: EmptyPackageBehavior; + readonly debug: boolean; +} + +export interface ActionOutputs { + readonly cacheHit: boolean; + readonly packageVersionList: string; + readonly allPackageVersionList: string; +} + +export class ActionPackageName implements Comparable { + constructor( + readonly name: string, + readonly version?: string, + ) {} + + serialize() { + if (this.version) { + return this.name + "=" + this.version; + } + return this.name; + } +} + +export function deserializePackageName(text: string): ActionPackageName | null { + const [name, version] = text.split("="); + if (!name) { + return null; + } + return new ActionPackageName(name, version); +} + +export function parseBoolean(value: string, fieldName: string): boolean { + if (value === "true") { + return true; + } + if (value === "false") { + return false; + } + + throw new Error( + `${fieldName} value '${value}' must be either true or false.`, + ); +} + +export function normalizeInputPackages( + inputPackages: string, +): ActionPackageName[] { + return inputPackages + .replace(/[,\\]/g, " ") + .replace(/\s+/g, " ") + .trim() + .split(" ") + .map((part) => part.trim()) + .filter(Boolean) + .sort((a, b) => a.localeCompare(b)) + .map((part) => deserializePackageName(part)) + .filter((pkg): pkg is ActionPackageName => pkg !== null); +} + +export class ActionRunner { + private readonly commandRunner: CommandRunner; + private readonly tar: TarModule; + private readonly logger: winston.Logger; + + constructor( + commandRunner: CommandRunner, + tarModule: TarModule, + logger: winston.Logger, + ) { + this.commandRunner = commandRunner; + this.tar = tarModule; + this.logger = logger; + } + + parseBoolean(value: string, fieldName: string): boolean { + return parseBoolean(value, fieldName); + } + + normalizeInputPackages(inputPackages: string): ActionPackageName[] { + return normalizeInputPackages(inputPackages); + } + + async resolvePackageVersion( + packageManager: PackageManager, + packageName: string, + ): Promise { + const packageInfo = await packageManager.getPackageInfo([packageName]); + const version = packageInfo[0]?.version; + if (!version) { + throw new Error( + `Unable to resolve package version for '${packageName}'.`, + ); + } + return version; + } + + async normalizePackagesWithVersions( + packageManager: PackageManager, + inputPackages: string, + ): Promise { + const raw = this.normalizeInputPackages(inputPackages); + const packages = await Promise.all( + raw.map(async (pkg) => { + if (pkg.version) { + return pkg.serialize(); + } + return `${pkg.name}=${await this.resolvePackageVersion(packageManager, pkg.name)}`; + }), + ); + + return packages.sort((a, b) => a.localeCompare(b)); + } + + validateEmptyPackages( + behavior: EmptyPackageBehavior, + packages: string[], + ): void { + if (packages.length > 0) { + return; + } + + if (behavior === "ignore") { + return; + } + + if (behavior === "warn") { + process.stdout.write("::warning::Packages argument is empty.\n"); + return; + } + + throw new Error("Packages argument is empty."); + } + + getCacheRoot(): string { + return path.join(os.homedir(), CACHE_DIRNAME); + } + + async getCacheKey( + normalizedPackages: string[], + version: string, + ): Promise { + const architecture = await ( + await this.commandRunner.run("arch") + ).stdout.trim(); + let value = `${normalizedPackages.join(" ")} @ ${version} ${FORCE_UPDATE_INCREMENT}`; + + if (architecture !== "x86_64") { + value = `${value} ${architecture}`; + } + + const hash = crypto.createHash("md5").update(value).digest("hex"); + return `${CACHE_PREFIX}${hash}`; + } + + findInstallScript( + packageName: string, + extension: "preinst" | "postinst", + root: string, + ): string | undefined { + const scriptsDir = path.join(root, "var", "lib", "dpkg", "info"); + if (!fs.existsSync(scriptsDir)) { + return undefined; + } + + const pattern = new RegExp(`^${packageName}(:.*)?\\.${extension}$`); + const matches = fs + .readdirSync(scriptsDir) + .filter((entry) => pattern.test(entry)) + .sort((a, b) => a.localeCompare(b)); + const candidate = matches[0]; + if (!candidate) { + return undefined; + } + + return path.join(scriptsDir, candidate); + } + + tarRelativePath(filePath: string): string { + return filePath.startsWith("/") ? filePath.slice(1) : filePath; + } + + async buildFileListForPackage( + packageManager: PackageManager, + packageName: string, + ): Promise { + const files = (await packageManager.listInstalledFiles(packageName)) + .filter((filePath) => { + if (!fs.existsSync(filePath)) { + return false; + } + + const stat = fs.lstatSync(filePath); + return stat.isFile() || stat.isSymbolicLink(); + }) + .map(this.tarRelativePath); + + const preinst = this.findInstallScript(packageName, "preinst", "/"); + const postinst = this.findInstallScript(packageName, "postinst", "/"); + + if (preinst) { + files.push(this.tarRelativePath(preinst)); + } + if (postinst) { + files.push(this.tarRelativePath(postinst)); + } + + return Array.from(new Set(files)).sort((a, b) => a.localeCompare(b)); + } + + async updateAptLists(packageManager: PackageManager): Promise { + if (isAptListsFresh()) { + return; + } + + await packageManager.update(); + } + + packageSpecifierToName(packageSpecifier: string): string { + return packageSpecifier.split("=")[0] ?? packageSpecifier; + } + + async installAndCachePackages( + cacheDir: string, + packages: string[], + packageManager: PackageManager, + ): Promise { + await this.updateAptLists(packageManager); + + writeManifest(path.join(cacheDir, "manifest_main.log"), packages); + + const installedPackages = await packageManager.install(packages); + + const manifestAll: string[] = []; + for (const pkg of installedPackages) { + const packageName = pkg.name; + const packageVersion = pkg.version; + if (!packageName || !packageVersion) { + continue; + } + + const archivePath = path.join( + cacheDir, + `${packageName}=${packageVersion}.tar`, + ); + if (!fs.existsSync(archivePath)) { + const filesToArchive = await this.buildFileListForPackage( + packageManager, + packageName, + ); + await this.tar.create( + { + cwd: "/", + file: archivePath, + portable: false, + preservePaths: false, + follow: false, + noDirRecurse: false, + }, + filesToArchive, + ); + } + + manifestAll.push(`${packageName}=${packageVersion}`); + } + + writeManifest(path.join(cacheDir, "manifest_all.log"), manifestAll); + } + + async restorePackages( + cacheDir: string, + executeInstallScripts: boolean, + ): Promise { + const archives = fs + .readdirSync(cacheDir) + .filter((entry) => entry.endsWith(".tar")) + .sort((a, b) => a.localeCompare(b)); + + for (const archive of archives) { + const archivePath = path.join(cacheDir, archive); + await this.tar.extract({ + cwd: "/", + file: archivePath, + preservePaths: true, + }); + + if (!executeInstallScripts) { + continue; + } + + const packageName = archive.split("=")[0] ?? ""; + if (!packageName) { + continue; + } + + const preinst = this.findInstallScript(packageName, "preinst", "/"); + if (preinst) { + this.logger.info(`Running pre-install script for ${packageName}`); + await this.commandRunner.run("sudo", ["sh", "-x", preinst, "install"]); + } + + const postinst = this.findInstallScript(packageName, "postinst", "/"); + if (postinst) { + this.logger.info(`Running post-install script for ${packageName}`); + await this.commandRunner.run("sudo", [ + "sh", + "-x", + postinst, + "configure", + ]); + } + } + } + + async runAction(inputs: ActionInputs): Promise { + if (/\s/.test(inputs.version)) { + throw new Error( + `Version value '${inputs.version}' cannot contain spaces.`, + ); + } + + const packageInfoManager = await createPackageManager(false); + const normalizedPackages = await this.normalizePackagesWithVersions( + packageInfoManager, + inputs.packages, + ); + this.validateEmptyPackages( + inputs.emptyPackagesBehavior, + normalizedPackages, + ); + + const cacheDir = this.getCacheRoot(); + fs.mkdirSync(cacheDir, { recursive: true }); + + if (normalizedPackages.length === 0) { + writeManifest(path.join(cacheDir, "manifest_main.log"), []); + writeManifest(path.join(cacheDir, "manifest_all.log"), []); + return { + cacheHit: false, + packageVersionList: "", + allPackageVersionList: "", + }; + } + + const key = await this.getCacheKey(normalizedPackages, inputs.version); + fs.writeFileSync( + path.join(cacheDir, "cache_key.md5"), + key.replace(CACHE_PREFIX, ""), + "utf8", + ); + + const restoredKey = await cache.restoreCache([cacheDir], key); + const cacheHit = restoredKey === key; + + if (cacheHit) { + await this.restorePackages(cacheDir, inputs.executeInstallScripts); + } else { + const installManager = await createPackageManager(true); + const installTargets = normalizedPackages.map((packageSpecifier) => + this.packageSpecifierToName(packageSpecifier), + ); + await this.installAndCachePackages( + cacheDir, + installTargets, + installManager, + ); + await cache.saveCache([cacheDir], key); + } + + return { + cacheHit, + packageVersionList: readManifest( + path.join(cacheDir, "manifest_main.log"), + ), + allPackageVersionList: readManifest( + path.join(cacheDir, "manifest_all.log"), + ), + }; + } +} + +export async function runAction( + inputs: ActionInputs, + logger: winston.Logger, +): Promise { + const packageManager = (await createPackageManager( + true, + logger, + logger, + )) as AptPackageManager; + const commandRunner = new DefaultCommandRunner(logger, logger); + const actionRunner = new ActionRunner(commandRunner, tar, logger); + + return await actionRunner.runAction(inputs); +} diff --git a/src/cmd/apt_query/main.go b/src/cmd/apt_query/main.go deleted file mode 100644 index b2df00c..0000000 --- a/src/cmd/apt_query/main.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/common" - "awalsh128.com/cache-apt-pkgs-action/src/internal/exec" - "awalsh128.com/cache-apt-pkgs-action/src/internal/logging" -) - -func getExecutor(replayFilename string) exec.Executor { - if len(replayFilename) == 0 { - return &exec.BinExecutor{} - } - return exec.NewReplayExecutor(replayFilename) -} - -func main() { - debug := flag.Bool("debug", false, "Log diagnostic information to a file alongside the binary.") - - replayFilename := flag.String("replayfile", "", - "Replay command output from a specified file rather than executing a binary."+ - "The file should be in the same format as the log generated by the debug flag.") - - flag.Parse() - unparsedFlags := flag.Args() - - logging.Init(os.Args[0]+".log", *debug) - - executor := getExecutor(*replayFilename) - - if len(unparsedFlags) < 2 { - logging.Fatalf("Expected at least 2 non-flag arguments but found %d.", len(unparsedFlags)) - return - } - command := unparsedFlags[0] - pkgNames := unparsedFlags[1:] - - switch command { - - case "normalized-list": - pkgs, err := common.GetAptPackages(executor, pkgNames) - if err != nil { - logging.Fatalf("Encountered error resolving some or all package names, see combined std[out,err] below.\n%s", err.Error()) - } - fmt.Println(pkgs.Serialize()) - - default: - logging.Fatalf("Command '%s' not recognized.", command) - } -} diff --git a/src/cmd/apt_query/main_test.go b/src/cmd/apt_query/main_test.go deleted file mode 100644 index 49e040d..0000000 --- a/src/cmd/apt_query/main_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "flag" - "testing" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/cmdtesting" -) - -var createReplayLogs bool = false - -func init() { - flag.BoolVar(&createReplayLogs, "createreplaylogs", false, "Execute the test commands, save the command output for future replay and skip the tests themselves.") -} - -func TestMain(m *testing.M) { - cmdtesting.TestMain(m) -} - -func TestNormalizedList_MultiplePackagesExists_StdoutsAlphaSortedPackageNameVersionPairs(t *testing.T) { - result := cmdtesting.New(t, createReplayLogs).Run("normalized-list", "xdot", "rolldice") - result.ExpectSuccessfulOut("rolldice=1.16-1build1 xdot=1.1-2") -} - -func TestNormalizedList_SamePackagesDifferentOrder_StdoutsMatch(t *testing.T) { - expected := "rolldice=1.16-1build1 xdot=1.1-2" - - ct := cmdtesting.New(t, createReplayLogs) - - result := ct.Run("normalized-list", "rolldice", "xdot") - result.ExpectSuccessfulOut(expected) - - result = ct.Run("normalized-list", "xdot", "rolldice") - result.ExpectSuccessfulOut(expected) -} - -func TestNormalizedList_MultiVersionWarning_StdoutSingleVersion(t *testing.T) { - var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list", "libosmesa6-dev", "libgl1-mesa-dev") - result.ExpectSuccessfulOut("libgl1-mesa-dev=21.2.6-0ubuntu0.1~20.04.2 libosmesa6-dev=21.2.6-0ubuntu0.1~20.04.2") -} - -func TestNormalizedList_SinglePackageExists_StdoutsSinglePackageNameVersionPair(t *testing.T) { - var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list", "xdot") - result.ExpectSuccessfulOut("xdot=1.1-2") -} - -func TestNormalizedList_VersionContainsColon_StdoutsEntireVersion(t *testing.T) { - var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list", "default-jre") - result.ExpectSuccessfulOut("default-jre=2:1.11-72") -} - -func TestNormalizedList_NonExistentPackageName_StderrsAptCacheErrors(t *testing.T) { - var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list", "nonexistentpackagename") - result.ExpectError( - `Error encountered running apt-cache --quiet=0 --no-all-versions show nonexistentpackagename -Exited with status code 100; see combined std[out,err] below: -N: Unable to locate package nonexistentpackagename -N: Unable to locate package nonexistentpackagename -E: No packages found`) -} - -func TestNormalizedList_NoPackagesGiven_StderrsArgMismatch(t *testing.T) { - var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list") - result.ExpectError("Expected at least 2 non-flag arguments but found 1.") -} - -func TestNormalizedList_VirtualPackagesExists_StdoutsConcretePackage(t *testing.T) { - result := cmdtesting.New(t, createReplayLogs).Run("normalized-list", "libvips") - result.ExpectSuccessfulOut("libvips42=8.9.1-2") -} diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_multiplepackagesexists_stdoutsalphasortedpackagenameversionpairs.log b/src/cmd/apt_query/testlogs/testnormalizedlist_multiplepackagesexists_stdoutsalphasortedpackagenameversionpairs.log deleted file mode 100644 index 8fc29f0..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_multiplepackagesexists_stdoutsalphasortedpackagenameversionpairs.log +++ /dev/null @@ -1,10 +0,0 @@ -2025/03/15 22:29:08 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:09 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show xdot rolldice", - "Stdout": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\nPackage: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\n", - "Stderr": "", - "CombinedOut": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\nPackage: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_multiversionwarning_stdoutsingleversion.log b/src/cmd/apt_query/testlogs/testnormalizedlist_multiversionwarning_stdoutsingleversion.log deleted file mode 100644 index 028edbc..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_multiversionwarning_stdoutsingleversion.log +++ /dev/null @@ -1,10 +0,0 @@ -2025/03/15 22:29:10 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:12 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show libosmesa6-dev libgl1-mesa-dev", - "Stdout": "Package: libosmesa6-dev\nArchitecture: amd64\nVersion: 21.2.6-0ubuntu0.1~20.04.2\nMulti-Arch: same\nPriority: extra\nSection: devel\nSource: mesa\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian X Strike Force \u003cdebian-x@lists.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 88\nProvides: libosmesa-dev\nDepends: libosmesa6 (= 21.2.6-0ubuntu0.1~20.04.2), mesa-common-dev (= 21.2.6-0ubuntu0.1~20.04.2) | libgl-dev\nConflicts: libosmesa-dev\nReplaces: libosmesa-dev\nFilename: pool/main/m/mesa/libosmesa6-dev_21.2.6-0ubuntu0.1~20.04.2_amd64.deb\nSize: 8844\nMD5sum: b6c380d1b916bc6955aaf108a3be468e\nSHA1: 4b772c8127e60a342dabec4ff0939969d99038b4\nSHA256: bf003b66573d611877664e01659046d281b26698f3665345cb784ddded662c6a\nSHA512: 761557925874473e4408504772a0af4d29f6dc1dcbd53e772315dffb6da87d47960edca4de39deda7cae33a8730d87a19b40a7d29739ba7cff5b60ee4900a13a\nHomepage: https://mesa3d.org/\nDescription-en: Mesa Off-screen rendering extension -- development files\n This package provides the required environment for developing programs\n that use the off-screen rendering extension of Mesa.\n .\n For more information on OSmesa see the libosmesa6 package.\nDescription-md5: 9b1d7a0b3e6a2ea021f4443f42dcff4f\n\nPackage: libgl1-mesa-dev\nArchitecture: amd64\nVersion: 21.2.6-0ubuntu0.1~20.04.2\nMulti-Arch: same\nPriority: extra\nSection: libdevel\nSource: mesa\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian X Strike Force \u003cdebian-x@lists.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 70\nDepends: libgl-dev, libglvnd-dev\nFilename: pool/main/m/mesa/libgl1-mesa-dev_21.2.6-0ubuntu0.1~20.04.2_amd64.deb\nSize: 6420\nMD5sum: 759a811dcb12adfcebfc1a6aa52e85b9\nSHA1: 3b9de17b1c67ee40603e1eebaefa978810a2f2d2\nSHA256: 76846d96ae0706a7edcd514d452a1393bb8b8a8ac06518253dd5869441807052\nSHA512: 581e4b3752b4c98399f3519fce2c5ab033cea3cac66bde3c204af769ff0377400087f9c4c6aaebe06c19d05f8715b3346d249a86c3ae80a098ca476e76af01c3\nHomepage: https://mesa3d.org/\nDescription-en: transitional dummy package\n This is a transitional dummy package, it can be safely removed.\nDescription-md5: 635a93bcd1440d16621693fe064c2aa9\n\n", - "Stderr": "N: There are 2 additional records. Please use the '-a' switch to see them.\n", - "CombinedOut": "Package: libosmesa6-dev\nArchitecture: amd64\nVersion: 21.2.6-0ubuntu0.1~20.04.2\nMulti-Arch: same\nPriority: extra\nSection: devel\nSource: mesa\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian X Strike Force \u003cdebian-x@lists.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 88\nProvides: libosmesa-dev\nDepends: libosmesa6 (= 21.2.6-0ubuntu0.1~20.04.2), mesa-common-dev (= 21.2.6-0ubuntu0.1~20.04.2) | libgl-dev\nConflicts: libosmesa-dev\nReplaces: libosmesa-dev\nFilename: pool/main/m/mesa/libosmesa6-dev_21.2.6-0ubuntu0.1~20.04.2_amd64.deb\nSize: 8844\nMD5sum: b6c380d1b916bc6955aaf108a3be468e\nSHA1: 4b772c8127e60a342dabec4ff0939969d99038b4\nSHA256: bf003b66573d611877664e01659046d281b26698f3665345cb784ddded662c6a\nSHA512: 761557925874473e4408504772a0af4d29f6dc1dcbd53e772315dffb6da87d47960edca4de39deda7cae33a8730d87a19b40a7d29739ba7cff5b60ee4900a13a\nHomepage: https://mesa3d.org/\nDescription-en: Mesa Off-screen rendering extension -- development files\n This package provides the required environment for developing programs\n that use the off-screen rendering extension of Mesa.\n .\n For more information on OSmesa see the libosmesa6 package.\nDescription-md5: 9b1d7a0b3e6a2ea021f4443f42dcff4f\n\nPackage: libgl1-mesa-dev\nArchitecture: amd64\nVersion: 21.2.6-0ubuntu0.1~20.04.2\nMulti-Arch: same\nPriority: extra\nSection: libdevel\nSource: mesa\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian X Strike Force \u003cdebian-x@lists.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 70\nDepends: libgl-dev, libglvnd-dev\nFilename: pool/main/m/mesa/libgl1-mesa-dev_21.2.6-0ubuntu0.1~20.04.2_amd64.deb\nSize: 6420\nMD5sum: 759a811dcb12adfcebfc1a6aa52e85b9\nSHA1: 3b9de17b1c67ee40603e1eebaefa978810a2f2d2\nSHA256: 76846d96ae0706a7edcd514d452a1393bb8b8a8ac06518253dd5869441807052\nSHA512: 581e4b3752b4c98399f3519fce2c5ab033cea3cac66bde3c204af769ff0377400087f9c4c6aaebe06c19d05f8715b3346d249a86c3ae80a098ca476e76af01c3\nHomepage: https://mesa3d.org/\nDescription-en: transitional dummy package\n This is a transitional dummy package, it can be safely removed.\nDescription-md5: 635a93bcd1440d16621693fe064c2aa9\n\nN: There are 2 additional records. Please use the '-a' switch to see them.\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_nonexistentpackagename_stderrsaptcacheerrors.log b/src/cmd/apt_query/testlogs/testnormalizedlist_nonexistentpackagename_stderrsaptcacheerrors.log deleted file mode 100644 index 3523448..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_nonexistentpackagename_stderrsaptcacheerrors.log +++ /dev/null @@ -1,15 +0,0 @@ -2025/03/15 22:29:13 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:14 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show nonexistentpackagename", - "Stdout": "", - "Stderr": "N: Unable to locate package nonexistentpackagename\nN: Unable to locate package nonexistentpackagename\nE: No packages found\n", - "CombinedOut": "N: Unable to locate package nonexistentpackagename\nN: Unable to locate package nonexistentpackagename\nE: No packages found\n", - "ExitCode": 100 -} -EXECUTION-OBJ-END -2025/03/15 22:29:14 Error encountered running apt-cache --quiet=0 --no-all-versions show nonexistentpackagename -Exited with status code 100; see combined std[out,err] below: -N: Unable to locate package nonexistentpackagename -N: Unable to locate package nonexistentpackagename -E: No packages found diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_nopackagesgiven_stderrsargmismatch.log b/src/cmd/apt_query/testlogs/testnormalizedlist_nopackagesgiven_stderrsargmismatch.log deleted file mode 100644 index fbf15a6..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_nopackagesgiven_stderrsargmismatch.log +++ /dev/null @@ -1,2 +0,0 @@ -2025/03/15 22:29:14 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:14 Expected at least 2 non-flag arguments but found 1. diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_samepackagesdifferentorder_stdoutsmatch.log b/src/cmd/apt_query/testlogs/testnormalizedlist_samepackagesdifferentorder_stdoutsmatch.log deleted file mode 100644 index 6e53eef..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_samepackagesdifferentorder_stdoutsmatch.log +++ /dev/null @@ -1,20 +0,0 @@ -2025/03/15 22:29:09 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:10 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show rolldice xdot", - "Stdout": "Package: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\nPackage: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\n", - "Stderr": "", - "CombinedOut": "Package: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\nPackage: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END -2025/03/15 22:29:10 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:10 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show xdot rolldice", - "Stdout": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\nPackage: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\n", - "Stderr": "", - "CombinedOut": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\nPackage: rolldice\nArchitecture: amd64\nVersion: 1.16-1build1\nPriority: optional\nSection: universe/games\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Thomas Ross \u003cthomasross@thomasross.io\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 31\nDepends: libc6 (\u003e= 2.7), libreadline8 (\u003e= 6.0)\nFilename: pool/universe/r/rolldice/rolldice_1.16-1build1_amd64.deb\nSize: 9628\nMD5sum: af6390bf2d5d5b4710d308ac06d4913a\nSHA1: 1d87ccac5b20f4e2a217a0e058408f46cfe5caff\nSHA256: 2e076006200057da0be52060e3cc2f4fc7c51212867173e727590bd7603a0337\nHomepage: https://github.com/sstrickl/rolldice\nDescription-en: virtual dice roller\n rolldice is a virtual dice roller that takes a string on the command\n line in the format of some fantasy role playing games like Advanced\n Dungeons \u0026 Dragons [1] and returns the result of the dice rolls.\n .\n [1] Advanced Dungeons \u0026 Dragons is a registered trademark of TSR, Inc.\nDescription-md5: fc24e9e12c794a8f92ab0ca6e1058501\n\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_singlepackageexists_stdoutssinglepackagenameversionpair.log b/src/cmd/apt_query/testlogs/testnormalizedlist_singlepackageexists_stdoutssinglepackagenameversionpair.log deleted file mode 100644 index be926ab..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_singlepackageexists_stdoutssinglepackagenameversionpair.log +++ /dev/null @@ -1,10 +0,0 @@ -2025/03/15 22:29:12 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:12 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show xdot", - "Stdout": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\n", - "Stderr": "", - "CombinedOut": "Package: xdot\nArchitecture: all\nVersion: 1.1-2\nPriority: optional\nSection: universe/python\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Python Applications Packaging Team \u003cpython-apps-team@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 153\nDepends: gir1.2-gtk-3.0, graphviz, python3-gi, python3-gi-cairo, python3:any\nFilename: pool/universe/x/xdot/xdot_1.1-2_all.deb\nSize: 26708\nMD5sum: aab630b6e1f73a0e3ae85b208b8b6d00\nSHA1: 202155c123c7bd7628023b848e997f342d14359d\nSHA256: 4b7ecb2c4dc948a850024a9b7378d58195230659307bbde4018a1be17645e690\nHomepage: https://github.com/jrfonseca/xdot.py\nDescription-en: interactive viewer for Graphviz dot files\n xdot is an interactive viewer for graphs written in Graphviz's dot language.\n It uses internally the graphviz's xdot output format as an intermediate\n format, and PyGTK and Cairo for rendering. xdot can be used either as a\n standalone application from command line, or as a library embedded in your\n Python 3 application.\n .\n Features:\n * Since it doesn't use bitmaps it is fast and has a small memory footprint.\n * Arbitrary zoom.\n * Keyboard/mouse navigation.\n * Supports events on the nodes with URLs.\n * Animated jumping between nodes.\n * Highlights node/edge under mouse.\nDescription-md5: eb58f25a628b48a744f1b904af3b9282\n\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_versioncontainscolon_stdoutsentireversion.log b/src/cmd/apt_query/testlogs/testnormalizedlist_versioncontainscolon_stdoutsentireversion.log deleted file mode 100644 index 9c986f5..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_versioncontainscolon_stdoutsentireversion.log +++ /dev/null @@ -1,10 +0,0 @@ -2025/03/15 22:29:12 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:13 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show default-jre", - "Stdout": "Package: default-jre\nArchitecture: amd64\nVersion: 2:1.11-72\nPriority: optional\nSection: interpreters\nSource: java-common (0.72)\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian Java Maintainers \u003cpkg-java-maintainers@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 6\nProvides: java-runtime, java10-runtime, java11-runtime, java2-runtime, java5-runtime, java6-runtime, java7-runtime, java8-runtime, java9-runtime\nDepends: default-jre-headless (= 2:1.11-72), openjdk-11-jre\nFilename: pool/main/j/java-common/default-jre_1.11-72_amd64.deb\nSize: 1084\nMD5sum: 4f441bb884801f3a07806934e4519652\nSHA1: 9922edaa7bd91921a2beee6c60343ebf551957a9\nSHA256: 063bb2ca3b51309f6625033c336beffb0eb8286aaabcf3bf917eef498de29ea5\nHomepage: https://wiki.debian.org/Java/\nDescription-en: Standard Java or Java compatible Runtime\n This dependency package points to the Java runtime, or Java compatible\n runtime recommended for this architecture, which is\n openjdk-11-jre for amd64.\nDescription-md5: 071b7a2f9baf048d89c849c14bcafb9e\nCnf-Extra-Commands: java,jexec\n\n", - "Stderr": "", - "CombinedOut": "Package: default-jre\nArchitecture: amd64\nVersion: 2:1.11-72\nPriority: optional\nSection: interpreters\nSource: java-common (0.72)\nOrigin: Ubuntu\nMaintainer: Ubuntu Developers \u003cubuntu-devel-discuss@lists.ubuntu.com\u003e\nOriginal-Maintainer: Debian Java Maintainers \u003cpkg-java-maintainers@lists.alioth.debian.org\u003e\nBugs: https://bugs.launchpad.net/ubuntu/+filebug\nInstalled-Size: 6\nProvides: java-runtime, java10-runtime, java11-runtime, java2-runtime, java5-runtime, java6-runtime, java7-runtime, java8-runtime, java9-runtime\nDepends: default-jre-headless (= 2:1.11-72), openjdk-11-jre\nFilename: pool/main/j/java-common/default-jre_1.11-72_amd64.deb\nSize: 1084\nMD5sum: 4f441bb884801f3a07806934e4519652\nSHA1: 9922edaa7bd91921a2beee6c60343ebf551957a9\nSHA256: 063bb2ca3b51309f6625033c336beffb0eb8286aaabcf3bf917eef498de29ea5\nHomepage: https://wiki.debian.org/Java/\nDescription-en: Standard Java or Java compatible Runtime\n This dependency package points to the Java runtime, or Java compatible\n runtime recommended for this architecture, which is\n openjdk-11-jre for amd64.\nDescription-md5: 071b7a2f9baf048d89c849c14bcafb9e\nCnf-Extra-Commands: java,jexec\n\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagesexists_stdoutsconcretepackage.log b/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagesexists_stdoutsconcretepackage.log deleted file mode 100644 index 58d6b77..0000000 --- a/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagesexists_stdoutsconcretepackage.log +++ /dev/null @@ -1,19 +0,0 @@ -2025/03/15 22:29:14 Debug log created at /home/awalsh128/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log -2025/03/15 22:29:14 EXECUTION-OBJ-START -{ - "Cmd": "apt-cache --quiet=0 --no-all-versions show libvips", - "Stdout": "", - "Stderr": "N: Can't select candidate version from package libvips as it has no candidate\nN: Can't select versions from package 'libvips' as it is purely virtual\nN: No packages found\n", - "CombinedOut": "N: Can't select candidate version from package libvips as it has no candidate\nN: Can't select versions from package 'libvips' as it is purely virtual\nN: No packages found\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END -2025/03/15 22:29:14 EXECUTION-OBJ-START -{ - "Cmd": "bash -c apt-cache showpkg libvips | grep -A 1 \"Reverse Provides\" | tail -1", - "Stdout": "libvips42 8.9.1-2 (= )\n", - "Stderr": "", - "CombinedOut": "libvips42 8.9.1-2 (= )\n", - "ExitCode": 0 -} -EXECUTION-OBJ-END diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..466ae0e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,57 @@ +import * as core from "@actions/core"; +import { parseBoolean, runAction, type ActionInputs } from "./action.js"; +import winston from "winston"; + +function parseEmptyPackagesBehavior( + value: string, +): "error" | "warn" | "ignore" { + if (value === "error" || value === "warn" || value === "ignore") { + return value; + } + + throw new Error( + `empty_packages_behavior value '${value}' must be one of: error, warn, ignore.`, + ); +} + +function getInputs(): ActionInputs { + const executeInstallScriptsRaw = core.getInput("execute_install_scripts"); + const debugRaw = core.getInput("debug"); + const emptyPackagesBehaviorRaw = + core.getInput("empty_packages_behavior") || "error"; + + return { + packages: core.getInput("packages", { required: true }), + version: core.getInput("version"), + executeInstallScripts: parseBoolean( + executeInstallScriptsRaw, + "execute_install_scripts", + ), + emptyPackagesBehavior: parseEmptyPackagesBehavior(emptyPackagesBehaviorRaw), + debug: parseBoolean(debugRaw, "debug"), + }; +} + +async function main(): Promise { + try { + const inputs = getInputs(); + const logger = winston.createLogger({ + level: inputs.debug ? "debug" : "info", + format: winston.format.combine( + winston.format.colorize(), + winston.format.printf(({ level, message }) => `${level}: ${message}`), + ), + transports: [new winston.transports.Console()], + }); + const outputs = await runAction(inputs, logger); + + core.setOutput("cache-hit", String(outputs.cacheHit)); + core.setOutput("package-version-list", outputs.packageVersionList); + core.setOutput("all-package-version-list", outputs.allPackageVersionList); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + core.setFailed(message); + } +} + +void main(); diff --git a/src/internal/cmdtesting/cmdtesting.go b/src/internal/cmdtesting/cmdtesting.go deleted file mode 100644 index 4b6555c..0000000 --- a/src/internal/cmdtesting/cmdtesting.go +++ /dev/null @@ -1,91 +0,0 @@ -package cmdtesting - -import ( - "os" - "os/exec" - "strings" - "testing" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/common" -) - -const binaryName = "apt_query" - -type CmdTesting struct { - *testing.T - createReplayLogs bool - replayFilename string -} - -func New(t *testing.T, createReplayLogs bool) *CmdTesting { - replayFilename := "testlogs/" + strings.ToLower(t.Name()) + ".log" - if createReplayLogs { - os.Remove(replayFilename) - os.Remove(binaryName + ".log") - } - return &CmdTesting{t, createReplayLogs, replayFilename} -} - -type RunResult struct { - Testing *CmdTesting - CombinedOut string - Err error -} - -func TestMain(m *testing.M) { - cmd := exec.Command("go", "build") - out, err := cmd.CombinedOutput() - if err != nil { - panic(string(out)) - } - os.Exit(m.Run()) -} - -func (t *CmdTesting) Run(command string, pkgNames ...string) RunResult { - replayfile := "testlogs/" + strings.ToLower(t.Name()) + ".log" - - flags := []string{"-debug=true"} - if !t.createReplayLogs { - flags = append(flags, "-replayfile="+replayfile) - } - - cmd := exec.Command("./"+binaryName, append(append(flags, command), pkgNames...)...) - combinedOut, err := cmd.CombinedOutput() - - if t.createReplayLogs { - err := common.AppendFile(binaryName+".log", t.replayFilename) - if err != nil { - t.T.Fatalf("Error encountered appending log file.\n%s", err.Error()) - } - } - - return RunResult{Testing: t, CombinedOut: string(combinedOut), Err: err} -} - -func (r *RunResult) ExpectSuccessfulOut(expected string) { - if r.Testing.createReplayLogs { - r.Testing.Log("Skipping test while creating replay logs.") - return - } - - if r.Err != nil { - r.Testing.Errorf("Error running command: %v\n%s", r.Err, r.CombinedOut) - return - } - fullExpected := expected + "\n" // Output will always have a end of output newline. - if r.CombinedOut != fullExpected { - r.Testing.Errorf("Unexpected combined std[err,out] found.\nExpected:\n'%s'\nActual:\n'%s'", fullExpected, r.CombinedOut) - } -} - -func (r *RunResult) ExpectError(expectedCombinedOut string) { - if r.Testing.createReplayLogs { - r.Testing.Log("Skipping test while creating replay logs.") - return - } - - fullExpectedCombinedOut := expectedCombinedOut + "\n" // Output will always have a end of output newline. - if r.CombinedOut != fullExpectedCombinedOut { - r.Testing.Errorf("Unexpected combined std[err,out] found.\nExpected:\n'%s'\nActual:\n'%s'", fullExpectedCombinedOut, r.CombinedOut) - } -} diff --git a/src/internal/common/apt.go b/src/internal/common/apt.go deleted file mode 100644 index b497a66..0000000 --- a/src/internal/common/apt.go +++ /dev/null @@ -1,127 +0,0 @@ -package common - -import ( - "errors" - "fmt" - "sort" - "strings" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/exec" - "awalsh128.com/cache-apt-pkgs-action/src/internal/logging" -) - -// An APT package name and version representation. -type AptPackage struct { - Name string - Version string -} - -type AptPackages []AptPackage - -// Serialize the APT packages into lines of =. -func (ps AptPackages) Serialize() string { - tokens := []string{} - for _, p := range ps { - tokens = append(tokens, p.Name+"="+p.Version) - } - return strings.Join(tokens, " ") -} - -func isErrLine(line string) bool { - return strings.HasPrefix(line, "E: ") || strings.HasPrefix(line, "N: ") -} - -// Resolves virtual packages names to their concrete one. -func getNonVirtualPackage(executor exec.Executor, name string) (pkg *AptPackage, err error) { - execution := executor.Exec("bash", "-c", fmt.Sprintf("apt-cache showpkg %s | grep -A 1 \"Reverse Provides\" | tail -1", name)) - err = execution.Error() - if err != nil { - logging.Fatal(err) - return pkg, err - } - if isErrLine(execution.CombinedOut) { - return pkg, execution.Error() - } - splitLine := GetSplitLine(execution.CombinedOut, " ", 3) - if len(splitLine.Words) < 2 { - return pkg, fmt.Errorf("unable to parse space delimited line's package name and version from apt-cache showpkg output below:\n%s", execution.CombinedOut) - } - return &AptPackage{Name: splitLine.Words[0], Version: splitLine.Words[1]}, nil -} - -func getPackage(executor exec.Executor, paragraph string) (pkg *AptPackage, err error) { - errMsgs := []string{} - for _, splitLine := range GetSplitLines(paragraph, ":", 2) { - if len(splitLine.Words) < 2 { - logging.Debug("Skipping invalid line: %+v\n", splitLine.Line) - continue - } - switch splitLine.Words[0] { - case "Package": - // Initialize since this will provide the first struct value if present. - pkg = &AptPackage{} - pkg.Name = splitLine.Words[1] - - case "Version": - pkg.Version = splitLine.Words[1] - - case "N": - // e.g. Can't select versions from package 'libvips' as it is purely virtual - if strings.Contains(splitLine.Words[1], "as it is purely virtual") { - return getNonVirtualPackage(executor, GetSplitLine(splitLine.Words[1], "'", 4).Words[2]) - } - if strings.HasPrefix(splitLine.Words[1], "Unable to locate package") && !ArrContainsString(errMsgs, splitLine.Line) { - errMsgs = append(errMsgs, splitLine.Line) - } - case "E": - if !ArrContainsString(errMsgs, splitLine.Line) { - errMsgs = append(errMsgs, splitLine.Line) - } - } - } - if len(errMsgs) == 0 { - return pkg, nil - } - return pkg, errors.New(strings.Join(errMsgs, "\n")) -} - -// Gets the APT based packages as a sorted by package name list (normalized). -func GetAptPackages(executor exec.Executor, names []string) (AptPackages, error) { - prefixArgs := []string{"--quiet=0", "--no-all-versions", "show"} - execution := executor.Exec("apt-cache", append(prefixArgs, names...)...) - pkgs := []AptPackage{} - - err := execution.Error() - if err != nil { - logging.Fatal(err) - return pkgs, err - } - - errMsgs := []string{} - - for _, paragraph := range strings.Split(execution.CombinedOut, "\n\n") { - trimmed := strings.TrimSpace(paragraph) - if trimmed == "" { - continue - } - pkg, err := getPackage(executor, trimmed) - if err != nil { - errMsgs = append(errMsgs, err.Error()) - } else if pkg != nil { // Ignore cases where no package parsed and no errors occurred. - pkgs = append(pkgs, *pkg) - } - } - - if len(errMsgs) > 0 { - errMsgs = append(errMsgs, strings.Join(errMsgs, "\n")) - } - - sort.Slice(pkgs, func(i, j int) bool { - return pkgs[i].Name < pkgs[j].Name - }) - if len(errMsgs) > 0 { - return pkgs, errors.New(strings.Join(errMsgs, "\n")) - } - - return pkgs, nil -} diff --git a/src/internal/common/io.go b/src/internal/common/io.go deleted file mode 100644 index a05a62e..0000000 --- a/src/internal/common/io.go +++ /dev/null @@ -1,85 +0,0 @@ -package common - -import ( - "io" - "os" - "path/filepath" -) - -func AppendFile(source string, destination string) error { - err := createDirectoryIfNotPresent(filepath.Dir(destination)) - if err != nil { - return err - } - in, err := os.Open(source) - if err != nil { - return err - } - defer in.Close() - - out, err := os.OpenFile(destination, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return err - } - defer out.Close() - - data, err := io.ReadAll(in) - if err != nil { - return err - } - - _, err = out.Write(data) - if err != nil { - return err - } - - return nil -} - -func CopyFile(source string, destination string) error { - err := createDirectoryIfNotPresent(filepath.Dir(destination)) - if err != nil { - return err - } - in, err := os.Open(source) - if err != nil { - return err - } - defer in.Close() - - out, err := os.Create(destination) - if err != nil { - return err - } - defer out.Close() - - data, err := io.ReadAll(in) - if err != nil { - return err - } - - _, err = out.Write(data) - if err != nil { - return err - } - - return nil -} - -func MoveFile(source string, destination string) error { - err := createDirectoryIfNotPresent(filepath.Dir(destination)) - if err != nil { - return err - } - return os.Rename(source, destination) -} - -func createDirectoryIfNotPresent(path string) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - err := os.MkdirAll(path, 0755) - if err != nil { - return err - } - } - return nil -} diff --git a/src/internal/common/strings.go b/src/internal/common/strings.go deleted file mode 100644 index 05da5a6..0000000 --- a/src/internal/common/strings.go +++ /dev/null @@ -1,44 +0,0 @@ -package common - -import ( - "strings" -) - -// Checks if an exact string is in an array of strings. -func ArrContainsString(arr []string, element string) bool { - for _, x := range arr { - if x == element { - return true - } - } - return false -} - -// A line that has been split into words. -type SplitLine struct { - Line string // The original line. - Words []string // The split words in the line. -} - -// Splits a line into words by the delimiter and max number of delimitation. -func GetSplitLine(line string, delimiter string, numWords int) SplitLine { - words := strings.SplitN(line, delimiter, numWords) - trimmedWords := make([]string, len(words)) - for i, word := range words { - trimmedWords[i] = strings.TrimSpace(word) - } - return SplitLine{line, trimmedWords} -} - -// Splits a paragraph into lines by newline and then splits each line into words specified by the delimiter and max number of delimitation. -func GetSplitLines(paragraph string, delimiter string, numWords int) []SplitLine { - lines := []SplitLine{} - for _, line := range strings.Split(paragraph, "\n") { - trimmed := strings.TrimSpace(line) - if trimmed == "" { - continue - } - lines = append(lines, GetSplitLine(trimmed, delimiter, numWords)) - } - return lines -} diff --git a/src/internal/exec/binexecutor.go b/src/internal/exec/binexecutor.go deleted file mode 100644 index b290139..0000000 --- a/src/internal/exec/binexecutor.go +++ /dev/null @@ -1,37 +0,0 @@ -package exec - -import ( - "fmt" - "os/exec" - "strings" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/logging" -) - -// An executor that proxies command executions from the OS. -// -// NOTE: Extra abstraction layer needed for testing and replay. -type BinExecutor struct{} - -func (c *BinExecutor) Exec(name string, arg ...string) *Execution { - cmd := exec.Command(name, arg...) - - out, err := cmd.CombinedOutput() - if err != nil { - logging.Fatal(err) - } - - execution := &Execution{ - Cmd: name + " " + strings.Join(arg, " "), - CombinedOut: string(out), - ExitCode: cmd.ProcessState.ExitCode(), - } - - logging.DebugLazy(func() string { - return fmt.Sprintf("EXECUTION-OBJ-START\n%s\nEXECUTION-OBJ-END", execution.Serialize()) - }) - if err != nil { - logging.Fatal(execution.Error()) - } - return execution -} diff --git a/src/internal/exec/executor.go b/src/internal/exec/executor.go deleted file mode 100644 index c9c4d0c..0000000 --- a/src/internal/exec/executor.go +++ /dev/null @@ -1,49 +0,0 @@ -package exec - -import ( - "encoding/json" - "fmt" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/logging" -) - -type Executor interface { - // Executes a command and either returns the output or exits the programs and writes the output (including error) to STDERR. - Exec(name string, arg ...string) *Execution -} - -type Execution struct { - Cmd string - CombinedOut string - ExitCode int -} - -// Gets the error, if the command ran with a non-zero exit code. -func (e *Execution) Error() error { - if e.ExitCode == 0 { - return nil - } - return fmt.Errorf( - "Error encountered running %s\nExited with status code %d; see combined std[out,err] below:\n%s", - e.Cmd, - e.ExitCode, - e.CombinedOut, - ) -} - -func DeserializeExecution(payload string) *Execution { - var execution Execution - err := json.Unmarshal([]byte(payload), &execution) - if err != nil { - logging.Fatalf("Error encountered deserializing Execution object.\n%s", err) - } - return &execution -} - -func (e *Execution) Serialize() string { - bytes, err := json.MarshalIndent(e, "", " ") - if err != nil { - logging.Fatalf("Error encountered serializing Execution object.\n%s", err) - } - return string(bytes) -} diff --git a/src/internal/exec/replayexecutor.go b/src/internal/exec/replayexecutor.go deleted file mode 100644 index 674c71d..0000000 --- a/src/internal/exec/replayexecutor.go +++ /dev/null @@ -1,74 +0,0 @@ -package exec - -import ( - "bufio" - "os" - "strings" - - "awalsh128.com/cache-apt-pkgs-action/src/internal/logging" -) - -// An executor that replays execution results from a recorded result. -type ReplayExecutor struct { - logFilepath string - cmdExecs map[string]*Execution -} - -func NewReplayExecutor(logFilepath string) *ReplayExecutor { - file, err := os.Open(logFilepath) - if err != nil { - logging.Fatal(err) - } - defer file.Close() - - scanner := bufio.NewScanner(file) - - cmdExecs := make(map[string]*Execution) - - for scanner.Scan() { - line := scanner.Text() - if strings.Contains(line, "EXECUTION-OBJ-START") { - payload := "" - for scanner.Scan() { - line = scanner.Text() - if strings.Contains(line, "EXECUTION-OBJ-END") { - execution := DeserializeExecution(payload) - cmdExecs[execution.Cmd] = execution - break - } else { - payload += line + "\n" - } - } - } - } - - if err := scanner.Err(); err != nil { - logging.Fatal(err) - } - return &ReplayExecutor{logFilepath, cmdExecs} -} - -func (e *ReplayExecutor) getCmds() []string { - cmds := []string{} - for cmd := range e.cmdExecs { - cmds = append(cmds, cmd) - } - return cmds -} - -func (e *ReplayExecutor) Exec(name string, arg ...string) *Execution { - cmd := name + " " + strings.Join(arg, " ") - value, ok := e.cmdExecs[cmd] - if !ok { - var available string - if len(e.getCmds()) > 0 { - available = "\n" + strings.Join(e.getCmds(), "\n") - } else { - available = " NONE" - } - logging.Fatalf( - "Unable to replay command '%s'.\n"+ - "No command found in the debug log; available commands:%s", cmd, available) - } - return value -} diff --git a/src/internal/logging/logger.go b/src/internal/logging/logger.go deleted file mode 100644 index 5b0bcdd..0000000 --- a/src/internal/logging/logger.go +++ /dev/null @@ -1,57 +0,0 @@ -package logging - -import ( - "fmt" - "log" - "os" - "path/filepath" -) - -type Logger struct { - wrapped *log.Logger - Filename string - Debug bool -} - -var logger *Logger - -var LogFilepath = os.Args[0] + ".log" - -func Init(filename string, debug bool) *Logger { - os.Remove(LogFilepath) - file, err := os.OpenFile(LogFilepath, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - log.Fatal(err) - os.Exit(2) - } - cwd, _ := os.Getwd() - logger = &Logger{ - wrapped: log.New(file, "", log.LstdFlags), - Filename: filepath.Join(cwd, file.Name()), - Debug: debug, - } - Debug("Debug log created at %s", logger.Filename) - return logger -} - -func DebugLazy(getLine func() string) { - if logger.Debug { - logger.wrapped.Println(getLine()) - } -} - -func Debug(format string, a ...any) { - if logger.Debug { - logger.wrapped.Printf(format, a...) - } -} - -func Fatal(err error) { - fmt.Fprintf(os.Stderr, "%s", err.Error()) - logger.wrapped.Fatal(err) -} - -func Fatalf(format string, a ...any) { - fmt.Fprintf(os.Stderr, format+"\n", a...) - logger.wrapped.Fatalf(format, a...) -} diff --git a/src/io.ts b/src/io.ts new file mode 100644 index 0000000..2d4b9be --- /dev/null +++ b/src/io.ts @@ -0,0 +1,106 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as crypto from "crypto"; +import * as os from "os"; +import { type CommandRunner } from "../../ts-apt/dist/index.js"; + +export function isAptListsFresh(): boolean { + const aptListsPath = "/var/lib/apt/lists"; + const maxDepth = 5; + + function search(currentPath: string, currentDepth: number): boolean { + if (currentDepth > maxDepth) return false; + + try { + const stats = fs.statSync(currentPath); + if (stats.isDirectory()) { + const entries = fs.readdirSync(currentPath); + for (const entry of entries) { + const fullPath = path.join(currentPath, entry); + if (search(fullPath, currentDepth + 1)) { + return true; + } + } + } else { + return true; + } + } catch (error) { + // Ignore permission errors or inaccessible paths + } + return false; + } + + return search(aptListsPath, 0); +} + +export class Package { + constructor( + readonly name: string, + readonly version: string, + ) {} + + serialize(): string { + return `${this.name}@${this.version}`; + } +} + +const FORCE_UPDATE_INCREMENT = "4"; +const CACHE_DIRNAME = "cache-apt-pkgs"; +const CACHE_PREFIX = "cache-apt-pkgs_"; + +export class CacheKey { + readonly version: string, + readonly forceUpdateIncrement: string, + readonly arch: string, + readonly normalizedPackages: PackageName[], + + constructor(version: string, forceUpdateIncrement: string, arch: string, normalizedPackages: PackageName[]) { + this.version = version; + this.forceUpdateIncrement = forceUpdateIncrement; + this.arch = arch; + this.normalizedPackages = normalizedPackages; + } + + serialize(): string { + return `${this.version}|${this.forceUpdateIncrement}|${this.arch}|${this.normalizedPackages.join(",")}`; + } +} + +export function deserializeCacheKey(serialized: string): CacheKey { + const parts = serialized.split("|"); + if (parts.length !== 4) { + throw new Error(`Invalid serialized cache key: ${serialized}`); + } + const [version, forceUpdateIncrement, arch, normalizedPackagesStr] = parts; + const normalizedPackages = normalizedPackagesStr!.split(","); + return new CacheKey( + version!, + forceUpdateIncrement!, + arch!, + normalizedPackages, + ); +} + +export class Cache { + private readonly cachePath: string; + private readonly commandRunner: CommandRunner; + + constructor(cacheDir: string = CACHE_DIRNAME, commandRunner: CommandRunner) { + this.cachePath = path.join(os.homedir(), cacheDir); + this.commandRunner = commandRunner; + } + + async getKey(normalizedPackages: string[], version: string): Promise { + const architecture = await ( + await this.commandRunner.run("arch") + ).stdout.trim(); + let value = `${normalizedPackages.join(" ")} @ ${version} ${FORCE_UPDATE_INCREMENT}`; + + if (architecture !== "x86_64") { + value = `${value} ${architecture}`; + } + + const hash = crypto.createHash("md5").update(value).digest("hex"); + return `${CACHE_PREFIX}${hash}`; + } +} diff --git a/src/manifest.ts b/src/manifest.ts new file mode 100644 index 0000000..1314678 --- /dev/null +++ b/src/manifest.ts @@ -0,0 +1,35 @@ +import { ActionPackageName } from "./action.js"; +import fs from "fs"; +import { CacheKey, deserializeCacheKey } from "./io.js"; + +class ManifestEntry { + readonly packageName: ActionPackageName; + readonly filepaths: string[]; + + constructor(packageName: ActionPackageName, filepaths: string[]) { + this.packageName = packageName; + this.filepaths = filepaths; + } +} + +class Manifest { + readonly cacheTimestamp: string; + readonly cacheTimestampMs: string; + readonly cacheKey: CacheKey; + readonly entries: ManifestEntry[]; + + constructor(cacheDate: Date, cacheKey: CacheKey, entries: ManifestEntry[]) { + this.cacheTimestamp = cacheDate.toISOString(); + this.cacheTimestampMs = new Date(this.cacheTimestamp).getTime().toString(); + this.cacheKey = cacheKey; + this.entries = entries; + } + + readFromFile(filepath: string): Manifest | null { + fs.readFileSync(file, JSON.parse()) + } + + writeToFile(filePath: string): void { + fs.writeFileSync(filePath, JSON.stringify(this, null, 2), "utf-8"); + } +} diff --git a/test/action.test.ts b/test/action.test.ts new file mode 100644 index 0000000..0308572 --- /dev/null +++ b/test/action.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; +import { normalizeInputPackages, parseBoolean } from "../src/action.js"; + +describe("action utils", () => { + it("normalizes package list syntax", () => { + const input = " git, curl \\\n jq "; + expect(normalizeInputPackages(input)).toEqual(["curl", "git", "jq"]); + }); + + it("parses true/false values", () => { + expect(parseBoolean("true", "debug")).toBe(true); + expect(parseBoolean("false", "debug")).toBe(false); + }); + + it("fails for invalid booleans", () => { + expect(() => parseBoolean("TRUE", "debug")).toThrow(); + }); +}); diff --git a/test/manifest.test.ts b/test/manifest.test.ts new file mode 100644 index 0000000..a1f83b0 --- /dev/null +++ b/test/manifest.test.ts @@ -0,0 +1,22 @@ +import os from "node:os"; +import path from "node:path"; +import fs from "node:fs"; +import { describe, expect, it } from "vitest"; +import { readManifestAsCsv, writeManifest } from "../src/manifest.js"; + +describe("manifest", () => { + it("writes sorted entries and reads csv output", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "manifest-test-")); + const filePath = path.join(tempDir, "manifest.log"); + + writeManifest(filePath, ["z=2", "a=1", "m=9"]); + + expect(fs.readFileSync(filePath, "utf8")).toBe("a=1\nm=9\nz=2"); + expect(readManifestAsCsv(filePath)).toBe("a=1,m=9,z=2"); + }); + + it("returns empty csv for missing files", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "manifest-missing-")); + expect(readManifestAsCsv(path.join(tempDir, "none.log"))).toBe(""); + }); +}); diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..c68163d --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2023", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noUncheckedIndexedAccess": true, + "declaration": true, + "sourceMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "lib": [ + "ES2023" + ] + } +} \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..ff902cd --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.base.json", + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "test", + "dist" + ], + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "types": [ + "node" + ] + } +} \ No newline at end of file diff --git a/tsconfig.dev.json b/tsconfig.dev.json new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..509f968 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.base.json", + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ], + "compilerOptions": { + "types": [ + "node", + "vitest/globals" + ], + "noEmit": true + } +} \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..0b2383b --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + environment: "node", + include: ["test/**/*.test.ts"], + testTimeout: 120000, + }, +});