Compare commits
5 Commits
coverity-t
...
failed-val
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110a9ef105 | ||
|
|
6bc358ba38 | ||
|
|
9aa3cc9c8f | ||
|
|
6de4db100f | ||
|
|
b13143280c |
@@ -1,14 +0,0 @@
|
||||
# Disable CodeRabbit auto-review to prevent verbose comments on PRs.
|
||||
# When enabled: false, CodeRabbit won't attempt reviews and won't post
|
||||
# "Review skipped" or other automated comments.
|
||||
reviews:
|
||||
auto_review:
|
||||
enabled: false
|
||||
review_status: false
|
||||
high_level_summary: false
|
||||
poem: false
|
||||
sequence_diagrams: false
|
||||
changed_files_summary: false
|
||||
tools:
|
||||
github-checks:
|
||||
enabled: false
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -15,10 +15,6 @@ so you understand the process and the expectations.
|
||||
- volunteering contributions effectively
|
||||
- how to get help and our review process.
|
||||
|
||||
PR stuck in review? We have two Nix team meetings per week online that are open for everyone in a jitsi conference:
|
||||
|
||||
- https://calendar.google.com/calendar/u/0/embed?src=b9o52fobqjak8oq8lfkhg3t0qg@group.calendar.google.com
|
||||
|
||||
-->
|
||||
|
||||
## Motivation
|
||||
|
||||
83
.github/actions/install-nix-action/action.yaml
vendored
83
.github/actions/install-nix-action/action.yaml
vendored
@@ -4,29 +4,15 @@ inputs:
|
||||
dogfood:
|
||||
description: "Whether to use Nix installed from the latest artifact from master branch"
|
||||
required: true # Be explicit about the fact that we are using unreleased artifacts
|
||||
experimental-installer:
|
||||
description: "Whether to use the experimental installer to install Nix"
|
||||
default: false
|
||||
experimental-installer-version:
|
||||
description: "Version of the experimental installer to use. If `latest`, the newest artifact from the default branch is used."
|
||||
# TODO: This should probably be pinned to a release after https://github.com/NixOS/experimental-nix-installer/pull/49 lands in one
|
||||
default: "latest"
|
||||
extra_nix_config:
|
||||
description: "Gets appended to `/etc/nix/nix.conf` if passed."
|
||||
install_url:
|
||||
description: "URL of the Nix installer"
|
||||
required: false
|
||||
default: "https://releases.nixos.org/nix/nix-2.32.1/install"
|
||||
tarball_url:
|
||||
description: "URL of the Nix tarball to use with the experimental installer"
|
||||
required: false
|
||||
default: "https://releases.nixos.org/nix/nix-2.30.2/install"
|
||||
github_token:
|
||||
description: "Github token"
|
||||
required: true
|
||||
use_cache:
|
||||
description: "Whether to setup magic-nix-cache"
|
||||
default: true
|
||||
required: false
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -51,81 +37,14 @@ runs:
|
||||
|
||||
gh run download "$RUN_ID" --repo "$DOGFOOD_REPO" -n "$INSTALLER_ARTIFACT" -D "$INSTALLER_DOWNLOAD_DIR"
|
||||
echo "installer-path=file://$INSTALLER_DOWNLOAD_DIR" >> "$GITHUB_OUTPUT"
|
||||
TARBALL_PATH="$(find "$INSTALLER_DOWNLOAD_DIR" -name 'nix*.tar.xz' -print | head -n 1)"
|
||||
echo "tarball-path=file://$TARBALL_PATH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "::notice ::Dogfooding Nix installer from master (https://github.com/$DOGFOOD_REPO/actions/runs/$RUN_ID)"
|
||||
env:
|
||||
GH_TOKEN: ${{ inputs.github_token }}
|
||||
DOGFOOD_REPO: "NixOS/nix"
|
||||
- name: "Gather system info for experimental installer"
|
||||
shell: bash
|
||||
if: ${{ inputs.experimental-installer == 'true' }}
|
||||
run: |
|
||||
echo "::notice Using experimental installer from $EXPERIMENTAL_INSTALLER_REPO (https://github.com/$EXPERIMENTAL_INSTALLER_REPO)"
|
||||
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
EXPERIMENTAL_INSTALLER_SYSTEM="linux"
|
||||
echo "EXPERIMENTAL_INSTALLER_SYSTEM=$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
EXPERIMENTAL_INSTALLER_SYSTEM="darwin"
|
||||
echo "EXPERIMENTAL_INSTALLER_SYSTEM=$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "::error ::Unsupported RUNNER_OS: $RUNNER_OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$RUNNER_ARCH" == "X64" ]; then
|
||||
EXPERIMENTAL_INSTALLER_ARCH=x86_64
|
||||
echo "EXPERIMENTAL_INSTALLER_ARCH=$EXPERIMENTAL_INSTALLER_ARCH" >> "$GITHUB_ENV"
|
||||
elif [ "$RUNNER_ARCH" == "ARM64" ]; then
|
||||
EXPERIMENTAL_INSTALLER_ARCH=aarch64
|
||||
echo "EXPERIMENTAL_INSTALLER_ARCH=$EXPERIMENTAL_INSTALLER_ARCH" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "::error ::Unsupported RUNNER_ARCH: $RUNNER_ARCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "EXPERIMENTAL_INSTALLER_ARTIFACT=nix-installer-$EXPERIMENTAL_INSTALLER_ARCH-$EXPERIMENTAL_INSTALLER_SYSTEM" >> "$GITHUB_ENV"
|
||||
env:
|
||||
EXPERIMENTAL_INSTALLER_REPO: "NixOS/experimental-nix-installer"
|
||||
- name: "Download latest experimental installer"
|
||||
shell: bash
|
||||
id: download-latest-experimental-installer
|
||||
if: ${{ inputs.experimental-installer == 'true' && inputs.experimental-installer-version == 'latest' }}
|
||||
run: |
|
||||
RUN_ID=$(gh run list --repo "$EXPERIMENTAL_INSTALLER_REPO" --workflow ci.yml --branch main --status success --json databaseId --jq ".[0].databaseId")
|
||||
|
||||
EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR="$GITHUB_WORKSPACE/$EXPERIMENTAL_INSTALLER_ARTIFACT"
|
||||
mkdir -p "$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR"
|
||||
|
||||
gh run download "$RUN_ID" --repo "$EXPERIMENTAL_INSTALLER_REPO" -n "$EXPERIMENTAL_INSTALLER_ARTIFACT" -D "$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR"
|
||||
# Executable permissions are lost in artifacts
|
||||
find $EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR -type f -exec chmod +x {} +
|
||||
echo "installer-path=$EXPERIMENTAL_INSTALLER_DOWNLOAD_DIR" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ inputs.github_token }}
|
||||
EXPERIMENTAL_INSTALLER_REPO: "NixOS/experimental-nix-installer"
|
||||
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
|
||||
if: ${{ inputs.experimental-installer != 'true' }}
|
||||
with:
|
||||
# Ternary operator in GHA: https://www.github.com/actions/runner/issues/409#issuecomment-752775072
|
||||
install_url: ${{ inputs.dogfood == 'true' && format('{0}/install', steps.download-nix-installer.outputs.installer-path) || inputs.install_url }}
|
||||
install_options: ${{ inputs.dogfood == 'true' && format('--tarball-url-prefix {0}', steps.download-nix-installer.outputs.installer-path) || '' }}
|
||||
extra_nix_config: ${{ inputs.extra_nix_config }}
|
||||
- uses: DeterminateSystems/nix-installer-action@786fff0690178f1234e4e1fe9b536e94f5433196 # v20
|
||||
if: ${{ inputs.experimental-installer == 'true' }}
|
||||
with:
|
||||
diagnostic-endpoint: ""
|
||||
# TODO: It'd be nice to use `artifacts.nixos.org` for both of these, maybe through an `/experimental-installer/latest` endpoint? or `/commit/<hash>`?
|
||||
local-root: ${{ inputs.experimental-installer-version == 'latest' && steps.download-latest-experimental-installer.outputs.installer-path || '' }}
|
||||
source-url: ${{ inputs.experimental-installer-version != 'latest' && 'https://artifacts.nixos.org/experimental-installer/tag/${{ inputs.experimental-installer-version }}/${{ env.EXPERIMENTAL_INSTALLER_ARTIFACT }}' || '' }}
|
||||
nix-package-url: ${{ inputs.dogfood == 'true' && steps.download-nix-installer.outputs.tarball-path || (inputs.tarball_url || '') }}
|
||||
extra-conf: ${{ inputs.extra_nix_config }}
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13
|
||||
if: ${{ inputs.use_cache == 'true' }}
|
||||
with:
|
||||
diagnostic-endpoint: ''
|
||||
use-flakehub: false
|
||||
use-gha-cache: true
|
||||
source-revision: 92d9581367be2233c2d5714a2640e1339f4087d8 # main
|
||||
|
||||
37
.github/workflows/backport.yml
vendored
37
.github/workflows/backport.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Backport
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed, labeled]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
backport:
|
||||
name: Backport Pull Request
|
||||
permissions:
|
||||
# for korthout/backport-action
|
||||
contents: write
|
||||
pull-requests: write
|
||||
if: github.repository_owner == 'NixOS' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ vars.CI_APP_ID }}
|
||||
private-key: ${{ secrets.CI_APP_PRIVATE_KEY }}
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
# required to find all branches
|
||||
fetch-depth: 0
|
||||
- name: Create backport PRs
|
||||
uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1
|
||||
id: backport
|
||||
with:
|
||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||
github_token: ${{ steps.generate-token.outputs.token }}
|
||||
github_workspace: ${{ github.workspace }}
|
||||
auto_merge_enabled: true
|
||||
pull_description: |-
|
||||
Automatic backport to `${target_branch}`, triggered by a label in #${pull_number}.
|
||||
99
.github/workflows/ci.yml
vendored
99
.github/workflows/ci.yml
vendored
@@ -4,8 +4,6 @@ on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dogfood:
|
||||
@@ -14,10 +12,6 @@ on:
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
@@ -33,34 +27,9 @@ jobs:
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
use_cache: false
|
||||
- run: nix flake show --all-systems --json
|
||||
|
||||
pre-commit-checks:
|
||||
name: pre-commit checks
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config: experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: ./ci/gha/tests/pre-commit-checks
|
||||
|
||||
basic-checks:
|
||||
name: aggregate basic checks
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [pre-commit-checks, eval]
|
||||
steps:
|
||||
- name: Exit with any errors
|
||||
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
|
||||
run: |
|
||||
exit 1
|
||||
|
||||
tests:
|
||||
needs: basic-checks
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -96,6 +65,7 @@ jobs:
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
# The sandbox would otherwise be disabled by default on Darwin
|
||||
extra_nix_config: "sandbox = true"
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
# Since ubuntu 22.30, unprivileged usernamespaces are no longer allowed to map to the root user:
|
||||
# https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
|
||||
- run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
@@ -105,12 +75,6 @@ jobs:
|
||||
nix build --file ci/gha/tests/wrapper.nix componentTests -L \
|
||||
--arg withInstrumentation ${{ matrix.instrumented }} \
|
||||
--argstr stdenv "${{ matrix.stdenv }}"
|
||||
- name: Run VM tests
|
||||
run: |
|
||||
nix build --file ci/gha/tests/wrapper.nix vmTests -L \
|
||||
--arg withInstrumentation ${{ matrix.instrumented }} \
|
||||
--argstr stdenv "${{ matrix.stdenv }}"
|
||||
if: ${{ matrix.os == 'linux' }}
|
||||
- name: Run flake checks and prepare the installer tarball
|
||||
run: |
|
||||
ci/gha/tests/build-checks
|
||||
@@ -146,19 +110,9 @@ jobs:
|
||||
- scenario: on ubuntu
|
||||
runs-on: ubuntu-24.04
|
||||
os: linux
|
||||
experimental-installer: false
|
||||
- scenario: on macos
|
||||
runs-on: macos-14
|
||||
os: darwin
|
||||
experimental-installer: false
|
||||
- scenario: on ubuntu (experimental)
|
||||
runs-on: ubuntu-24.04
|
||||
os: linux
|
||||
experimental-installer: true
|
||||
- scenario: on macos (experimental)
|
||||
runs-on: macos-14
|
||||
os: darwin
|
||||
experimental-installer: true
|
||||
name: installer test ${{ matrix.scenario }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
@@ -170,22 +124,11 @@ jobs:
|
||||
path: out
|
||||
- name: Looking up the installer tarball URL
|
||||
id: installer-tarball-url
|
||||
run: |
|
||||
echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
|
||||
TARBALL_PATH="$(find "$GITHUB_WORKSPACE/out" -name 'nix*.tar.xz' -print | head -n 1)"
|
||||
echo "tarball-path=file://$TARBALL_PATH" >> "$GITHUB_OUTPUT"
|
||||
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
|
||||
if: ${{ !matrix.experimental-installer }}
|
||||
run: echo "installer-url=file://$GITHUB_WORKSPACE/out" >> "$GITHUB_OUTPUT"
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
install_url: ${{ format('{0}/install', steps.installer-tarball-url.outputs.installer-url) }}
|
||||
install_options: ${{ format('--tarball-url-prefix {0}', steps.installer-tarball-url.outputs.installer-url) }}
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
if: ${{ matrix.experimental-installer }}
|
||||
with:
|
||||
dogfood: false
|
||||
experimental-installer: true
|
||||
tarball_url: ${{ steps.installer-tarball-url.outputs.tarball-path }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: sudo apt install fish zsh
|
||||
if: matrix.os == 'linux'
|
||||
- run: brew install fish
|
||||
@@ -217,7 +160,7 @@ jobs:
|
||||
echo "docker=${{ env._DOCKER_SECRETS != '' }}" >> $GITHUB_OUTPUT
|
||||
|
||||
docker_push_image:
|
||||
needs: [tests, check_secrets]
|
||||
needs: [tests, vm_tests, check_secrets]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -230,13 +173,12 @@ jobs:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
dogfood: false
|
||||
extra_nix_config: |
|
||||
experimental-features = flakes nix-command
|
||||
- run: echo NIX_VERSION="$(nix eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
|
||||
- run: nix build .#dockerImage -L
|
||||
install_url: https://releases.nixos.org/nix/nix-2.20.3/install
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#nix.version | tr -d \")" >> $GITHUB_ENV
|
||||
- run: nix --experimental-features 'nix-command flakes' build .#dockerImage -L
|
||||
- run: docker load -i ./result/image.tar.gz
|
||||
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:$NIX_VERSION
|
||||
- run: docker tag nix:$NIX_VERSION ${{ secrets.DOCKERHUB_USERNAME }}/nix:master
|
||||
@@ -271,8 +213,27 @@ jobs:
|
||||
docker tag nix:$NIX_VERSION $IMAGE_ID:master
|
||||
docker push $IMAGE_ID:master
|
||||
|
||||
vm_tests:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }}
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- run: |
|
||||
nix build -L \
|
||||
.#hydraJobs.tests.functional_user \
|
||||
.#hydraJobs.tests.githubFlakes \
|
||||
.#hydraJobs.tests.nix-docker \
|
||||
.#hydraJobs.tests.tarballFlakes \
|
||||
;
|
||||
|
||||
flake_regressions:
|
||||
needs: tests
|
||||
needs: vm_tests
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout nix
|
||||
@@ -293,6 +254,7 @@ jobs:
|
||||
extra_nix_config:
|
||||
experimental-features = nix-command flakes
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- run: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh
|
||||
|
||||
profile_build:
|
||||
@@ -313,6 +275,7 @@ jobs:
|
||||
extra_nix_config: |
|
||||
experimental-features = flakes nix-command ca-derivations impure-derivations
|
||||
max-jobs = 1
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- run: |
|
||||
nix build -L --file ./ci/gha/profile-build buildTimeReport --out-link build-time-report.md
|
||||
cat build-time-report.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
35
.github/workflows/coverity.yml
vendored
35
.github/workflows/coverity.yml
vendored
@@ -1,35 +0,0 @@
|
||||
name: "Coverity Scan"
|
||||
|
||||
on:
|
||||
# FIXME: This is here for testing, should be removed before merging
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- coverity-test
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
name: Coverity static analysis
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/install-nix-action
|
||||
with:
|
||||
dogfood: false
|
||||
extra_nix_config: experimental-features = nix-command flakes
|
||||
- name: configure
|
||||
run: nix develop --configure
|
||||
- uses: vapier/coverity-scan-action@v1
|
||||
with:
|
||||
project: NixOS/nix
|
||||
email: ${{ secrets.COVERITY_SCAN_EMAIL }}
|
||||
token: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
build_language: cxx
|
||||
command: nix develop --build
|
||||
version: ${{ github.sha }}
|
||||
174
.mergify.yml
Normal file
174
.mergify.yml
Normal file
@@ -0,0 +1,174 @@
|
||||
queue_rules:
|
||||
- name: default
|
||||
# all required tests need to go here
|
||||
merge_conditions:
|
||||
- check-success=tests on macos
|
||||
- check-success=tests on ubuntu
|
||||
- check-success=installer test on macos
|
||||
- check-success=installer test on ubuntu
|
||||
- check-success=vm_tests
|
||||
batch_size: 5
|
||||
|
||||
pull_request_rules:
|
||||
- name: merge using the merge queue
|
||||
conditions:
|
||||
- base~=master|.+-maintenance
|
||||
- label~=merge-queue|dependencies
|
||||
actions:
|
||||
queue: {}
|
||||
|
||||
# The rules below will first create backport pull requests and put those in a merge queue.
|
||||
|
||||
- name: backport patches to 2.18
|
||||
conditions:
|
||||
- label=backport 2.18-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.18-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.19
|
||||
conditions:
|
||||
- label=backport 2.19-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.19-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.20
|
||||
conditions:
|
||||
- label=backport 2.20-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.20-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.21
|
||||
conditions:
|
||||
- label=backport 2.21-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.21-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.22
|
||||
conditions:
|
||||
- label=backport 2.22-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.22-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.23
|
||||
conditions:
|
||||
- label=backport 2.23-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- 2.23-maintenance
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.24
|
||||
conditions:
|
||||
- label=backport 2.24-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.24-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.25
|
||||
conditions:
|
||||
- label=backport 2.25-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.25-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.26
|
||||
conditions:
|
||||
- label=backport 2.26-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.26-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.27
|
||||
conditions:
|
||||
- label=backport 2.27-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.27-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.28
|
||||
conditions:
|
||||
- label=backport 2.28-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.28-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.29
|
||||
conditions:
|
||||
- label=backport 2.29-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.29-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.30
|
||||
conditions:
|
||||
- label=backport 2.30-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.30-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
|
||||
- name: backport patches to 2.31
|
||||
conditions:
|
||||
- label=backport 2.31-maintenance
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "2.31-maintenance"
|
||||
labels:
|
||||
- automatic backport
|
||||
- merge-queue
|
||||
25
COPYING
25
COPYING
@@ -1,8 +1,8 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@@ -112,7 +112,7 @@ modification follow. Pay close attention to the difference between a
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
@@ -146,7 +146,7 @@ such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
@@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
@@ -455,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
@@ -484,7 +484,8 @@ convey the exclusion of warranty; and each file should have at least the
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <https://www.gnu.org/licenses/>.
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -495,7 +496,9 @@ necessary. Here is a sample; alter the names:
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Moe Ghoul>, 1 April 1990
|
||||
Moe Ghoul, President of Vice
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,25 @@ let
|
||||
packages' = nixFlake.packages.${system};
|
||||
stdenv = (getStdenv pkgs);
|
||||
|
||||
enableSanitizersLayer = finalAttrs: prevAttrs: {
|
||||
mesonFlags =
|
||||
(prevAttrs.mesonFlags or [ ])
|
||||
++ [
|
||||
# Run all tests with UBSAN enabled. Running both with ubsan and
|
||||
# without doesn't seem to have much immediate benefit for doubling
|
||||
# the GHA CI workaround.
|
||||
#
|
||||
# TODO: Work toward enabling "address,undefined" if it seems feasible.
|
||||
# This would maybe require dropping Boost coroutines and ignoring intentional
|
||||
# memory leaks with detect_leaks=0.
|
||||
(lib.mesonOption "b_sanitize" "undefined")
|
||||
]
|
||||
++ (lib.optionals stdenv.cc.isClang [
|
||||
# https://www.github.com/mesonbuild/meson/issues/764
|
||||
(lib.mesonBool "b_lundef" false)
|
||||
]);
|
||||
};
|
||||
|
||||
collectCoverageLayer = finalAttrs: prevAttrs: {
|
||||
env =
|
||||
let
|
||||
@@ -43,33 +62,20 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
componentOverrides = (lib.optional withCoverage collectCoverageLayer);
|
||||
componentOverrides =
|
||||
(lib.optional withSanitizers enableSanitizersLayer)
|
||||
++ (lib.optional withCoverage collectCoverageLayer);
|
||||
in
|
||||
|
||||
rec {
|
||||
nixComponentsInstrumented = nixComponents.overrideScope (
|
||||
final: prev: {
|
||||
withASan = withSanitizers;
|
||||
withUBSan = withSanitizers;
|
||||
|
||||
nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; };
|
||||
# Boehm is incompatible with ASAN.
|
||||
nix-expr = prev.nix-expr.override { enableGC = !withSanitizers; };
|
||||
|
||||
mesonComponentOverrides = lib.composeManyExtensions componentOverrides;
|
||||
# Unclear how to make Perl bindings work with a dynamically linked ASAN.
|
||||
nix-perl-bindings = if withSanitizers then null else prev.nix-perl-bindings;
|
||||
}
|
||||
);
|
||||
|
||||
# Import NixOS tests using the instrumented components
|
||||
nixosTests = import ../../../tests/nixos {
|
||||
inherit lib pkgs;
|
||||
nixComponents = nixComponentsInstrumented;
|
||||
nixpkgs = nixFlake.inputs.nixpkgs;
|
||||
inherit (nixFlake.inputs) nixpkgs-23-11;
|
||||
};
|
||||
|
||||
/**
|
||||
Top-level tests for the flake outputs, as they would be built by hydra.
|
||||
These tests generally can't be overridden to run with sanitizers.
|
||||
@@ -116,7 +122,6 @@ rec {
|
||||
) nixComponentsInstrumented)
|
||||
// lib.optionalAttrs (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) {
|
||||
"${componentTestsPrefix}nix-functional-tests" = nixComponentsInstrumented.nix-functional-tests;
|
||||
"${componentTestsPrefix}nix-json-schema-checks" = nixComponentsInstrumented.nix-json-schema-checks;
|
||||
};
|
||||
|
||||
codeCoverage =
|
||||
@@ -221,20 +226,4 @@ rec {
|
||||
{
|
||||
inherit coverageProfileDrvs mergedProfdata coverageReports;
|
||||
};
|
||||
|
||||
vmTests = {
|
||||
inherit (nixosTests) s3-binary-cache-store;
|
||||
}
|
||||
// lib.optionalAttrs (!withSanitizers && !withCoverage) {
|
||||
# evalNixpkgs uses non-instrumented components from hydraJobs, so only run it
|
||||
# when not testing with sanitizers to avoid rebuilding nix
|
||||
inherit (hydraJobs.tests) evalNixpkgs;
|
||||
# FIXME: CI times out when building vm tests instrumented
|
||||
inherit (nixosTests)
|
||||
functional_user
|
||||
githubFlakes
|
||||
nix-docker
|
||||
tarballFlakes
|
||||
;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
system=$(nix eval --raw --impure --expr builtins.currentSystem)
|
||||
|
||||
echo "::group::Running pre-commit checks"
|
||||
|
||||
if nix build ".#checks.$system.pre-commit" -L; then
|
||||
echo "::endgroup::"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "::error ::Changes do not pass pre-commit checks"
|
||||
|
||||
cat <<EOF
|
||||
The code isn't formatted or doesn't pass lints. You can run pre-commit locally with:
|
||||
|
||||
nix develop -c ./maintainers/format.sh
|
||||
EOF
|
||||
|
||||
echo "::endgroup::"
|
||||
|
||||
exit 1
|
||||
@@ -88,7 +88,7 @@ manual = custom_target(
|
||||
@0@ @INPUT0@ @CURRENT_SOURCE_DIR@ > @DEPFILE@
|
||||
@0@ @INPUT1@ summary @2@ < @CURRENT_SOURCE_DIR@/source/SUMMARY.md.in > @2@/source/SUMMARY.md
|
||||
sed -e 's|@version@|@3@|g' < @INPUT2@ > @2@/book.toml
|
||||
@4@ -r -L --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/
|
||||
@4@ -r --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/
|
||||
(cd @2@; RUST_LOG=warn @1@ build -d @2@ 3>&2 2>&1 1>&3) | { grep -Fv "because fragment resolution isn't implemented" || :; } 3>&2 2>&1 1>&3
|
||||
rm -rf @2@/manual
|
||||
mv @2@/html @2@/manual
|
||||
@@ -115,7 +115,6 @@ manual = custom_target(
|
||||
builtins_md,
|
||||
rl_next_generated,
|
||||
summary_rl_next,
|
||||
json_schema_generated_files,
|
||||
nix_input,
|
||||
],
|
||||
output : [
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
rsync,
|
||||
nix-cli,
|
||||
changelog-d,
|
||||
json-schema-for-humans,
|
||||
officialRelease,
|
||||
|
||||
# Configuration Options
|
||||
@@ -33,11 +32,6 @@ mkMesonDerivation (finalAttrs: {
|
||||
fileset.difference
|
||||
(fileset.unions [
|
||||
../../.version
|
||||
# For example JSON
|
||||
../../src/libutil-tests/data/hash
|
||||
../../src/libstore-tests/data/content-address
|
||||
../../src/libstore-tests/data/store-path
|
||||
../../src/libstore-tests/data/derived-path
|
||||
# Too many different types of files to filter for now
|
||||
../../doc/manual
|
||||
./.
|
||||
@@ -61,7 +55,6 @@ mkMesonDerivation (finalAttrs: {
|
||||
jq
|
||||
python3
|
||||
rsync
|
||||
json-schema-for-humans
|
||||
changelog-d
|
||||
]
|
||||
++ lib.optionals (!officialRelease) [
|
||||
|
||||
23
doc/manual/rl-next/c-api-recoverable-errors.md
Normal file
23
doc/manual/rl-next/c-api-recoverable-errors.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
synopsis: "C API: Errors returned from your primops are not treated as recoverable by default"
|
||||
prs: [13930]
|
||||
---
|
||||
|
||||
Nix 2.32 by default remembers the error in the thunk that triggered it.
|
||||
|
||||
Previously the following sequence of events worked:
|
||||
|
||||
1. Have a thunk that invokes a primop that's defined through the C API
|
||||
2. The primop returns an error
|
||||
3. Force the thunk again
|
||||
4. The primop returns a value
|
||||
5. The thunk evaluated successfully
|
||||
|
||||
**Resolution**
|
||||
|
||||
C API consumers that rely on this must change their recoverable error calls:
|
||||
|
||||
```diff
|
||||
-nix_set_err_msg(context, NIX_ERR_*, msg);
|
||||
+nix_set_err_msg(context, NIX_ERR_RECOVERABLE, msg);
|
||||
```
|
||||
6
doc/manual/rl-next/dropped-compat.md
Normal file
6
doc/manual/rl-next/dropped-compat.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
synopsis: "Removed support for daemons and clients older than Nix 2.0"
|
||||
prs: [13951]
|
||||
---
|
||||
|
||||
We have dropped support in the daemon worker protocol for daemons and clients that don't speak at least version 18 of the protocol. This first Nix release that supports this version is Nix 2.0, released in February 2018.
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
synopsis: "Improved S3 binary cache support via HTTP"
|
||||
prs: [13823, 14026, 14120, 14131, 14135, 14144, 14170, 14190, 14198, 14206, 14209, 14222, 14223, 13752]
|
||||
issues: [13084, 12671, 11748, 12403]
|
||||
---
|
||||
|
||||
S3 binary cache operations now happen via HTTP, leveraging `libcurl`'s native
|
||||
AWS SigV4 authentication instead of the AWS C++ SDK, providing significant
|
||||
improvements:
|
||||
|
||||
- **Reduced memory usage**: Eliminates memory buffering issues that caused
|
||||
segfaults with large files
|
||||
- **Fixed upload reliability**: Resolves AWS SDK chunking errors
|
||||
(`InvalidChunkSizeError`)
|
||||
- **Lighter dependencies**: Uses lightweight `aws-crt-cpp` instead of full
|
||||
`aws-cpp-sdk`, reducing build complexity
|
||||
|
||||
The new implementation requires curl >= 7.75.0 and `aws-crt-cpp` for credential
|
||||
management.
|
||||
|
||||
All existing S3 URL formats and parameters remain supported, with the notable
|
||||
exception of multi-part uploads, which are no longer supported.
|
||||
|
||||
Note that this change also means Nix now supports S3 binary cache stores even
|
||||
if build without `aws-crt-cpp`, but only for public buckets which do not
|
||||
require auth.
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
synopsis: "S3 URLs now support object versioning via versionId parameter"
|
||||
prs: [14274]
|
||||
issues: [13955]
|
||||
---
|
||||
|
||||
S3 URLs now support a `versionId` query parameter to fetch specific versions
|
||||
of objects from S3 buckets with versioning enabled. This allows pinning to
|
||||
exact object versions for reproducibility and protection against unexpected
|
||||
changes:
|
||||
|
||||
```
|
||||
s3://bucket/key?region=us-east-1&versionId=abc123def456
|
||||
```
|
||||
6
doc/manual/rl-next/shorter-build-dir-names.md
Normal file
6
doc/manual/rl-next/shorter-build-dir-names.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
synopsis: "Temporary build directories no longer include derivation names"
|
||||
prs: [13839]
|
||||
---
|
||||
|
||||
Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`.
|
||||
@@ -117,12 +117,8 @@
|
||||
- [Architecture and Design](architecture/architecture.md)
|
||||
- [Formats and Protocols](protocols/index.md)
|
||||
- [JSON Formats](protocols/json/index.md)
|
||||
- [Hash](protocols/json/hash.md)
|
||||
- [Content Address](protocols/json/content-address.md)
|
||||
- [Store Path](protocols/json/store-path.md)
|
||||
- [Store Object Info](protocols/json/store-object-info.md)
|
||||
- [Derivation](protocols/json/derivation.md)
|
||||
- [Deriving Path](protocols/json/deriving-path.md)
|
||||
- [Serving Tarball Flakes](protocols/tarball-fetcher.md)
|
||||
- [Store Path Specification](protocols/store-path.md)
|
||||
- [Nix Archive (NAR) Format](protocols/nix-archive.md)
|
||||
@@ -142,7 +138,6 @@
|
||||
- [Contributing](development/contributing.md)
|
||||
- [Releases](release-notes/index.md)
|
||||
{{#include ./SUMMARY-rl-next.md}}
|
||||
- [Release 2.32 (2025-10-06)](release-notes/rl-2.32.md)
|
||||
- [Release 2.31 (2025-08-21)](release-notes/rl-2.31.md)
|
||||
- [Release 2.30 (2025-07-07)](release-notes/rl-2.30.md)
|
||||
- [Release 2.29 (2025-05-14)](release-notes/rl-2.29.md)
|
||||
|
||||
@@ -2,7 +2,6 @@ xp_features_json = custom_target(
|
||||
command : [ nix, '__dump-xp-features' ],
|
||||
capture : true,
|
||||
output : 'xp-features.json',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
experimental_features_shortlist_md = custom_target(
|
||||
|
||||
@@ -48,7 +48,8 @@ The behaviour of the collector is also influenced by the
|
||||
configuration file.
|
||||
|
||||
By default, the collector prints the total number of freed bytes when it
|
||||
finishes (or when it is interrupted).
|
||||
finishes (or when it is interrupted). With `--print-dead`, it prints the
|
||||
number of bytes that would be freed.
|
||||
|
||||
{{#include ./opt-common.md}}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ $ nix-shell
|
||||
To get a shell with one of the other [supported compilation environments](#compilation-environments):
|
||||
|
||||
```console
|
||||
$ nix-shell --attr devShells.x86_64-linux.native-clangStdenv
|
||||
$ nix-shell --attr devShells.x86_64-linux.native-clangStdenvPackages
|
||||
```
|
||||
|
||||
> **Note**
|
||||
|
||||
@@ -24,19 +24,6 @@ It is also possible to build without debugging for faster build:
|
||||
|
||||
(The first line is needed because `fortify` hardening requires at least some optimization.)
|
||||
|
||||
## Building Nix with sanitizers
|
||||
|
||||
Nix can be built with [Address](https://clang.llvm.org/docs/AddressSanitizer.html) and
|
||||
[UB](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) sanitizers using LLVM
|
||||
or GCC. This is useful when debugging memory corruption issues.
|
||||
|
||||
```console
|
||||
[nix-shell]$ export mesonBuildType=debugoptimized
|
||||
[nix-shell]$ appendToVar mesonFlags "-Dlibexpr:gc=disabled" # Disable Boehm
|
||||
[nix-shell]$ appendToVar mesonFlags "-Dbindings=false" # Disable nix-perl
|
||||
[nix-shell]$ appendToVar mesonFlags "-Db_sanitize=address,undefined"
|
||||
```
|
||||
|
||||
## Debugging the Nix Binary
|
||||
|
||||
Obtain your preferred debugger within the development shell:
|
||||
|
||||
@@ -25,31 +25,20 @@ nix build .#nix-manual
|
||||
and open `./result/share/doc/nix/manual/index.html`.
|
||||
|
||||
|
||||
To build the manual incrementally, [enter the development shell](./building.md) and configure with `doc-gen` enabled:
|
||||
|
||||
**If using interactive `nix develop`:**
|
||||
To build the manual incrementally, [enter the development shell](./building.md) and run:
|
||||
|
||||
```console
|
||||
$ nix develop
|
||||
$ mesonFlags="$mesonFlags -Ddoc-gen=true" mesonConfigurePhase
|
||||
make manual-html-open -j $NIX_BUILD_CORES
|
||||
```
|
||||
|
||||
**If using direnv:**
|
||||
In order to reflect changes to the [Makefile for the manual], clear all generated files before re-building:
|
||||
|
||||
[Makefile for the manual]: https://github.com/NixOS/nix/blob/master/doc/manual/local.mk
|
||||
|
||||
```console
|
||||
$ direnv allow
|
||||
$ bash -c 'source $stdenv/setup && mesonFlags="$mesonFlags -Ddoc-gen=true" mesonConfigurePhase'
|
||||
rm $(git ls-files doc/manual/ -o | grep -F '.md') && rmdir doc/manual/source/command-ref/new-cli && make manual-html -j $NIX_BUILD_CORES
|
||||
```
|
||||
|
||||
Then build the manual:
|
||||
|
||||
```console
|
||||
$ cd build
|
||||
$ meson compile manual
|
||||
```
|
||||
|
||||
The HTML manual will be generated at `build/src/nix-manual/manual/index.html`.
|
||||
|
||||
## Style guide
|
||||
|
||||
The goal of this style guide is to make it such that
|
||||
|
||||
@@ -7,6 +7,5 @@ experimental_feature_descriptions_md = custom_target(
|
||||
xp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
env : nix_env_for_docs,
|
||||
output : 'experimental-feature-descriptions.md',
|
||||
)
|
||||
|
||||
@@ -5,28 +5,12 @@ All built-ins are available through the global [`builtins`](#builtins-builtins)
|
||||
|
||||
Some built-ins are also exposed directly in the global scope:
|
||||
|
||||
<!-- TODO(@rhendric, #10970): this list is incomplete -->
|
||||
|
||||
- [`derivation`](#builtins-derivation)
|
||||
- `derivationStrict`
|
||||
- [`abort`](#builtins-abort)
|
||||
- [`baseNameOf`](#builtins-baseNameOf)
|
||||
- [`break`](#builtins-break)
|
||||
- [`dirOf`](#builtins-dirOf)
|
||||
- [`false`](#builtins-false)
|
||||
- [`fetchGit`](#builtins-fetchGit)
|
||||
- `fetchMercurial`
|
||||
- [`fetchTarball`](#builtins-fetchTarball)
|
||||
- [`fetchTree`](#builtins-fetchTree)
|
||||
- [`fromTOML`](#builtins-fromTOML)
|
||||
- [`import`](#builtins-import)
|
||||
- [`isNull`](#builtins-isNull)
|
||||
- [`map`](#builtins-map)
|
||||
- [`null`](#builtins-null)
|
||||
- [`placeholder`](#builtins-placeholder)
|
||||
- [`removeAttrs`](#builtins-removeAttrs)
|
||||
- `scopedImport`
|
||||
- [`abort`](#builtins-abort)
|
||||
- [`throw`](#builtins-throw)
|
||||
- [`toString`](#builtins-toString)
|
||||
- [`true`](#builtins-true)
|
||||
|
||||
<dl>
|
||||
<dt id="builtins-derivation"><a href="#builtins-derivation"><code>derivation <var>attrs</var></code></a></dt>
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Process JSON schema documentation
|
||||
subdir('protocols')
|
||||
|
||||
summary_rl_next = custom_target(
|
||||
command : [
|
||||
bash,
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{{#include content-address-v1-fixed.md}}
|
||||
|
||||
## Examples
|
||||
|
||||
### [Text](@docroot@/store/store-object/content-address.html#method-text) method
|
||||
|
||||
```json
|
||||
{{#include schema/content-address-v1/text.json}}
|
||||
```
|
||||
|
||||
### [Nix Archive](@docroot@/store/store-object/content-address.html#method-nix-archive) method
|
||||
|
||||
```json
|
||||
{{#include schema/content-address-v1/nar.json}}
|
||||
```
|
||||
|
||||
<!-- need to convert YAML to JSON first
|
||||
## Raw Schema
|
||||
|
||||
[JSON Schema for Hash v1](schema/content-address-v1.json)
|
||||
-->
|
||||
@@ -1,7 +1,97 @@
|
||||
{{#include derivation-v3-fixed.md}}
|
||||
# Derivation JSON Format
|
||||
|
||||
<!--
|
||||
## Raw Schema
|
||||
> **Warning**
|
||||
>
|
||||
> This JSON format is currently
|
||||
> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
|
||||
> and subject to change.
|
||||
|
||||
[JSON Schema for Derivation v3](schema/derivation-v3.json)
|
||||
-->
|
||||
The JSON serialization of a
|
||||
[derivations](@docroot@/glossary.md#gloss-store-derivation)
|
||||
is a JSON object with the following fields:
|
||||
|
||||
* `name`:
|
||||
The name of the derivation.
|
||||
This is used when calculating the store paths of the derivation's outputs.
|
||||
|
||||
* `outputs`:
|
||||
Information about the output paths of the derivation.
|
||||
This is a JSON object with one member per output, where the key is the output name and the value is a JSON object with these fields:
|
||||
|
||||
* `path`:
|
||||
The output path, if it is known in advanced.
|
||||
Otherwise, `null`.
|
||||
|
||||
|
||||
* `method`:
|
||||
For an output which will be [content addressed], a string representing the [method](@docroot@/store/store-object/content-address.md) of content addressing that is chosen.
|
||||
Valid method strings are:
|
||||
|
||||
- [`flat`](@docroot@/store/store-object/content-address.md#method-flat)
|
||||
- [`nar`](@docroot@/store/store-object/content-address.md#method-nix-archive)
|
||||
- [`text`](@docroot@/store/store-object/content-address.md#method-text)
|
||||
- [`git`](@docroot@/store/store-object/content-address.md#method-git)
|
||||
|
||||
Otherwise, `null`.
|
||||
|
||||
* `hashAlgo`:
|
||||
For an output which will be [content addressed], the name of the hash algorithm used.
|
||||
Valid algorithm strings are:
|
||||
|
||||
- `blake3`
|
||||
- `md5`
|
||||
- `sha1`
|
||||
- `sha256`
|
||||
- `sha512`
|
||||
|
||||
* `hash`:
|
||||
For fixed-output derivations, the expected content hash in base-16.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```json
|
||||
> "outputs": {
|
||||
> "out": {
|
||||
> "path": "/nix/store/2543j7c6jn75blc3drf4g5vhb1rhdq29-source",
|
||||
> "method": "nar",
|
||||
> "hashAlgo": "sha256",
|
||||
> "hash": "6fc80dcc62179dbc12fc0b5881275898f93444833d21b89dfe5f7fbcbb1d0d62"
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
* `inputSrcs`:
|
||||
A list of store paths on which this derivation depends.
|
||||
|
||||
* `inputDrvs`:
|
||||
A JSON object specifying the derivations on which this derivation depends, and what outputs of those derivations.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```json
|
||||
> "inputDrvs": {
|
||||
> "/nix/store/6lkh5yi7nlb7l6dr8fljlli5zfd9hq58-curl-7.73.0.drv": ["dev"],
|
||||
> "/nix/store/fn3kgnfzl5dzym26j8g907gq3kbm8bfh-unzip-6.0.drv": ["out"]
|
||||
> }
|
||||
> ```
|
||||
|
||||
specifies that this derivation depends on the `dev` output of `curl`, and the `out` output of `unzip`.
|
||||
|
||||
* `system`:
|
||||
The system type on which this derivation is to be built
|
||||
(e.g. `x86_64-linux`).
|
||||
|
||||
* `builder`:
|
||||
The absolute path of the program to be executed to run the build.
|
||||
Typically this is the `bash` shell
|
||||
(e.g. `/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash`).
|
||||
|
||||
* `args`:
|
||||
The command-line arguments passed to the `builder`.
|
||||
|
||||
* `env`:
|
||||
The environment passed to the `builder`.
|
||||
|
||||
* `structuredAttrs`:
|
||||
[Strucutured Attributes](@docroot@/store/derivation/index.md#structured-attrs), only defined if the derivation contains them.
|
||||
Structured attributes are JSON, and thus embedded as-is.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{{#include deriving-path-v1-fixed.md}}
|
||||
|
||||
## Examples
|
||||
|
||||
### Constant
|
||||
|
||||
```json
|
||||
{{#include schema/deriving-path-v1/single_opaque.json}}
|
||||
```
|
||||
|
||||
### Output of static derivation
|
||||
|
||||
```json
|
||||
{{#include schema/deriving-path-v1/single_built.json}}
|
||||
```
|
||||
|
||||
### Output of dynamic derivation
|
||||
|
||||
```json
|
||||
{{#include schema/deriving-path-v1/single_built_built.json}}
|
||||
```
|
||||
@@ -1,17 +0,0 @@
|
||||
# For some reason, backticks in the JSON schema are being escaped rather
|
||||
# than being kept as intentional code spans. This removes all backtick
|
||||
# escaping, which is an ugly solution, but one that is fine, because we
|
||||
# are not using backticks for any other purpose.
|
||||
s/\\`/`/g
|
||||
|
||||
# The way that semi-external references are rendered (i.e. ones to
|
||||
# sibling schema files, as opposed to separate website ones, is not nice
|
||||
# for humans. Replace it with a nice relative link within the manual
|
||||
# instead.
|
||||
#
|
||||
# As we have more such relative links, more replacements of this nature
|
||||
# should appear below.
|
||||
s^\(./hash-v1.yaml\)\?#/$defs/algorithm^[JSON format for `Hash`](./hash.html#algorithm)^g
|
||||
s^\(./hash-v1.yaml\)^[JSON format for `Hash`](./hash.html)^g
|
||||
s^\(./content-address-v1.yaml\)\?#/$defs/method^[JSON format for `ContentAddress`](./content-address.html#method)^g
|
||||
s^\(./content-address-v1.yaml\)^[JSON format for `ContentAddress`](./content-address.html)^g
|
||||
@@ -1,33 +0,0 @@
|
||||
{{#include hash-v1-fixed.md}}
|
||||
|
||||
## Examples
|
||||
|
||||
### SHA-256 with Base64 encoding
|
||||
|
||||
```json
|
||||
{{#include schema/hash-v1/sha256-base64.json}}
|
||||
```
|
||||
|
||||
### SHA-256 with Base16 (hexadecimal) encoding
|
||||
|
||||
```json
|
||||
{{#include schema/hash-v1/sha256-base16.json}}
|
||||
```
|
||||
|
||||
### SHA-256 with Nix32 encoding
|
||||
|
||||
```json
|
||||
{{#include schema/hash-v1/sha256-nix32.json}}
|
||||
```
|
||||
|
||||
### BLAKE3 with Base64 encoding
|
||||
|
||||
```json
|
||||
{{#include schema/hash-v1/blake3-base64.json}}
|
||||
```
|
||||
|
||||
<!--
|
||||
## Raw Schema
|
||||
|
||||
[JSON Schema for Hash v1](schema/hash-v1.json)
|
||||
-->
|
||||
@@ -1,17 +0,0 @@
|
||||
# Configuration file for json-schema-for-humans
|
||||
#
|
||||
# https://github.com/coveooss/json-schema-for-humans/blob/main/docs/examples/examples_md_default/Configuration.md
|
||||
|
||||
template_name: md
|
||||
show_toc: true
|
||||
# impure timestamp and distracting
|
||||
with_footer: false
|
||||
recursive_detection_depth: 3
|
||||
show_breadcrumbs: false
|
||||
description_is_markdown: true
|
||||
template_md_options:
|
||||
properties_table_columns:
|
||||
- Property
|
||||
- Type
|
||||
- Pattern
|
||||
- Title/Description
|
||||
@@ -1,77 +0,0 @@
|
||||
# Tests in: ../../../../src/json-schema-checks
|
||||
|
||||
fs = import('fs')
|
||||
|
||||
# Find json-schema-for-humans if available
|
||||
json_schema_for_humans = find_program('generate-schema-doc', required : false)
|
||||
|
||||
# Configuration for json-schema-for-humans
|
||||
json_schema_config = files('json-schema-for-humans-config.yaml')
|
||||
|
||||
schemas = [
|
||||
'hash-v1',
|
||||
'content-address-v1',
|
||||
'store-path-v1',
|
||||
'derivation-v3',
|
||||
'deriving-path-v1',
|
||||
]
|
||||
|
||||
schema_files = files()
|
||||
foreach schema_name : schemas
|
||||
schema_files += files('schema' / schema_name + '.yaml')
|
||||
endforeach
|
||||
|
||||
|
||||
schema_outputs = []
|
||||
foreach schema_name : schemas
|
||||
schema_outputs += schema_name + '.md'
|
||||
endforeach
|
||||
|
||||
json_schema_generated_files = []
|
||||
|
||||
# Generate markdown documentation from JSON schema
|
||||
# Note: output must be just a filename, not a path
|
||||
gen_file = custom_target(
|
||||
schema_name + '-schema-docs.tmp',
|
||||
command : [
|
||||
json_schema_for_humans,
|
||||
'--config-file',
|
||||
json_schema_config,
|
||||
meson.current_source_dir() / 'schema',
|
||||
meson.current_build_dir(),
|
||||
],
|
||||
input : schema_files + [
|
||||
json_schema_config,
|
||||
],
|
||||
output : schema_outputs,
|
||||
capture : false,
|
||||
build_by_default : true,
|
||||
)
|
||||
|
||||
idx = 0
|
||||
if json_schema_for_humans.found()
|
||||
foreach schema_name : schemas
|
||||
#schema_file = 'schema' / schema_name + '.yaml'
|
||||
|
||||
# There is one so-so hack, and one horrible hack being done here.
|
||||
sedded_file = custom_target(
|
||||
schema_name + '-schema-docs',
|
||||
command : [
|
||||
'sed',
|
||||
'-f',
|
||||
# Out of line to avoid https://github.com/mesonbuild/meson/issues/1564
|
||||
files('fixup-json-schema-generated-doc.sed'),
|
||||
'@INPUT@',
|
||||
],
|
||||
capture : true,
|
||||
input : gen_file[idx],
|
||||
output : schema_name + '-fixed.md',
|
||||
)
|
||||
idx += 1
|
||||
json_schema_generated_files += [ sedded_file ]
|
||||
endforeach
|
||||
else
|
||||
warning(
|
||||
'json-schema-for-humans not found, skipping JSON schema documentation generation',
|
||||
)
|
||||
endif
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../src/libstore-tests/data/content-address
|
||||
@@ -1,55 +0,0 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema"
|
||||
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/content-address-v1.json"
|
||||
title: Content Address
|
||||
description: |
|
||||
This schema describes the JSON representation of Nix's `ContentAddress` type, which conveys information about [content-addressing store objects](@docroot@/store/store-object/content-address.md).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> For current methods of content addressing, this data type is a bit suspicious, because it is neither simply a content address of a file system object (the `method` is richer), nor simply a content address of a store object (the `hash` doesn't account for the references).
|
||||
> It should thus only be used in contexts where the references are also known / otherwise made tamper-resistant.
|
||||
|
||||
<!--
|
||||
TODO currently `ContentAddress` is used in both of these, and so same rationale applies, but actually in both cases the JSON is currently ad-hoc.
|
||||
That will be fixed, and as each is fixed, the example (along with a more precise link to the field in question) should be become part of the above note, so what is is saying is more clear.
|
||||
|
||||
> For example:
|
||||
|
||||
> - Fixed outputs of derivations are not allowed to have any references, so an empty reference set is statically known by assumption.
|
||||
|
||||
> - [Store object info](./store-object-info.md) includes the set of references along side the (optional) content address.
|
||||
|
||||
> This data type is thus safely used in both of these contexts.
|
||||
|
||||
-->
|
||||
|
||||
type: object
|
||||
properties:
|
||||
method:
|
||||
"$ref": "#/$defs/method"
|
||||
hash:
|
||||
title: Content Address
|
||||
description: |
|
||||
This would be the content-address itself.
|
||||
|
||||
For all current methods, this is just a content address of the file system object of the store object, [as described in the store chapter](@docroot@/store/file-system-object/content-address.md), and not of the store object as a whole.
|
||||
In particular, the references of the store object are *not* taken into account with this hash (and currently-supported methods).
|
||||
"$ref": "./hash-v1.yaml"
|
||||
required:
|
||||
- method
|
||||
- hash
|
||||
additionalProperties: false
|
||||
"$defs":
|
||||
method:
|
||||
type: string
|
||||
enum: [flat, nar, text, git]
|
||||
title: Content-Addressing Method
|
||||
description: |
|
||||
A string representing the [method](@docroot@/store/store-object/content-address.md) of content addressing that is chosen.
|
||||
|
||||
Valid method strings are:
|
||||
|
||||
- [`flat`](@docroot@/store/store-object/content-address.md#method-flat) (provided the contents are a single file)
|
||||
- [`nar`](@docroot@/store/store-object/content-address.md#method-nix-archive)
|
||||
- [`text`](@docroot@/store/store-object/content-address.md#method-text)
|
||||
- [`git`](@docroot@/store/store-object/content-address.md#method-git)
|
||||
@@ -1,203 +0,0 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema"
|
||||
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/derivation-v3.json"
|
||||
title: Derivation
|
||||
description: |
|
||||
Experimental JSON representation of a Nix derivation (version 3).
|
||||
|
||||
This schema describes the JSON representation of Nix's `Derivation` type.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> This JSON format is currently
|
||||
> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
|
||||
> and subject to change.
|
||||
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- version
|
||||
- outputs
|
||||
- inputSrcs
|
||||
- inputDrvs
|
||||
- system
|
||||
- builder
|
||||
- args
|
||||
- env
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
title: Derivation name
|
||||
description: |
|
||||
The name of the derivation.
|
||||
Used when calculating store paths for the derivation’s outputs.
|
||||
|
||||
version:
|
||||
const: 3
|
||||
title: Format version (must be 3)
|
||||
description: |
|
||||
Must be `3`.
|
||||
This is a guard that allows us to continue evolving this format.
|
||||
The choice of `3` is fairly arbitrary, but corresponds to this informal version:
|
||||
|
||||
- Version 0: A-Term format
|
||||
|
||||
- Version 1: Original JSON format, with ugly `"r:sha256"` inherited from A-Term format.
|
||||
|
||||
- Version 2: Separate `method` and `hashAlgo` fields in output specs
|
||||
|
||||
- Version 3: Drop store dir from store paths, just include base name.
|
||||
|
||||
Note that while this format is experimental, the maintenance of versions is best-effort, and not promised to identify every change.
|
||||
|
||||
outputs:
|
||||
type: object
|
||||
title: Output specifications
|
||||
description: |
|
||||
Information about the output paths of the derivation.
|
||||
This is a JSON object with one member per output, where the key is the output name and the value is a JSON object as described.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```json
|
||||
> "outputs": {
|
||||
> "out": {
|
||||
> "method": "nar",
|
||||
> "hashAlgo": "sha256",
|
||||
> "hash": "6fc80dcc62179dbc12fc0b5881275898f93444833d21b89dfe5f7fbcbb1d0d62"
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
additionalProperties:
|
||||
"$ref": "#/$defs/output"
|
||||
|
||||
inputSrcs:
|
||||
type: array
|
||||
title: Input source paths
|
||||
description: |
|
||||
List of store paths on which this derivation depends.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```json
|
||||
> "inputSrcs": [
|
||||
> "47y241wqdhac3jm5l7nv0x4975mb1975-separate-debug-info.sh",
|
||||
> "56d0w71pjj9bdr363ym3wj1zkwyqq97j-fix-pop-var-context-error.patch"
|
||||
> ]
|
||||
> ```
|
||||
items:
|
||||
$ref: "store-path-v1.yaml"
|
||||
|
||||
inputDrvs:
|
||||
type: object
|
||||
title: Input derivations
|
||||
description: |
|
||||
Mapping of derivation paths to lists of output names they provide.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```json
|
||||
> "inputDrvs": {
|
||||
> "6lkh5yi7nlb7l6dr8fljlli5zfd9hq58-curl-7.73.0.drv": ["dev"],
|
||||
> "fn3kgnfzl5dzym26j8g907gq3kbm8bfh-unzip-6.0.drv": ["out"]
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> specifies that this derivation depends on the `dev` output of `curl`, and the `out` output of `unzip`.
|
||||
patternProperties:
|
||||
"^[0123456789abcdfghijklmnpqrsvwxyz]{32}-.+\\.drv$":
|
||||
title: Store Path
|
||||
description: |
|
||||
A store path to a derivation, mapped to the outputs of that derivation.
|
||||
oneOf:
|
||||
- "$ref": "#/$defs/outputNames"
|
||||
- "$ref": "#/$defs/dynamicOutputs"
|
||||
additionalProperties: false
|
||||
|
||||
system:
|
||||
type: string
|
||||
title: Build system type
|
||||
description: |
|
||||
The system type on which this derivation is to be built
|
||||
(e.g. `x86_64-linux`).
|
||||
|
||||
builder:
|
||||
type: string
|
||||
title: Build program path
|
||||
description: |
|
||||
Absolute path of the program used to perform the build.
|
||||
Typically this is the `bash` shell
|
||||
(e.g. `/nix/store/r3j288vpmczbl500w6zz89gyfa4nr0b1-bash-4.4-p23/bin/bash`).
|
||||
|
||||
args:
|
||||
type: array
|
||||
title: Builder arguments
|
||||
description: |
|
||||
Command-line arguments passed to the `builder`.
|
||||
items:
|
||||
type: string
|
||||
|
||||
env:
|
||||
type: object
|
||||
title: Environment variables
|
||||
description: |
|
||||
Environment variables passed to the `builder`.
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
||||
structuredAttrs:
|
||||
title: Structured attributes
|
||||
description: |
|
||||
[Structured Attributes](@docroot@/store/derivation/index.md#structured-attrs), only defined if the derivation contains them.
|
||||
Structured attributes are JSON, and thus embedded as-is.
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
"$defs":
|
||||
output:
|
||||
type: object
|
||||
properties:
|
||||
path:
|
||||
$ref: "store-path-v1.yaml"
|
||||
title: Output path
|
||||
description: |
|
||||
The output path, if known in advance.
|
||||
|
||||
method:
|
||||
"$ref": "./content-address-v1.yaml#/$defs/method"
|
||||
description: |
|
||||
For an output which will be [content addressed](@docroot@/store/derivation/outputs/content-address.md), a string representing the [method](@docroot@/store/store-object/content-address.md) of content addressing that is chosen.
|
||||
See the linked original definition for further details.
|
||||
hashAlgo:
|
||||
title: Hash algorithm
|
||||
"$ref": "./hash-v1.yaml#/$defs/algorithm"
|
||||
|
||||
hash:
|
||||
type: string
|
||||
title: Expected hash value
|
||||
description: |
|
||||
For fixed-output derivations, the expected content hash in base-16.
|
||||
|
||||
outputName:
|
||||
type: string
|
||||
title: Output name
|
||||
description: Name of the derivation output to depend on
|
||||
|
||||
outputNames:
|
||||
type: array
|
||||
title: Output Names
|
||||
description: Set of names of derivation outputs to depend on
|
||||
items:
|
||||
"$ref": "#/$defs/outputName"
|
||||
|
||||
dynamicOutputs:
|
||||
type: object
|
||||
title: Dynamic Outputs
|
||||
description: |
|
||||
**Experimental feature**: [`dynamic-derivations`](@docroot@/development/experimental-features.md#xp-feature-dynamic-derivations)
|
||||
|
||||
This recursive data type allows for depending on outputs of outputs.
|
||||
properties:
|
||||
outputs:
|
||||
"$ref": "#/$defs/outputNames"
|
||||
dynamicOutputs:
|
||||
"$ref": "#/$defs/dynamicOutputs"
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../src/libstore-tests/data/derived-path
|
||||
@@ -1,27 +0,0 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema"
|
||||
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/deriving-path-v1.json"
|
||||
title: Deriving Path
|
||||
description: |
|
||||
This schema describes the JSON representation of Nix's [Deriving Path](@docroot@/store/derivation/index.md#deriving-path).
|
||||
oneOf:
|
||||
- title: Constant
|
||||
description: |
|
||||
See [Constant](@docroot@/store/derivation/index.md#deriving-path-constant) deriving path.
|
||||
$ref: "store-path-v1.yaml"
|
||||
- title: Output
|
||||
description: |
|
||||
See [Output](@docroot@/store/derivation/index.md#deriving-path-output) deriving path.
|
||||
type: object
|
||||
properties:
|
||||
drvPath:
|
||||
"$ref": "#"
|
||||
description: |
|
||||
A deriving path to a [Derivation](@docroot@/store/derivation/index.md#store-derivation), whose output is being referred to.
|
||||
output:
|
||||
type: string
|
||||
description: |
|
||||
The name of an output produced by that derivation (e.g. "out", "doc", etc.).
|
||||
required:
|
||||
- drvPath
|
||||
- output
|
||||
additionalProperties: false
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../src/libutil-tests/data/hash/
|
||||
@@ -1,54 +0,0 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema"
|
||||
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/hash-v1.json"
|
||||
title: Hash
|
||||
description: |
|
||||
A cryptographic hash value used throughout Nix for content addressing and integrity verification.
|
||||
|
||||
This schema describes the JSON representation of Nix's `Hash` type.
|
||||
type: object
|
||||
properties:
|
||||
algorithm:
|
||||
"$ref": "#/$defs/algorithm"
|
||||
format:
|
||||
type: string
|
||||
enum:
|
||||
- base64
|
||||
- nix32
|
||||
- base16
|
||||
- sri
|
||||
title: Hash format
|
||||
description: |
|
||||
The encoding format of the hash value.
|
||||
|
||||
- `base64` uses standard Base64 encoding [RFC 4648, section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4)
|
||||
- `nix32` is Nix-specific base-32 encoding
|
||||
- `base16` is lowercase hexadecimal
|
||||
- `sri` is the [Subresource Integrity format](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
|
||||
hash:
|
||||
type: string
|
||||
title: Hash
|
||||
description: |
|
||||
The encoded hash value, itself.
|
||||
|
||||
It is specified in the format specified by the `format` field.
|
||||
It must be the right length for the hash algorithm specified in the `algorithm` field, also.
|
||||
The hash value does not include any algorithm prefix.
|
||||
required:
|
||||
- algorithm
|
||||
- format
|
||||
- hash
|
||||
additionalProperties: false
|
||||
"$defs":
|
||||
algorithm:
|
||||
type: string
|
||||
enum:
|
||||
- blake3
|
||||
- md5
|
||||
- sha1
|
||||
- sha256
|
||||
- sha512
|
||||
title: Hash algorithm
|
||||
description: |
|
||||
The hash algorithm used to compute the hash value.
|
||||
|
||||
`blake3` is currently experimental and requires the [`blake-hashing`](@docroot@/development/experimental-features.md#xp-feature-blake-hashing) experimental feature.
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../../src/libstore-tests/data/store-path
|
||||
@@ -1,32 +0,0 @@
|
||||
"$schema": "http://json-schema.org/draft-07/schema"
|
||||
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/store-path-v1.json"
|
||||
title: Store Path
|
||||
description: |
|
||||
A [store path](@docroot@/store/store-path.md) identifying a store object.
|
||||
|
||||
This schema describes the JSON representation of store paths as used in various Nix JSON APIs.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> This JSON format is currently
|
||||
> [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command)
|
||||
> and subject to change.
|
||||
|
||||
## Format
|
||||
|
||||
Store paths in JSON are represented as strings containing just the hash and name portion, without the store directory prefix.
|
||||
|
||||
For example: `"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"`
|
||||
|
||||
(If the store dir is `/nix/store`, then this corresponds to the path `/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv`.)
|
||||
|
||||
## Structure
|
||||
|
||||
The format follows this pattern: `${digest}-${name}`
|
||||
|
||||
- **hash**: Digest rendered in a custom variant of [Base32](https://en.wikipedia.org/wiki/Base32) (20 arbitrary bytes become 32 ASCII characters)
|
||||
- **name**: The package name and optional version/suffix information
|
||||
|
||||
type: string
|
||||
pattern: "^[0123456789abcdfghijklmnpqrsvwxyz]{32}-.+$"
|
||||
minLength: 34
|
||||
@@ -1,15 +0,0 @@
|
||||
{{#include store-path-v1-fixed.md}}
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple store path
|
||||
|
||||
```json
|
||||
{{#include schema/store-path-v1/simple.json}}
|
||||
```
|
||||
|
||||
<!--
|
||||
## Raw Schema
|
||||
|
||||
[JSON Schema for Store Path v1](schema/store-path-v1.json)
|
||||
-->
|
||||
@@ -1,2 +0,0 @@
|
||||
# Process JSON schema documentation
|
||||
subdir('json')
|
||||
@@ -1,130 +0,0 @@
|
||||
# Release 2.32.0 (2025-10-06)
|
||||
|
||||
## Incompatible changes
|
||||
|
||||
- Removed support for daemons and clients older than Nix 2.0 [#13951](https://github.com/NixOS/nix/pull/13951)
|
||||
|
||||
We have dropped support in the daemon worker protocol for daemons and clients that don't speak at least version 18 of the protocol. This first Nix release that supports this version is Nix 2.0, released in February 2018.
|
||||
|
||||
- Derivation JSON format now uses store path basenames only [#13570](https://github.com/NixOS/nix/issues/13570) [#13980](https://github.com/NixOS/nix/pull/13980)
|
||||
|
||||
Experience with many JSON frameworks (e.g. nlohmann/json in C++, Serde in Rust, and Aeson in Haskell) has shown that the use of the store directory in JSON formats is an impediment to systematic JSON formats, because it requires the serializer/deserializer to take an extra paramater (the store directory).
|
||||
|
||||
We ultimately want to rectify this issue with all JSON formats to the extent allowed by our stability promises. To start with, we are changing the JSON format for derivations because the `nix derivation` commands are — in addition to being formally unstable — less widely used than other unstable commands.
|
||||
|
||||
See the documentation on the [JSON format for derivations](@docroot@/protocols/json/derivation.md) for further details.
|
||||
|
||||
- C API: `nix_get_attr_name_byidx`, `nix_get_attr_byidx` take a `nix_value *` instead of `const nix_value *` [#13987](https://github.com/NixOS/nix/pull/13987)
|
||||
|
||||
In order to accommodate a more optimized internal representation of attribute set merges these functions require
|
||||
a mutable `nix_value *` that might be modified on access. This does *not* break the ABI of these functions.
|
||||
|
||||
## New features
|
||||
|
||||
- C API: Add lazy attribute and list item accessors [#14030](https://github.com/NixOS/nix/pull/14030)
|
||||
|
||||
The C API now includes lazy accessor functions for retrieving values from lists and attribute sets without forcing evaluation:
|
||||
|
||||
- `nix_get_list_byidx_lazy()` - Get a list element without forcing its evaluation
|
||||
- `nix_get_attr_byname_lazy()` - Get an attribute value by name without forcing evaluation
|
||||
- `nix_get_attr_byidx_lazy()` - Get an attribute by index without forcing evaluation
|
||||
|
||||
These functions are useful when forwarding unevaluated sub-values to other lists, attribute sets, or function calls. They allow more efficient handling of Nix values by deferring evaluation until actually needed.
|
||||
|
||||
Additionally, bounds checking has been improved for all `_byidx` functions to properly validate indices before access, preventing potential out-of-bounds errors.
|
||||
|
||||
The documentation for `NIX_ERR_KEY` error handling has also been clarified to specify when this error code is returned.
|
||||
|
||||
- HTTP binary caches now support transparent compression for metadata
|
||||
|
||||
HTTP binary cache stores can now compress `.narinfo`, `.ls`, and build log files before uploading them,
|
||||
reducing bandwidth usage and storage requirements. The compression is applied transparently using the
|
||||
`Content-Encoding` header, allowing compatible clients to automatically decompress the files.
|
||||
|
||||
Three new configuration options control this behavior:
|
||||
- `narinfo-compression`: Compression method for `.narinfo` files
|
||||
- `ls-compression`: Compression method for `.ls` files
|
||||
- `log-compression`: Compression method for build logs in `log/` directory
|
||||
|
||||
Example usage:
|
||||
```
|
||||
nix copy --to 'http://cache.example.com?narinfo-compression=gzip&ls-compression=gzip' /nix/store/...
|
||||
nix store copy-log --to 'http://cache.example.com?log-compression=br' /nix/store/...
|
||||
```
|
||||
|
||||
- Temporary build directories no longer include derivation names [#13839](https://github.com/NixOS/nix/pull/13839)
|
||||
|
||||
Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`.
|
||||
|
||||
- External derivation builders [#14145](https://github.com/NixOS/nix/pull/14145)
|
||||
|
||||
These are helper programs that Nix calls to perform derivations for specified system types, e.g. by using QEMU to emulate a different type of platform. For more information, see the [`external-builders` setting](../command-ref/conf-file.md#conf-external-builders).
|
||||
|
||||
This is currently an experimental feature.
|
||||
|
||||
## Performance improvements
|
||||
|
||||
- Optimize memory usage of attribute set merges [#13987](https://github.com/NixOS/nix/pull/13987)
|
||||
|
||||
[Attribute set update operations](@docroot@/language/operators.md#update) have been optimized to
|
||||
reduce reallocations in cases when the second operand is small.
|
||||
|
||||
For typical evaluations of nixpkgs this optimization leads to ~20% less memory allocated in total
|
||||
without significantly affecting evaluation performance.
|
||||
|
||||
See [eval-attrset-update-layer-rhs-threshold](@docroot@/command-ref/conf-file.md#conf-eval-attrset-update-layer-rhs-threshold)
|
||||
|
||||
- Substituted flake inputs are no longer re-copied to the store [#14041](https://github.com/NixOS/nix/pull/14041)
|
||||
|
||||
Since 2.25, Nix would fail to store a cache entry for substituted flake inputs, which in turn would cause them to be re-copied to the store on initial evaluation. Caching these inputs results in a near doubling of performance in some cases — especially on I/O-bound machines and when using commands that fetch many inputs, like `nix flake [archive|prefetch-inputs]`.
|
||||
|
||||
- `nix flake check` now skips derivations that can be substituted [#13574](https://github.com/NixOS/nix/pull/13574)
|
||||
|
||||
Previously, `nix flake check` would evaluate and build/substitute all
|
||||
derivations. Now, it will skip downloading derivations that can be substituted.
|
||||
This can drastically decrease the time invocations take in environments where
|
||||
checks may already be cached (like in CI).
|
||||
|
||||
- `fetchTarball` and `fetchurl` now correctly substitute (#14138)
|
||||
|
||||
At some point we stopped substituting calls to `fetchTarball` and `fetchurl` with a set `narHash` to avoid incorrectly substituting things in `fetchTree`, even though it would be safe to substitute when calling the legacy `fetch{Tarball,url}`. This fixes that regression where it is safe.
|
||||
- Started moving AST allocations into a bump allocator [#14088](https://github.com/NixOS/nix/issues/14088)
|
||||
|
||||
This leaves smaller, immutable structures in the AST. So far this saves about 2% memory on a NixOS config evaluation.
|
||||
## Contributors
|
||||
|
||||
This release was made possible by the following 32 contributors:
|
||||
|
||||
- Farid Zakaria [**(@fzakaria)**](https://github.com/fzakaria)
|
||||
- dram [**(@dramforever)**](https://github.com/dramforever)
|
||||
- Ephraim Siegfried [**(@EphraimSiegfried)**](https://github.com/EphraimSiegfried)
|
||||
- Robert Hensing [**(@roberth)**](https://github.com/roberth)
|
||||
- Taeer Bar-Yam [**(@Radvendii)**](https://github.com/Radvendii)
|
||||
- Emily [**(@emilazy)**](https://github.com/emilazy)
|
||||
- Jens Petersen [**(@juhp)**](https://github.com/juhp)
|
||||
- Bernardo Meurer [**(@lovesegfault)**](https://github.com/lovesegfault)
|
||||
- Jörg Thalheim [**(@Mic92)**](https://github.com/Mic92)
|
||||
- Leandro Emmanuel Reina Kiperman [**(@kip93)**](https://github.com/kip93)
|
||||
- Marie [**(@NyCodeGHG)**](https://github.com/NyCodeGHG)
|
||||
- Ethan Evans [**(@ethanavatar)**](https://github.com/ethanavatar)
|
||||
- Yaroslav Bolyukin [**(@CertainLach)**](https://github.com/CertainLach)
|
||||
- Matej Urbas [**(@urbas)**](https://github.com/urbas)
|
||||
- Jami Kettunen [**(@JamiKettunen)**](https://github.com/JamiKettunen)
|
||||
- Clayton [**(@netadr)**](https://github.com/netadr)
|
||||
- Grégory Marti [**(@gmarti)**](https://github.com/gmarti)
|
||||
- Eelco Dolstra [**(@edolstra)**](https://github.com/edolstra)
|
||||
- rszyma [**(@rszyma)**](https://github.com/rszyma)
|
||||
- Philip Wilk [**(@philipwilk)**](https://github.com/philipwilk)
|
||||
- John Ericson [**(@Ericson2314)**](https://github.com/Ericson2314)
|
||||
- Tom Westerhout [**(@twesterhout)**](https://github.com/twesterhout)
|
||||
- Tristan Ross [**(@RossComputerGuy)**](https://github.com/RossComputerGuy)
|
||||
- Sergei Zimmerman [**(@xokdvium)**](https://github.com/xokdvium)
|
||||
- Jean-François Roche [**(@jfroche)**](https://github.com/jfroche)
|
||||
- Seth Flynn [**(@getchoo)**](https://github.com/getchoo)
|
||||
- éclairevoyant [**(@eclairevoyant)**](https://github.com/eclairevoyant)
|
||||
- Glen Huang [**(@hgl)**](https://github.com/hgl)
|
||||
- osman - オスマン [**(@osbm)**](https://github.com/osbm)
|
||||
- David McFarland [**(@corngood)**](https://github.com/corngood)
|
||||
- Cole Helbling [**(@cole-h)**](https://github.com/cole-h)
|
||||
- Sinan Mohd [**(@sinanmohd)**](https://github.com/sinanmohd)
|
||||
- Philipp Otterbein
|
||||
@@ -106,7 +106,7 @@ The system type on which the [`builder`](#attr-builder) executable is meant to b
|
||||
|
||||
A necessary condition for Nix to schedule a given derivation on some [Nix instance] is for the "system" of that derivation to match that instance's [`system` configuration option] or [`extra-platforms` configuration option].
|
||||
|
||||
By putting the `system` in each derivation, Nix allows *heterogeneous* build plans, where not all steps can be run on the same machine or same sort of machine.
|
||||
By putting the `system` in each derivation, Nix allows *heterogenous* build plans, where not all steps can be run on the same machine or same sort of machine.
|
||||
Nix can schedule builds such that it automatically builds on other platforms by [forwarding build requests](@docroot@/advanced-topics/distributed-builds.md) to other Nix instances.
|
||||
|
||||
[`system` configuration option]: @docroot@/command-ref/conf-file.md#conf-system
|
||||
|
||||
@@ -20,8 +20,7 @@ The graph of references excluding self-references thus forms a [directed acyclic
|
||||
|
||||
[directed acyclic graph]: @docroot@/glossary.md#gloss-directed-acyclic-graph
|
||||
|
||||
We can take the [transitive closure] of the references graph, in which any pair of store objects have an edge if a *path* of one or more references exists from the first to the second object.
|
||||
(A single reference always forms a path which is one reference long, but longer paths may connect objects which have no direct reference between them.)
|
||||
We can take the [transitive closure] of the references graph, which any pair of store objects have an edge not if there is a single reference from the first to the second, but a path of one or more references from the first to the second.
|
||||
The *requisites* of a store object are all store objects reachable by paths of references which start with given store object's references.
|
||||
|
||||
[transitive closure]: https://en.wikipedia.org/wiki/Transitive_closure
|
||||
|
||||
25
flake.nix
25
flake.nix
@@ -413,10 +413,6 @@
|
||||
supportsCross = false;
|
||||
};
|
||||
|
||||
"nix-json-schema-checks" = {
|
||||
supportsCross = false;
|
||||
};
|
||||
|
||||
"nix-perl-bindings" = {
|
||||
supportsCross = false;
|
||||
};
|
||||
@@ -471,27 +467,6 @@
|
||||
}
|
||||
);
|
||||
|
||||
apps = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgsFor.${system}.native;
|
||||
opener = if pkgs.stdenv.isDarwin then "open" else "xdg-open";
|
||||
in
|
||||
{
|
||||
open-manual = {
|
||||
type = "app";
|
||||
program = "${pkgs.writeShellScript "open-nix-manual" ''
|
||||
manual_path="${self.packages.${system}.nix-manual}/share/doc/nix/manual/index.html"
|
||||
if ! ${opener} "$manual_path"; then
|
||||
echo "Failed to open manual with ${opener}. Manual is located at:"
|
||||
echo "$manual_path"
|
||||
fi
|
||||
''}";
|
||||
meta.description = "Open the Nix manual in your browser";
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
devShells =
|
||||
let
|
||||
makeShell = import ./packaging/dev-shell.nix { inherit lib devFlake; };
|
||||
|
||||
@@ -203,26 +203,5 @@
|
||||
"ConnorBaker01@Gmail.com": "ConnorBaker",
|
||||
"jsoo1@asu.edu": "jsoo1",
|
||||
"hsngrmpf+github@gmail.com": "DavHau",
|
||||
"matthew@floxdev.com": "mkenigs",
|
||||
"taeer@bar-yam.me": "Radvendii",
|
||||
"beme@anthropic.com": "lovesegfault",
|
||||
"osbm@osbm.dev": "osbm",
|
||||
"jami.kettunen@protonmail.com": "JamiKettunen",
|
||||
"ephraim.siegfried@hotmail.com": "EphraimSiegfried",
|
||||
"rszyma.dev@gmail.com": "rszyma",
|
||||
"tristan.ross@determinate.systems": "RossComputerGuy",
|
||||
"corngood@gmail.com": "corngood",
|
||||
"jfroche@pyxel.be": "jfroche",
|
||||
"848000+eclairevoyant@users.noreply.github.com": "eclairevoyant",
|
||||
"petersen@redhat.com": "juhp",
|
||||
"dramforever@live.com": "dramforever",
|
||||
"me@glenhuang.com": "hgl",
|
||||
"philip.wilk@fivium.co.uk": "philipwilk",
|
||||
"me@nycode.dev": "NyCodeGHG",
|
||||
"14264576+twesterhout@users.noreply.github.com": "twesterhout",
|
||||
"sinan@sinanmohd.com": "sinanmohd",
|
||||
"42688647+netadr@users.noreply.github.com": "netadr",
|
||||
"matej.urbas@gmail.com": "urbas",
|
||||
"ethanalexevans@gmail.com": "ethanavatar",
|
||||
"greg.marti@gmail.com": "gmarti"
|
||||
"matthew@floxdev.com": "mkenigs"
|
||||
}
|
||||
@@ -177,24 +177,5 @@
|
||||
"avnik": "Alexander V. Nikolaev",
|
||||
"DavHau": null,
|
||||
"aln730": "AGawas",
|
||||
"vog": "Volker Diels-Grabsch",
|
||||
"corngood": "David McFarland",
|
||||
"twesterhout": "Tom Westerhout",
|
||||
"JamiKettunen": "Jami Kettunen",
|
||||
"dramforever": "dram",
|
||||
"philipwilk": "Philip Wilk",
|
||||
"netadr": "Clayton",
|
||||
"NyCodeGHG": "Marie",
|
||||
"jfroche": "Jean-Fran\u00e7ois Roche",
|
||||
"urbas": "Matej Urbas",
|
||||
"osbm": "osman - \u30aa\u30b9\u30de\u30f3",
|
||||
"rszyma": null,
|
||||
"eclairevoyant": "\u00e9clairevoyant",
|
||||
"Radvendii": "Taeer Bar-Yam",
|
||||
"sinanmohd": "Sinan Mohd",
|
||||
"ethanavatar": "Ethan Evans",
|
||||
"gmarti": "Gr\u00e9gory Marti",
|
||||
"lovesegfault": "Bernardo Meurer",
|
||||
"EphraimSiegfried": "Ephraim Siegfried",
|
||||
"hgl": "Glen Huang"
|
||||
"vog": "Volker Diels-Grabsch"
|
||||
}
|
||||
@@ -104,6 +104,151 @@
|
||||
};
|
||||
shellcheck = {
|
||||
enable = true;
|
||||
excludes = [
|
||||
# We haven't linted these files yet
|
||||
''^config/install-sh$''
|
||||
''^misc/bash/completion\.sh$''
|
||||
''^misc/fish/completion\.fish$''
|
||||
''^misc/zsh/completion\.zsh$''
|
||||
''^scripts/create-darwin-volume\.sh$''
|
||||
''^scripts/install-darwin-multi-user\.sh$''
|
||||
''^scripts/install-multi-user\.sh$''
|
||||
''^scripts/install-systemd-multi-user\.sh$''
|
||||
''^src/nix/get-env\.sh$''
|
||||
''^tests/functional/ca/build-dry\.sh$''
|
||||
''^tests/functional/ca/build-with-garbage-path\.sh$''
|
||||
''^tests/functional/ca/common\.sh$''
|
||||
''^tests/functional/ca/concurrent-builds\.sh$''
|
||||
''^tests/functional/ca/eval-store\.sh$''
|
||||
''^tests/functional/ca/gc\.sh$''
|
||||
''^tests/functional/ca/import-from-derivation\.sh$''
|
||||
''^tests/functional/ca/new-build-cmd\.sh$''
|
||||
''^tests/functional/ca/nix-shell\.sh$''
|
||||
''^tests/functional/ca/post-hook\.sh$''
|
||||
''^tests/functional/ca/recursive\.sh$''
|
||||
''^tests/functional/ca/repl\.sh$''
|
||||
''^tests/functional/ca/selfref-gc\.sh$''
|
||||
''^tests/functional/ca/why-depends\.sh$''
|
||||
''^tests/functional/characterisation-test-infra\.sh$''
|
||||
''^tests/functional/common/vars-and-functions\.sh$''
|
||||
''^tests/functional/completions\.sh$''
|
||||
''^tests/functional/compute-levels\.sh$''
|
||||
''^tests/functional/config\.sh$''
|
||||
''^tests/functional/db-migration\.sh$''
|
||||
''^tests/functional/debugger\.sh$''
|
||||
''^tests/functional/dependencies\.builder0\.sh$''
|
||||
''^tests/functional/dependencies\.sh$''
|
||||
''^tests/functional/dump-db\.sh$''
|
||||
''^tests/functional/dyn-drv/build-built-drv\.sh$''
|
||||
''^tests/functional/dyn-drv/common\.sh$''
|
||||
''^tests/functional/dyn-drv/dep-built-drv\.sh$''
|
||||
''^tests/functional/dyn-drv/eval-outputOf\.sh$''
|
||||
''^tests/functional/dyn-drv/old-daemon-error-hack\.sh$''
|
||||
''^tests/functional/dyn-drv/recursive-mod-json\.sh$''
|
||||
''^tests/functional/eval-store\.sh$''
|
||||
''^tests/functional/export-graph\.sh$''
|
||||
''^tests/functional/export\.sh$''
|
||||
''^tests/functional/extra-sandbox-profile\.sh$''
|
||||
''^tests/functional/fetchClosure\.sh$''
|
||||
''^tests/functional/fetchGit\.sh$''
|
||||
''^tests/functional/fetchGitRefs\.sh$''
|
||||
''^tests/functional/fetchGitSubmodules\.sh$''
|
||||
''^tests/functional/fetchGitVerification\.sh$''
|
||||
''^tests/functional/fetchMercurial\.sh$''
|
||||
''^tests/functional/fixed\.builder1\.sh$''
|
||||
''^tests/functional/fixed\.builder2\.sh$''
|
||||
''^tests/functional/fixed\.sh$''
|
||||
''^tests/functional/flakes/absolute-paths\.sh$''
|
||||
''^tests/functional/flakes/check\.sh$''
|
||||
''^tests/functional/flakes/config\.sh$''
|
||||
''^tests/functional/flakes/flakes\.sh$''
|
||||
''^tests/functional/flakes/follow-paths\.sh$''
|
||||
''^tests/functional/flakes/prefetch\.sh$''
|
||||
''^tests/functional/flakes/run\.sh$''
|
||||
''^tests/functional/flakes/show\.sh$''
|
||||
''^tests/functional/formatter\.sh$''
|
||||
''^tests/functional/formatter\.simple\.sh$''
|
||||
''^tests/functional/gc-auto\.sh$''
|
||||
''^tests/functional/gc-concurrent\.builder\.sh$''
|
||||
''^tests/functional/gc-concurrent\.sh$''
|
||||
''^tests/functional/gc-concurrent2\.builder\.sh$''
|
||||
''^tests/functional/gc-non-blocking\.sh$''
|
||||
''^tests/functional/hash-convert\.sh$''
|
||||
''^tests/functional/impure-derivations\.sh$''
|
||||
''^tests/functional/impure-eval\.sh$''
|
||||
''^tests/functional/install-darwin\.sh$''
|
||||
''^tests/functional/legacy-ssh-store\.sh$''
|
||||
''^tests/functional/linux-sandbox\.sh$''
|
||||
''^tests/functional/local-overlay-store/add-lower-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/add-lower\.sh$''
|
||||
''^tests/functional/local-overlay-store/bad-uris\.sh$''
|
||||
''^tests/functional/local-overlay-store/build-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/build\.sh$''
|
||||
''^tests/functional/local-overlay-store/check-post-init-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/check-post-init\.sh$''
|
||||
''^tests/functional/local-overlay-store/common\.sh$''
|
||||
''^tests/functional/local-overlay-store/delete-duplicate-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/delete-duplicate\.sh$''
|
||||
''^tests/functional/local-overlay-store/delete-refs-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/delete-refs\.sh$''
|
||||
''^tests/functional/local-overlay-store/gc-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/gc\.sh$''
|
||||
''^tests/functional/local-overlay-store/optimise-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/optimise\.sh$''
|
||||
''^tests/functional/local-overlay-store/redundant-add-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/redundant-add\.sh$''
|
||||
''^tests/functional/local-overlay-store/remount\.sh$''
|
||||
''^tests/functional/local-overlay-store/stale-file-handle-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/stale-file-handle\.sh$''
|
||||
''^tests/functional/local-overlay-store/verify-inner\.sh$''
|
||||
''^tests/functional/local-overlay-store/verify\.sh$''
|
||||
''^tests/functional/logging\.sh$''
|
||||
''^tests/functional/misc\.sh$''
|
||||
''^tests/functional/multiple-outputs\.sh$''
|
||||
''^tests/functional/nested-sandboxing\.sh$''
|
||||
''^tests/functional/nested-sandboxing/command\.sh$''
|
||||
''^tests/functional/nix-build\.sh$''
|
||||
''^tests/functional/nix-channel\.sh$''
|
||||
''^tests/functional/nix-collect-garbage-d\.sh$''
|
||||
''^tests/functional/nix-copy-ssh-common\.sh$''
|
||||
''^tests/functional/nix-copy-ssh-ng\.sh$''
|
||||
''^tests/functional/nix-copy-ssh\.sh$''
|
||||
''^tests/functional/nix-daemon-untrusting\.sh$''
|
||||
''^tests/functional/nix-profile\.sh$''
|
||||
''^tests/functional/nix-shell\.sh$''
|
||||
''^tests/functional/nix_path\.sh$''
|
||||
''^tests/functional/optimise-store\.sh$''
|
||||
''^tests/functional/output-normalization\.sh$''
|
||||
''^tests/functional/parallel\.builder\.sh$''
|
||||
''^tests/functional/parallel\.sh$''
|
||||
''^tests/functional/pass-as-file\.sh$''
|
||||
''^tests/functional/path-from-hash-part\.sh$''
|
||||
''^tests/functional/path-info\.sh$''
|
||||
''^tests/functional/placeholders\.sh$''
|
||||
''^tests/functional/post-hook\.sh$''
|
||||
''^tests/functional/pure-eval\.sh$''
|
||||
''^tests/functional/push-to-store-old\.sh$''
|
||||
''^tests/functional/push-to-store\.sh$''
|
||||
''^tests/functional/read-only-store\.sh$''
|
||||
''^tests/functional/readfile-context\.sh$''
|
||||
''^tests/functional/recursive\.sh$''
|
||||
''^tests/functional/referrers\.sh$''
|
||||
''^tests/functional/remote-store\.sh$''
|
||||
''^tests/functional/repair\.sh$''
|
||||
''^tests/functional/restricted\.sh$''
|
||||
''^tests/functional/search\.sh$''
|
||||
''^tests/functional/secure-drv-outputs\.sh$''
|
||||
''^tests/functional/selfref-gc\.sh$''
|
||||
''^tests/functional/shell\.shebang\.sh$''
|
||||
''^tests/functional/simple\.builder\.sh$''
|
||||
''^tests/functional/supplementary-groups\.sh$''
|
||||
''^tests/functional/toString-path\.sh$''
|
||||
''^tests/functional/user-envs-migration\.sh$''
|
||||
''^tests/functional/user-envs-test-case\.sh$''
|
||||
''^tests/functional/user-envs\.builder\.sh$''
|
||||
''^tests/functional/user-envs\.sh$''
|
||||
''^tests/functional/why-depends\.sh$''
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -142,6 +142,7 @@ release:
|
||||
$ git pull
|
||||
$ NEW_VERSION=2.13.0
|
||||
$ echo $NEW_VERSION > .version
|
||||
$ ... edit .mergify.yml to add the previous version ...
|
||||
$ git checkout -b bump-$NEW_VERSION
|
||||
$ git commit -a -m 'Bump version'
|
||||
$ git push --set-upstream origin bump-$NEW_VERSION
|
||||
|
||||
@@ -41,10 +41,8 @@ subproject('libexpr-c')
|
||||
subproject('libflake-c')
|
||||
subproject('libmain-c')
|
||||
|
||||
asan_enabled = 'address' in get_option('b_sanitize')
|
||||
|
||||
# Language Bindings
|
||||
if get_option('bindings') and not meson.is_cross_build() and not asan_enabled
|
||||
if get_option('bindings') and not meson.is_cross_build()
|
||||
subproject('perl')
|
||||
endif
|
||||
|
||||
@@ -60,4 +58,3 @@ if get_option('unit-tests')
|
||||
subproject('libflake-tests')
|
||||
endif
|
||||
subproject('nix-functional-tests')
|
||||
subproject('json-schema-checks')
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# shellcheck shell=bash
|
||||
function _complete_nix {
|
||||
local -a words
|
||||
local cword cur
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# shellcheck disable=all
|
||||
function _nix_complete
|
||||
# Get the current command up to a cursor.
|
||||
# - Behaves correctly even with pipes and nested in commands like env.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#compdef nix
|
||||
# shellcheck disable=all
|
||||
|
||||
function _nix() {
|
||||
local ifs_bk="$IFS"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
extern "C" [[gnu::retain, gnu::weak]] const char * __asan_default_options()
|
||||
{
|
||||
// We leak a bunch of memory knowingly on purpose. It's not worthwhile to
|
||||
// diagnose that memory being leaked for now.
|
||||
return "abort_on_error=1:print_summary=1:detect_leaks=0:detect_odr_violation=0";
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
# Clang gets grumpy about missing libasan symbols if -shared-libasan is not
|
||||
# passed when building shared libs, at least on Linux
|
||||
if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefined' in get_option(
|
||||
'b_sanitize',
|
||||
))
|
||||
add_project_link_arguments('-shared-libasan', language : 'cpp')
|
||||
endif
|
||||
|
||||
if 'address' in get_option('b_sanitize')
|
||||
deps_other += declare_dependency(sources : 'asan-options.cc')
|
||||
endif
|
||||
@@ -1,32 +0,0 @@
|
||||
can_wrap_assert_fail_test_code = '''
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
extern "C" void * __real___assert_fail(const char *, const char *, unsigned int, const char *);
|
||||
|
||||
extern "C" void *
|
||||
__wrap___assert_fail(const char *, const char *, unsigned int, const char *)
|
||||
{
|
||||
return __real___assert_fail(nullptr, nullptr, 0, nullptr);
|
||||
}
|
||||
'''
|
||||
|
||||
wrap_assert_fail_args = [ '-Wl,--wrap=__assert_fail' ]
|
||||
|
||||
can_wrap_assert_fail = cxx.links(
|
||||
can_wrap_assert_fail_test_code,
|
||||
args : wrap_assert_fail_args,
|
||||
name : 'linker can wrap __assert_fail',
|
||||
)
|
||||
|
||||
if can_wrap_assert_fail
|
||||
deps_other += declare_dependency(
|
||||
sources : 'wrap-assert-fail.cc',
|
||||
link_args : wrap_assert_fail_args,
|
||||
)
|
||||
endif
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "nix/util/error.hh"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cinttypes>
|
||||
#include <string_view>
|
||||
|
||||
extern "C" [[noreturn]] void __attribute__((weak))
|
||||
__wrap___assert_fail(const char * assertion, const char * file, unsigned int line, const char * function)
|
||||
{
|
||||
char buf[512];
|
||||
int n =
|
||||
snprintf(buf, sizeof(buf), "Assertion '%s' failed in %s at %s:%" PRIuLEAST32, assertion, function, file, line);
|
||||
if (n < 0)
|
||||
nix::panic("Assertion failed and could not format error message");
|
||||
nix::panic(std::string_view(buf, std::min(static_cast<int>(sizeof(buf)), n)));
|
||||
}
|
||||
@@ -5,15 +5,6 @@ if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
|
||||
deps_private += dependency('threads')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'cygwin'
|
||||
# -std=gnu on cygwin defines 'unix', which conflicts with the namespace
|
||||
add_project_arguments(
|
||||
'-D_POSIX_C_SOURCE=200809L',
|
||||
'-D_GNU_SOURCE',
|
||||
language : 'cpp',
|
||||
)
|
||||
endif
|
||||
|
||||
add_project_arguments(
|
||||
'-Wdeprecated-copy',
|
||||
'-Werror=suggest-override',
|
||||
@@ -42,8 +33,10 @@ if cxx.get_id() == 'clang'
|
||||
add_project_arguments('-fpch-instantiate-templates', language : 'cpp')
|
||||
endif
|
||||
|
||||
# Darwin ld doesn't like "X.Y.Zpre"
|
||||
nix_soversion = meson.project_version().split('pre')[0]
|
||||
|
||||
subdir('assert-fail')
|
||||
subdir('asan-options')
|
||||
# Clang gets grumpy about missing libasan symbols if -shared-libasan is not
|
||||
# passed when building shared libs, at least on Linux
|
||||
if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefined' in get_option(
|
||||
'b_sanitize',
|
||||
))
|
||||
add_project_link_arguments('-shared-libasan', language : 'cpp')
|
||||
endif
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
# This is needed for std::atomic on some platforms
|
||||
# We did not manage to test this reliably on all platforms, so we hardcode
|
||||
# it for now.
|
||||
if host_machine.cpu_family() in [ 'arm', 'ppc' ]
|
||||
if host_machine.cpu_family() == 'arm'
|
||||
deps_other += cxx.find_library('atomic')
|
||||
endif
|
||||
|
||||
@@ -164,24 +164,6 @@ let
|
||||
};
|
||||
|
||||
mesonLibraryLayer = finalAttrs: prevAttrs: {
|
||||
preConfigure =
|
||||
let
|
||||
interpositionFlags = [
|
||||
"-fno-semantic-interposition"
|
||||
"-Wl,-Bsymbolic-functions"
|
||||
];
|
||||
in
|
||||
# NOTE: By default GCC disables interprocedular optimizations (in particular inlining) for
|
||||
# position-independent code and thus shared libraries.
|
||||
# Since LD_PRELOAD tricks aren't worth losing out on optimizations, we disable it for good.
|
||||
# This is not the case for Clang, where inlining is done by default even without -fno-semantic-interposition.
|
||||
# https://reviews.llvm.org/D102453
|
||||
# https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup
|
||||
prevAttrs.preConfigure or ""
|
||||
+ lib.optionalString stdenv.cc.isGNU ''
|
||||
export CFLAGS="''${CFLAGS:-} ${toString interpositionFlags}"
|
||||
export CXXFLAGS="''${CXXFLAGS:-} ${toString interpositionFlags}"
|
||||
'';
|
||||
outputs = prevAttrs.outputs or [ "out" ] ++ [ "dev" ];
|
||||
};
|
||||
|
||||
@@ -204,25 +186,6 @@ let
|
||||
mesonFlags = [ (lib.mesonBool "b_asneeded" false) ] ++ prevAttrs.mesonFlags or [ ];
|
||||
};
|
||||
|
||||
enableSanitizersLayer =
|
||||
finalAttrs: prevAttrs:
|
||||
let
|
||||
sanitizers = lib.optional scope.withASan "address" ++ lib.optional scope.withUBSan "undefined";
|
||||
in
|
||||
{
|
||||
mesonFlags =
|
||||
(prevAttrs.mesonFlags or [ ])
|
||||
++ lib.optionals (lib.length sanitizers > 0) (
|
||||
[
|
||||
(lib.mesonOption "b_sanitize" (lib.concatStringsSep "," sanitizers))
|
||||
]
|
||||
++ (lib.optionals stdenv.cc.isClang [
|
||||
# https://www.github.com/mesonbuild/meson/issues/764
|
||||
(lib.mesonBool "b_lundef" false)
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
nixDefaultsLayer = finalAttrs: prevAttrs: {
|
||||
strictDeps = prevAttrs.strictDeps or true;
|
||||
enableParallelBuilding = true;
|
||||
@@ -265,16 +228,6 @@ in
|
||||
|
||||
inherit filesetToSource;
|
||||
|
||||
/**
|
||||
Whether meson components are built with [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html).
|
||||
*/
|
||||
withASan = false;
|
||||
|
||||
/**
|
||||
Whether meson components are built with [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
|
||||
*/
|
||||
withUBSan = false;
|
||||
|
||||
/**
|
||||
A user-provided extension function to apply to each component derivation.
|
||||
*/
|
||||
@@ -361,7 +314,6 @@ in
|
||||
setVersionLayer
|
||||
mesonLayer
|
||||
fixupStaticLayer
|
||||
enableSanitizersLayer
|
||||
scope.mesonComponentOverrides
|
||||
];
|
||||
mkMesonExecutable = mkPackageBuilder [
|
||||
@@ -372,7 +324,6 @@ in
|
||||
mesonLayer
|
||||
mesonBuildLayer
|
||||
fixupStaticLayer
|
||||
enableSanitizersLayer
|
||||
scope.mesonComponentOverrides
|
||||
];
|
||||
mkMesonLibrary = mkPackageBuilder [
|
||||
@@ -384,7 +335,6 @@ in
|
||||
mesonBuildLayer
|
||||
mesonLibraryLayer
|
||||
fixupStaticLayer
|
||||
enableSanitizersLayer
|
||||
scope.mesonComponentOverrides
|
||||
];
|
||||
|
||||
@@ -438,11 +388,6 @@ in
|
||||
*/
|
||||
nix-external-api-docs = callPackage ../src/external-api-docs/package.nix { version = fineVersion; };
|
||||
|
||||
/**
|
||||
JSON schema validation checks
|
||||
*/
|
||||
nix-json-schema-checks = callPackage ../src/json-schema-checks/package.nix { };
|
||||
|
||||
nix-perl-bindings = callPackage ../src/perl/package.nix { };
|
||||
|
||||
/**
|
||||
@@ -495,7 +440,7 @@ in
|
||||
|
||||
Example:
|
||||
```
|
||||
overrideScope (finalScope: prevScope: { aws-crt-cpp = null; })
|
||||
overrideScope (finalScope: prevScope: { aws-sdk-cpp = null; })
|
||||
```
|
||||
*/
|
||||
overrideScope = f: (scope.overrideScope f).nix-everything;
|
||||
|
||||
@@ -10,12 +10,46 @@
|
||||
stdenv,
|
||||
}:
|
||||
|
||||
let
|
||||
prevStdenv = stdenv;
|
||||
in
|
||||
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
|
||||
stdenv = if prevStdenv.isDarwin && prevStdenv.isx86_64 then darwinStdenv else prevStdenv;
|
||||
|
||||
# Fix the following error with the default x86_64-darwin SDK:
|
||||
#
|
||||
# error: aligned allocation function of type 'void *(std::size_t, std::align_val_t)' is only available on macOS 10.13 or newer
|
||||
#
|
||||
# Despite the use of the 10.13 deployment target here, the aligned
|
||||
# allocation function Clang uses with this setting actually works
|
||||
# all the way back to 10.6.
|
||||
# NOTE: this is not just a version constraint, but a request to make Darwin
|
||||
# provide this version level of support. Removing this minimum version
|
||||
# request will regress the above error.
|
||||
darwinStdenv = pkgs.overrideSDK prevStdenv { darwinMinVersion = "10.13"; };
|
||||
|
||||
in
|
||||
scope: {
|
||||
inherit stdenv;
|
||||
|
||||
aws-sdk-cpp =
|
||||
(pkgs.aws-sdk-cpp.override {
|
||||
apis = [
|
||||
"identity-management"
|
||||
"s3"
|
||||
"transfer"
|
||||
];
|
||||
customMemoryManagement = false;
|
||||
}).overrideAttrs
|
||||
{
|
||||
# only a stripped down version is built, which takes a lot less resources
|
||||
# to build, so we don't need a "big-parallel" machine.
|
||||
requiredSystemFeatures = [ ];
|
||||
};
|
||||
|
||||
boehmgc =
|
||||
(pkgs.boehmgc.override {
|
||||
enableLargeConfig = true;
|
||||
@@ -42,20 +76,15 @@ scope: {
|
||||
prevAttrs.postInstall;
|
||||
});
|
||||
|
||||
# TODO: Remove this when https://github.com/NixOS/nixpkgs/pull/442682 is included in a stable release
|
||||
toml11 =
|
||||
if lib.versionAtLeast pkgs.toml11.version "4.4.0" then
|
||||
pkgs.toml11
|
||||
else
|
||||
pkgs.toml11.overrideAttrs rec {
|
||||
version = "4.4.0";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "ToruNiina";
|
||||
repo = "toml11";
|
||||
tag = "v${version}";
|
||||
hash = "sha256-sgWKYxNT22nw376ttGsTdg0AMzOwp8QH3E8mx0BZJTQ=";
|
||||
};
|
||||
};
|
||||
toml11 = pkgs.toml11.overrideAttrs rec {
|
||||
version = "4.4.0";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "ToruNiina";
|
||||
repo = "toml11";
|
||||
tag = "v${version}";
|
||||
hash = "sha256-sgWKYxNT22nw376ttGsTdg0AMzOwp8QH3E8mx0BZJTQ=";
|
||||
};
|
||||
};
|
||||
|
||||
# TODO Hack until https://github.com/NixOS/nixpkgs/issues/45462 is fixed.
|
||||
boost =
|
||||
@@ -74,4 +103,38 @@ scope: {
|
||||
buildPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.buildPhase;
|
||||
installPhase = lib.replaceStrings [ "--without-python" ] [ "" ] old.installPhase;
|
||||
});
|
||||
|
||||
libgit2 =
|
||||
if lib.versionAtLeast pkgs.libgit2.version "1.9.0" then
|
||||
pkgs.libgit2
|
||||
else
|
||||
pkgs.libgit2.overrideAttrs (attrs: {
|
||||
# libgit2: Nixpkgs 24.11 has < 1.9.0, which needs our patches
|
||||
nativeBuildInputs =
|
||||
attrs.nativeBuildInputs or [ ]
|
||||
# gitMinimal does not build on Windows. See packbuilder patch.
|
||||
++ lib.optionals (!stdenv.hostPlatform.isWindows) [
|
||||
# Needed for `git apply`; see `prePatch`
|
||||
pkgs.buildPackages.gitMinimal
|
||||
];
|
||||
# Only `git apply` can handle git binary patches
|
||||
prePatch =
|
||||
attrs.prePatch or ""
|
||||
+ lib.optionalString (!stdenv.hostPlatform.isWindows) ''
|
||||
patch() {
|
||||
git apply
|
||||
}
|
||||
'';
|
||||
patches =
|
||||
attrs.patches or [ ]
|
||||
++ [
|
||||
./patches/libgit2-mempack-thin-packfile.patch
|
||||
]
|
||||
# gitMinimal does not build on Windows, but fortunately this patch only
|
||||
# impacts interruptibility
|
||||
++ lib.optionals (!stdenv.hostPlatform.isWindows) [
|
||||
# binary patch; see `prePatch`
|
||||
./patches/libgit2-packbuilder-callback-interruptible.patch
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,9 +70,6 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
|
||||
# We use this shell with the local checkout, not unpackPhase.
|
||||
src = null;
|
||||
# Workaround https://sourceware.org/pipermail/gdb-patches/2025-October/221398.html
|
||||
# Remove when gdb fix is rolled out everywhere.
|
||||
separateDebugInfo = false;
|
||||
|
||||
env = {
|
||||
# For `make format`, to work without installing pre-commit
|
||||
@@ -96,45 +93,37 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
|
||||
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
|
||||
|
||||
nativeBuildInputs =
|
||||
let
|
||||
inputs =
|
||||
attrs.nativeBuildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-store.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.nativeBuildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.nativeBuildInputs
|
||||
++ lib.optionals buildCanExecuteHost pkgs.nixComponents2.nix-manual.externalNativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-internal-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-external-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-functional-tests.externalNativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-json-schema-checks.externalNativeBuildInputs
|
||||
++ lib.optional (
|
||||
!buildCanExecuteHost
|
||||
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
|
||||
&& !(stdenv.hostPlatform.isWindows && stdenv.buildPlatform.isDarwin)
|
||||
&& stdenv.hostPlatform.emulatorAvailable pkgs.buildPackages
|
||||
&& lib.meta.availableOn stdenv.buildPlatform (stdenv.hostPlatform.emulator pkgs.buildPackages)
|
||||
) pkgs.buildPackages.mesonEmulatorHook
|
||||
++ [
|
||||
pkgs.buildPackages.cmake
|
||||
pkgs.buildPackages.gnused
|
||||
pkgs.buildPackages.changelog-d
|
||||
modular.pre-commit.settings.package
|
||||
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
|
||||
pkgs.buildPackages.nixfmt-rfc-style
|
||||
pkgs.buildPackages.shellcheck
|
||||
pkgs.buildPackages.include-what-you-use
|
||||
pkgs.buildPackages.gdb
|
||||
]
|
||||
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
|
||||
lib.hiPrio pkgs.buildPackages.clang-tools
|
||||
)
|
||||
++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped;
|
||||
in
|
||||
# FIXME: separateDebugInfo = false doesn't actually prevent -Wa,--compress-debug-sections
|
||||
# from making its way into NIX_CFLAGS_COMPILE.
|
||||
lib.filter (p: !lib.hasInfix "separate-debug-info" p) inputs;
|
||||
attrs.nativeBuildInputs or [ ]
|
||||
++ pkgs.nixComponents2.nix-util.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-store.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-fetchers.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-expr.nativeBuildInputs
|
||||
++ lib.optionals havePerl pkgs.nixComponents2.nix-perl-bindings.nativeBuildInputs
|
||||
++ lib.optionals buildCanExecuteHost pkgs.nixComponents2.nix-manual.externalNativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-internal-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-external-api-docs.nativeBuildInputs
|
||||
++ pkgs.nixComponents2.nix-functional-tests.externalNativeBuildInputs
|
||||
++ lib.optional (
|
||||
!buildCanExecuteHost
|
||||
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
|
||||
&& !(stdenv.hostPlatform.isWindows && stdenv.buildPlatform.isDarwin)
|
||||
&& stdenv.hostPlatform.emulatorAvailable pkgs.buildPackages
|
||||
&& lib.meta.availableOn stdenv.buildPlatform (stdenv.hostPlatform.emulator pkgs.buildPackages)
|
||||
) pkgs.buildPackages.mesonEmulatorHook
|
||||
++ [
|
||||
pkgs.buildPackages.cmake
|
||||
pkgs.buildPackages.gnused
|
||||
pkgs.buildPackages.shellcheck
|
||||
pkgs.buildPackages.changelog-d
|
||||
modular.pre-commit.settings.package
|
||||
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
|
||||
pkgs.buildPackages.nixfmt-rfc-style
|
||||
pkgs.buildPackages.gdb
|
||||
]
|
||||
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
|
||||
lib.hiPrio pkgs.buildPackages.clang-tools
|
||||
)
|
||||
++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped;
|
||||
|
||||
buildInputs = [
|
||||
pkgs.gbenchmark
|
||||
|
||||
@@ -62,7 +62,6 @@ let
|
||||
"nix-cmd"
|
||||
"nix-cli"
|
||||
"nix-functional-tests"
|
||||
"nix-json-schema-checks"
|
||||
]
|
||||
++ lib.optionals enableBindings [
|
||||
"nix-perl-bindings"
|
||||
@@ -74,7 +73,7 @@ let
|
||||
]
|
||||
);
|
||||
in
|
||||
rec {
|
||||
{
|
||||
/**
|
||||
An internal check to make sure our package listing is complete.
|
||||
*/
|
||||
@@ -146,25 +145,13 @@ rec {
|
||||
)
|
||||
);
|
||||
|
||||
# Builds with sanitizers already have GC disabled, so this buildNoGc can just
|
||||
# point to buildWithSanitizers in order to reduce the load on hydra.
|
||||
buildNoGc = buildWithSanitizers;
|
||||
|
||||
buildWithSanitizers =
|
||||
buildNoGc =
|
||||
let
|
||||
components = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgsFor.${system}.native;
|
||||
in
|
||||
pkgs.nixComponents2.overrideScope (
|
||||
nixpkgsFor.${system}.native.nixComponents2.overrideScope (
|
||||
self: super: {
|
||||
# Boost coroutines fail with ASAN on darwin.
|
||||
withASan = !pkgs.stdenv.buildPlatform.isDarwin;
|
||||
withUBSan = true;
|
||||
nix-expr = super.nix-expr.override { enableGC = false; };
|
||||
# Unclear how to make Perl bindings work with a dynamically linked ASAN.
|
||||
nix-perl-bindings = null;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
282
packaging/patches/libgit2-mempack-thin-packfile.patch
Normal file
282
packaging/patches/libgit2-mempack-thin-packfile.patch
Normal file
@@ -0,0 +1,282 @@
|
||||
commit 9bacade4a3ef4b6b26e2c02f549eef0e9eb9eaa2
|
||||
Author: Robert Hensing <robert@roberthensing.nl>
|
||||
Date: Sun Aug 18 20:20:36 2024 +0200
|
||||
|
||||
Add unoptimized git_mempack_write_thin_pack
|
||||
|
||||
diff --git a/include/git2/sys/mempack.h b/include/git2/sys/mempack.h
|
||||
index 17da590a3..3688bdd50 100644
|
||||
--- a/include/git2/sys/mempack.h
|
||||
+++ b/include/git2/sys/mempack.h
|
||||
@@ -44,6 +44,29 @@ GIT_BEGIN_DECL
|
||||
*/
|
||||
GIT_EXTERN(int) git_mempack_new(git_odb_backend **out);
|
||||
|
||||
+/**
|
||||
+ * Write a thin packfile with the objects in the memory store.
|
||||
+ *
|
||||
+ * A thin packfile is a packfile that does not contain its transitive closure of
|
||||
+ * references. This is useful for efficiently distributing additions to a
|
||||
+ * repository over the network, but also finds use in the efficient bulk
|
||||
+ * addition of objects to a repository, locally.
|
||||
+ *
|
||||
+ * This operation performs the (shallow) insert operations into the
|
||||
+ * `git_packbuilder`, but does not write the packfile to disk;
|
||||
+ * see `git_packbuilder_write_buf`.
|
||||
+ *
|
||||
+ * It also does not reset the memory store; see `git_mempack_reset`.
|
||||
+ *
|
||||
+ * @note This function may or may not write trees and blobs that are not
|
||||
+ * referenced by commits. Currently everything is written, but this
|
||||
+ * behavior may change in the future as the packer is optimized.
|
||||
+ *
|
||||
+ * @param backend The mempack backend
|
||||
+ * @param pb The packbuilder to use to write the packfile
|
||||
+ */
|
||||
+GIT_EXTERN(int) git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb);
|
||||
+
|
||||
/**
|
||||
* Dump all the queued in-memory writes to a packfile.
|
||||
*
|
||||
diff --git a/src/libgit2/odb_mempack.c b/src/libgit2/odb_mempack.c
|
||||
index 6f27f45f8..0b61e2b66 100644
|
||||
--- a/src/libgit2/odb_mempack.c
|
||||
+++ b/src/libgit2/odb_mempack.c
|
||||
@@ -132,6 +132,35 @@ cleanup:
|
||||
return err;
|
||||
}
|
||||
|
||||
+int git_mempack_write_thin_pack(git_odb_backend *backend, git_packbuilder *pb)
|
||||
+{
|
||||
+ struct memory_packer_db *db = (struct memory_packer_db *)backend;
|
||||
+ const git_oid *oid;
|
||||
+ size_t iter = 0;
|
||||
+ int err = -1;
|
||||
+
|
||||
+ /* TODO: Implement the recency heuristics.
|
||||
+ For this it probably makes sense to only write what's referenced
|
||||
+ through commits, an option I've carved out for you in the docs.
|
||||
+ wrt heuristics: ask your favorite LLM to translate https://git-scm.com/docs/pack-heuristics/en
|
||||
+ to actual normal reference documentation. */
|
||||
+ while (true) {
|
||||
+ err = git_oidmap_iterate(NULL, db->objects, &iter, &oid);
|
||||
+ if (err == GIT_ITEROVER) {
|
||||
+ err = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (err != 0)
|
||||
+ return err;
|
||||
+
|
||||
+ err = git_packbuilder_insert(pb, oid, NULL);
|
||||
+ if (err != 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int git_mempack_dump(
|
||||
git_buf *pack,
|
||||
git_repository *repo,
|
||||
diff --git a/tests/libgit2/mempack/thinpack.c b/tests/libgit2/mempack/thinpack.c
|
||||
new file mode 100644
|
||||
index 000000000..604a4dda2
|
||||
--- /dev/null
|
||||
+++ b/tests/libgit2/mempack/thinpack.c
|
||||
@@ -0,0 +1,196 @@
|
||||
+#include "clar_libgit2.h"
|
||||
+#include "git2/indexer.h"
|
||||
+#include "git2/odb_backend.h"
|
||||
+#include "git2/tree.h"
|
||||
+#include "git2/types.h"
|
||||
+#include "git2/sys/mempack.h"
|
||||
+#include "git2/sys/odb_backend.h"
|
||||
+#include "util.h"
|
||||
+
|
||||
+static git_repository *_repo;
|
||||
+static git_odb_backend * _mempack_backend;
|
||||
+
|
||||
+void test_mempack_thinpack__initialize(void)
|
||||
+{
|
||||
+ git_odb *odb;
|
||||
+
|
||||
+ _repo = cl_git_sandbox_init_new("mempack_thinpack_repo");
|
||||
+
|
||||
+ cl_git_pass(git_mempack_new(&_mempack_backend));
|
||||
+ cl_git_pass(git_repository_odb(&odb, _repo));
|
||||
+ cl_git_pass(git_odb_add_backend(odb, _mempack_backend, 999));
|
||||
+ git_odb_free(odb);
|
||||
+}
|
||||
+
|
||||
+void _mempack_thinpack__cleanup(void)
|
||||
+{
|
||||
+ cl_git_sandbox_cleanup();
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ Generating a packfile for an unchanged repo works and produces an empty packfile.
|
||||
+ Even if we allow this scenario to be detected, it shouldn't misbehave if the
|
||||
+ application is unaware of it.
|
||||
+*/
|
||||
+void test_mempack_thinpack__empty(void)
|
||||
+{
|
||||
+ git_packbuilder *pb;
|
||||
+ int version;
|
||||
+ int n;
|
||||
+ git_buf buf = GIT_BUF_INIT;
|
||||
+
|
||||
+ git_packbuilder_new(&pb, _repo);
|
||||
+
|
||||
+ cl_git_pass(git_mempack_write_thin_pack(_mempack_backend, pb));
|
||||
+ cl_git_pass(git_packbuilder_write_buf(&buf, pb));
|
||||
+ cl_assert_in_range(12, buf.size, 1024 /* empty packfile is >0 bytes, but certainly not that big */);
|
||||
+ cl_assert(buf.ptr[0] == 'P');
|
||||
+ cl_assert(buf.ptr[1] == 'A');
|
||||
+ cl_assert(buf.ptr[2] == 'C');
|
||||
+ cl_assert(buf.ptr[3] == 'K');
|
||||
+ version = (buf.ptr[4] << 24) | (buf.ptr[5] << 16) | (buf.ptr[6] << 8) | buf.ptr[7];
|
||||
+ /* Subject to change. https://git-scm.com/docs/pack-format: Git currently accepts version number 2 or 3 but generates version 2 only.*/
|
||||
+ cl_assert_equal_i(2, version);
|
||||
+ n = (buf.ptr[8] << 24) | (buf.ptr[9] << 16) | (buf.ptr[10] << 8) | buf.ptr[11];
|
||||
+ cl_assert_equal_i(0, n);
|
||||
+ git_buf_dispose(&buf);
|
||||
+
|
||||
+ git_packbuilder_free(pb);
|
||||
+}
|
||||
+
|
||||
+#define LIT_LEN(x) x, sizeof(x) - 1
|
||||
+
|
||||
+/*
|
||||
+ Check that git_mempack_write_thin_pack produces a thin packfile.
|
||||
+*/
|
||||
+void test_mempack_thinpack__thin(void)
|
||||
+{
|
||||
+ /* Outline:
|
||||
+ - Create tree 1
|
||||
+ - Flush to packfile A
|
||||
+ - Create tree 2
|
||||
+ - Flush to packfile B
|
||||
+
|
||||
+ Tree 2 has a new blob and a reference to a blob from tree 1.
|
||||
+
|
||||
+ Expectation:
|
||||
+ - Packfile B is thin and does not contain the objects from packfile A
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+ git_oid oid_blob_1;
|
||||
+ git_oid oid_blob_2;
|
||||
+ git_oid oid_blob_3;
|
||||
+ git_oid oid_tree_1;
|
||||
+ git_oid oid_tree_2;
|
||||
+ git_treebuilder *tb;
|
||||
+
|
||||
+ git_packbuilder *pb;
|
||||
+ git_buf buf = GIT_BUF_INIT;
|
||||
+ git_indexer *indexer;
|
||||
+ git_indexer_progress stats;
|
||||
+ char pack_dir_path[1024];
|
||||
+
|
||||
+ char sbuf[1024];
|
||||
+ const char * repo_path;
|
||||
+ const char * pack_name_1;
|
||||
+ const char * pack_name_2;
|
||||
+ git_str pack_path_1 = GIT_STR_INIT;
|
||||
+ git_str pack_path_2 = GIT_STR_INIT;
|
||||
+ git_odb_backend * pack_odb_backend_1;
|
||||
+ git_odb_backend * pack_odb_backend_2;
|
||||
+
|
||||
+
|
||||
+ cl_assert_in_range(0, snprintf(pack_dir_path, sizeof(pack_dir_path), "%s/objects/pack", git_repository_path(_repo)), sizeof(pack_dir_path));
|
||||
+
|
||||
+ /* Create tree 1 */
|
||||
+
|
||||
+ cl_git_pass(git_blob_create_from_buffer(&oid_blob_1, _repo, LIT_LEN("thinpack blob 1")));
|
||||
+ cl_git_pass(git_blob_create_from_buffer(&oid_blob_2, _repo, LIT_LEN("thinpack blob 2")));
|
||||
+
|
||||
+
|
||||
+ cl_git_pass(git_treebuilder_new(&tb, _repo, NULL));
|
||||
+ cl_git_pass(git_treebuilder_insert(NULL, tb, "blob1", &oid_blob_1, GIT_FILEMODE_BLOB));
|
||||
+ cl_git_pass(git_treebuilder_insert(NULL, tb, "blob2", &oid_blob_2, GIT_FILEMODE_BLOB));
|
||||
+ cl_git_pass(git_treebuilder_write(&oid_tree_1, tb));
|
||||
+
|
||||
+ /* Flush */
|
||||
+
|
||||
+ cl_git_pass(git_packbuilder_new(&pb, _repo));
|
||||
+ cl_git_pass(git_mempack_write_thin_pack(_mempack_backend, pb));
|
||||
+ cl_git_pass(git_packbuilder_write_buf(&buf, pb));
|
||||
+ cl_git_pass(git_indexer_new(&indexer, pack_dir_path, 0, NULL, NULL));
|
||||
+ cl_git_pass(git_indexer_append(indexer, buf.ptr, buf.size, &stats));
|
||||
+ cl_git_pass(git_indexer_commit(indexer, &stats));
|
||||
+ pack_name_1 = strdup(git_indexer_name(indexer));
|
||||
+ cl_assert(pack_name_1);
|
||||
+ git_buf_dispose(&buf);
|
||||
+ git_mempack_reset(_mempack_backend);
|
||||
+ git_indexer_free(indexer);
|
||||
+ git_packbuilder_free(pb);
|
||||
+
|
||||
+ /* Create tree 2 */
|
||||
+
|
||||
+ cl_git_pass(git_treebuilder_clear(tb));
|
||||
+ /* blob 1 won't be used, but we add it anyway to test that just "declaring" an object doesn't
|
||||
+ necessarily cause its inclusion in the next thin packfile. It must only be included if new. */
|
||||
+ cl_git_pass(git_blob_create_from_buffer(&oid_blob_1, _repo, LIT_LEN("thinpack blob 1")));
|
||||
+ cl_git_pass(git_blob_create_from_buffer(&oid_blob_3, _repo, LIT_LEN("thinpack blob 3")));
|
||||
+ cl_git_pass(git_treebuilder_insert(NULL, tb, "blob1", &oid_blob_1, GIT_FILEMODE_BLOB));
|
||||
+ cl_git_pass(git_treebuilder_insert(NULL, tb, "blob3", &oid_blob_3, GIT_FILEMODE_BLOB));
|
||||
+ cl_git_pass(git_treebuilder_write(&oid_tree_2, tb));
|
||||
+
|
||||
+ /* Flush */
|
||||
+
|
||||
+ cl_git_pass(git_packbuilder_new(&pb, _repo));
|
||||
+ cl_git_pass(git_mempack_write_thin_pack(_mempack_backend, pb));
|
||||
+ cl_git_pass(git_packbuilder_write_buf(&buf, pb));
|
||||
+ cl_git_pass(git_indexer_new(&indexer, pack_dir_path, 0, NULL, NULL));
|
||||
+ cl_git_pass(git_indexer_append(indexer, buf.ptr, buf.size, &stats));
|
||||
+ cl_git_pass(git_indexer_commit(indexer, &stats));
|
||||
+ pack_name_2 = strdup(git_indexer_name(indexer));
|
||||
+ cl_assert(pack_name_2);
|
||||
+ git_buf_dispose(&buf);
|
||||
+ git_mempack_reset(_mempack_backend);
|
||||
+ git_indexer_free(indexer);
|
||||
+ git_packbuilder_free(pb);
|
||||
+ git_treebuilder_free(tb);
|
||||
+
|
||||
+ /* Assertions */
|
||||
+
|
||||
+ assert(pack_name_1);
|
||||
+ assert(pack_name_2);
|
||||
+
|
||||
+ repo_path = git_repository_path(_repo);
|
||||
+
|
||||
+ snprintf(sbuf, sizeof(sbuf), "objects/pack/pack-%s.pack", pack_name_1);
|
||||
+ git_str_joinpath(&pack_path_1, repo_path, sbuf);
|
||||
+ snprintf(sbuf, sizeof(sbuf), "objects/pack/pack-%s.pack", pack_name_2);
|
||||
+ git_str_joinpath(&pack_path_2, repo_path, sbuf);
|
||||
+
|
||||
+ /* If they're the same, something definitely went wrong. */
|
||||
+ cl_assert(strcmp(pack_name_1, pack_name_2) != 0);
|
||||
+
|
||||
+ cl_git_pass(git_odb_backend_one_pack(&pack_odb_backend_1, pack_path_1.ptr));
|
||||
+ cl_assert(pack_odb_backend_1->exists(pack_odb_backend_1, &oid_blob_1));
|
||||
+ cl_assert(pack_odb_backend_1->exists(pack_odb_backend_1, &oid_blob_2));
|
||||
+ cl_assert(!pack_odb_backend_1->exists(pack_odb_backend_1, &oid_blob_3));
|
||||
+ cl_assert(pack_odb_backend_1->exists(pack_odb_backend_1, &oid_tree_1));
|
||||
+ cl_assert(!pack_odb_backend_1->exists(pack_odb_backend_1, &oid_tree_2));
|
||||
+
|
||||
+ cl_git_pass(git_odb_backend_one_pack(&pack_odb_backend_2, pack_path_2.ptr));
|
||||
+ /* blob 1 is already in the packfile 1, so packfile 2 must not include it, in order to be _thin_. */
|
||||
+ cl_assert(!pack_odb_backend_2->exists(pack_odb_backend_2, &oid_blob_1));
|
||||
+ cl_assert(!pack_odb_backend_2->exists(pack_odb_backend_2, &oid_blob_2));
|
||||
+ cl_assert(pack_odb_backend_2->exists(pack_odb_backend_2, &oid_blob_3));
|
||||
+ cl_assert(!pack_odb_backend_2->exists(pack_odb_backend_2, &oid_tree_1));
|
||||
+ cl_assert(pack_odb_backend_2->exists(pack_odb_backend_2, &oid_tree_2));
|
||||
+
|
||||
+ pack_odb_backend_1->free(pack_odb_backend_1);
|
||||
+ pack_odb_backend_2->free(pack_odb_backend_2);
|
||||
+ free((void *)pack_name_1);
|
||||
+ free((void *)pack_name_2);
|
||||
+ git_str_dispose(&pack_path_1);
|
||||
+ git_str_dispose(&pack_path_2);
|
||||
+
|
||||
+}
|
||||
@@ -0,0 +1,930 @@
|
||||
commit e9823c5da4fa977c46bcb97167fbdd0d70adb5ff
|
||||
Author: Robert Hensing <robert@roberthensing.nl>
|
||||
Date: Mon Aug 26 20:07:04 2024 +0200
|
||||
|
||||
Make packbuilder interruptible using progress callback
|
||||
|
||||
Forward errors from packbuilder->progress_cb
|
||||
|
||||
This allows the callback to terminate long-running operations when
|
||||
the application is interrupted.
|
||||
|
||||
diff --git a/include/git2/pack.h b/include/git2/pack.h
|
||||
index 0f6bd2ab9..bee72a6c0 100644
|
||||
--- a/include/git2/pack.h
|
||||
+++ b/include/git2/pack.h
|
||||
@@ -247,6 +247,9 @@ typedef int GIT_CALLBACK(git_packbuilder_progress)(
|
||||
* @param progress_cb Function to call with progress information during
|
||||
* pack building. Be aware that this is called inline with pack building
|
||||
* operations, so performance may be affected.
|
||||
+ * When progress_cb returns an error, the pack building process will be
|
||||
+ * aborted and the error will be returned from the invoked function.
|
||||
+ * `pb` must then be freed.
|
||||
* @param progress_cb_payload Payload for progress callback.
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c
|
||||
index b2d80cba9..7c331c2d5 100644
|
||||
--- a/src/libgit2/pack-objects.c
|
||||
+++ b/src/libgit2/pack-objects.c
|
||||
@@ -932,6 +932,9 @@ static int report_delta_progress(
|
||||
{
|
||||
int ret;
|
||||
|
||||
+ if (pb->failure)
|
||||
+ return pb->failure;
|
||||
+
|
||||
if (pb->progress_cb) {
|
||||
uint64_t current_time = git_time_monotonic();
|
||||
uint64_t elapsed = current_time - pb->last_progress_report_time;
|
||||
@@ -943,8 +946,10 @@ static int report_delta_progress(
|
||||
GIT_PACKBUILDER_DELTAFICATION,
|
||||
count, pb->nr_objects, pb->progress_cb_payload);
|
||||
|
||||
- if (ret)
|
||||
+ if (ret) {
|
||||
+ pb->failure = ret;
|
||||
return git_error_set_after_callback(ret);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,7 +981,10 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
}
|
||||
|
||||
pb->nr_deltified += 1;
|
||||
- report_delta_progress(pb, pb->nr_deltified, false);
|
||||
+ if ((error = report_delta_progress(pb, pb->nr_deltified, false)) < 0) {
|
||||
+ GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
|
||||
+ goto on_error;
|
||||
+ }
|
||||
|
||||
po = *list++;
|
||||
(*list_size)--;
|
||||
@@ -1124,6 +1132,10 @@ struct thread_params {
|
||||
size_t depth;
|
||||
size_t working;
|
||||
size_t data_ready;
|
||||
+
|
||||
+ /* A pb->progress_cb can stop the packing process by returning an error.
|
||||
+ When that happens, all threads observe the error and stop voluntarily. */
|
||||
+ bool stopped;
|
||||
};
|
||||
|
||||
static void *threaded_find_deltas(void *arg)
|
||||
@@ -1133,7 +1145,12 @@ static void *threaded_find_deltas(void *arg)
|
||||
while (me->remaining) {
|
||||
if (find_deltas(me->pb, me->list, &me->remaining,
|
||||
me->window, me->depth) < 0) {
|
||||
- ; /* TODO */
|
||||
+ me->stopped = true;
|
||||
+ GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL);
|
||||
+ me->working = false;
|
||||
+ git_cond_signal(&me->pb->progress_cond);
|
||||
+ GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_unlock(me->pb) == 0, NULL);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
GIT_ASSERT_WITH_RETVAL(git_packbuilder__progress_lock(me->pb) == 0, NULL);
|
||||
@@ -1175,8 +1192,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
pb->nr_threads = git__online_cpus();
|
||||
|
||||
if (pb->nr_threads <= 1) {
|
||||
- find_deltas(pb, list, &list_size, window, depth);
|
||||
- return 0;
|
||||
+ return find_deltas(pb, list, &list_size, window, depth);
|
||||
}
|
||||
|
||||
p = git__mallocarray(pb->nr_threads, sizeof(*p));
|
||||
@@ -1195,6 +1211,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
p[i].depth = depth;
|
||||
p[i].working = 1;
|
||||
p[i].data_ready = 0;
|
||||
+ p[i].stopped = 0;
|
||||
|
||||
/* try to split chunks on "path" boundaries */
|
||||
while (sub_size && sub_size < list_size &&
|
||||
@@ -1262,7 +1279,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
(!victim || victim->remaining < p[i].remaining))
|
||||
victim = &p[i];
|
||||
|
||||
- if (victim) {
|
||||
+ if (victim && !target->stopped) {
|
||||
sub_size = victim->remaining / 2;
|
||||
list = victim->list + victim->list_size - sub_size;
|
||||
while (sub_size && list[0]->hash &&
|
||||
@@ -1286,7 +1303,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
}
|
||||
target->list_size = sub_size;
|
||||
target->remaining = sub_size;
|
||||
- target->working = 1;
|
||||
+ target->working = 1; /* even when target->stopped, so that we don't process this thread again */
|
||||
GIT_ASSERT(git_packbuilder__progress_unlock(pb) == 0);
|
||||
|
||||
if (git_mutex_lock(&target->mutex)) {
|
||||
@@ -1299,7 +1316,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
git_cond_signal(&target->cond);
|
||||
git_mutex_unlock(&target->mutex);
|
||||
|
||||
- if (!sub_size) {
|
||||
+ if (target->stopped || !sub_size) {
|
||||
git_thread_join(&target->thread, NULL);
|
||||
git_cond_free(&target->cond);
|
||||
git_mutex_free(&target->mutex);
|
||||
@@ -1308,7 +1325,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
|
||||
}
|
||||
|
||||
git__free(p);
|
||||
- return 0;
|
||||
+ return pb->failure;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -1319,6 +1336,7 @@ int git_packbuilder__prepare(git_packbuilder *pb)
|
||||
{
|
||||
git_pobject **delta_list;
|
||||
size_t i, n = 0;
|
||||
+ int error;
|
||||
|
||||
if (pb->nr_objects == 0 || pb->done)
|
||||
return 0; /* nothing to do */
|
||||
@@ -1327,8 +1345,10 @@ int git_packbuilder__prepare(git_packbuilder *pb)
|
||||
* Although we do not report progress during deltafication, we
|
||||
* at least report that we are in the deltafication stage
|
||||
*/
|
||||
- if (pb->progress_cb)
|
||||
- pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload);
|
||||
+ if (pb->progress_cb) {
|
||||
+ if ((error = pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload)) < 0)
|
||||
+ return git_error_set_after_callback(error);
|
||||
+ }
|
||||
|
||||
delta_list = git__mallocarray(pb->nr_objects, sizeof(*delta_list));
|
||||
GIT_ERROR_CHECK_ALLOC(delta_list);
|
||||
@@ -1345,31 +1365,33 @@ int git_packbuilder__prepare(git_packbuilder *pb)
|
||||
|
||||
if (n > 1) {
|
||||
git__tsort((void **)delta_list, n, type_size_sort);
|
||||
- if (ll_find_deltas(pb, delta_list, n,
|
||||
+ if ((error = ll_find_deltas(pb, delta_list, n,
|
||||
GIT_PACK_WINDOW + 1,
|
||||
- GIT_PACK_DEPTH) < 0) {
|
||||
+ GIT_PACK_DEPTH)) < 0) {
|
||||
git__free(delta_list);
|
||||
- return -1;
|
||||
+ return error;
|
||||
}
|
||||
}
|
||||
|
||||
- report_delta_progress(pb, pb->nr_objects, true);
|
||||
+ error = report_delta_progress(pb, pb->nr_objects, true);
|
||||
|
||||
pb->done = true;
|
||||
git__free(delta_list);
|
||||
- return 0;
|
||||
+ return error;
|
||||
}
|
||||
|
||||
-#define PREPARE_PACK if (git_packbuilder__prepare(pb) < 0) { return -1; }
|
||||
+#define PREPARE_PACK error = git_packbuilder__prepare(pb); if (error < 0) { return error; }
|
||||
|
||||
int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t size, void *payload), void *payload)
|
||||
{
|
||||
+ int error;
|
||||
PREPARE_PACK;
|
||||
return write_pack(pb, cb, payload);
|
||||
}
|
||||
|
||||
int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb)
|
||||
{
|
||||
+ int error;
|
||||
PREPARE_PACK;
|
||||
|
||||
return write_pack(pb, &write_pack_buf, buf);
|
||||
diff --git a/src/libgit2/pack-objects.h b/src/libgit2/pack-objects.h
|
||||
index bbc8b9430..380a28ebe 100644
|
||||
--- a/src/libgit2/pack-objects.h
|
||||
+++ b/src/libgit2/pack-objects.h
|
||||
@@ -100,6 +100,10 @@ struct git_packbuilder {
|
||||
uint64_t last_progress_report_time;
|
||||
|
||||
bool done;
|
||||
+
|
||||
+ /* A non-zero error code in failure causes all threads to shut themselves
|
||||
+ down. Some functions will return this error code. */
|
||||
+ volatile int failure;
|
||||
};
|
||||
|
||||
int git_packbuilder__write_buf(git_str *buf, git_packbuilder *pb);
|
||||
diff --git a/tests/libgit2/pack/cancel.c b/tests/libgit2/pack/cancel.c
|
||||
new file mode 100644
|
||||
index 000000000..a0aa9716a
|
||||
--- /dev/null
|
||||
+++ b/tests/libgit2/pack/cancel.c
|
||||
@@ -0,0 +1,240 @@
|
||||
+#include "clar_libgit2.h"
|
||||
+#include "futils.h"
|
||||
+#include "pack.h"
|
||||
+#include "hash.h"
|
||||
+#include "iterator.h"
|
||||
+#include "vector.h"
|
||||
+#include "posix.h"
|
||||
+#include "hash.h"
|
||||
+#include "pack-objects.h"
|
||||
+
|
||||
+static git_repository *_repo;
|
||||
+static git_revwalk *_revwalker;
|
||||
+static git_packbuilder *_packbuilder;
|
||||
+static git_indexer *_indexer;
|
||||
+static git_vector _commits;
|
||||
+static int _commits_is_initialized;
|
||||
+static git_indexer_progress _stats;
|
||||
+
|
||||
+extern bool git_disable_pack_keep_file_checks;
|
||||
+
|
||||
+static void pack_packbuilder_init(const char *sandbox) {
|
||||
+ _repo = cl_git_sandbox_init(sandbox);
|
||||
+ /* cl_git_pass(p_chdir(sandbox)); */
|
||||
+ cl_git_pass(git_revwalk_new(&_revwalker, _repo));
|
||||
+ cl_git_pass(git_packbuilder_new(&_packbuilder, _repo));
|
||||
+ cl_git_pass(git_vector_init(&_commits, 0, NULL));
|
||||
+ _commits_is_initialized = 1;
|
||||
+ memset(&_stats, 0, sizeof(_stats));
|
||||
+ p_fsync__cnt = 0;
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__initialize(void)
|
||||
+{
|
||||
+ pack_packbuilder_init("small.git");
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cleanup(void)
|
||||
+{
|
||||
+ git_oid *o;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
|
||||
+ cl_git_pass(git_libgit2_opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, false));
|
||||
+
|
||||
+ if (_commits_is_initialized) {
|
||||
+ _commits_is_initialized = 0;
|
||||
+ git_vector_foreach(&_commits, i, o) {
|
||||
+ git__free(o);
|
||||
+ }
|
||||
+ git_vector_free(&_commits);
|
||||
+ }
|
||||
+
|
||||
+ git_packbuilder_free(_packbuilder);
|
||||
+ _packbuilder = NULL;
|
||||
+
|
||||
+ git_revwalk_free(_revwalker);
|
||||
+ _revwalker = NULL;
|
||||
+
|
||||
+ git_indexer_free(_indexer);
|
||||
+ _indexer = NULL;
|
||||
+
|
||||
+ /* cl_git_pass(p_chdir("..")); */
|
||||
+ cl_git_sandbox_cleanup();
|
||||
+ _repo = NULL;
|
||||
+}
|
||||
+
|
||||
+static int seed_packbuilder(void)
|
||||
+{
|
||||
+ int error;
|
||||
+ git_oid oid, *o;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ git_revwalk_sorting(_revwalker, GIT_SORT_TIME);
|
||||
+ cl_git_pass(git_revwalk_push_ref(_revwalker, "HEAD"));
|
||||
+
|
||||
+ while (git_revwalk_next(&oid, _revwalker) == 0) {
|
||||
+ o = git__malloc(sizeof(git_oid));
|
||||
+ cl_assert(o != NULL);
|
||||
+ git_oid_cpy(o, &oid);
|
||||
+ cl_git_pass(git_vector_insert(&_commits, o));
|
||||
+ }
|
||||
+
|
||||
+ git_vector_foreach(&_commits, i, o) {
|
||||
+ if((error = git_packbuilder_insert(_packbuilder, o, NULL)) < 0)
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ git_vector_foreach(&_commits, i, o) {
|
||||
+ git_object *obj;
|
||||
+ cl_git_pass(git_object_lookup(&obj, _repo, o, GIT_OBJECT_COMMIT));
|
||||
+ error = git_packbuilder_insert_tree(_packbuilder,
|
||||
+ git_commit_tree_id((git_commit *)obj));
|
||||
+ git_object_free(obj);
|
||||
+ if (error < 0)
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int fail_stage;
|
||||
+
|
||||
+static int packbuilder_cancel_after_n_calls_cb(int stage, uint32_t current, uint32_t total, void *payload)
|
||||
+{
|
||||
+
|
||||
+ /* Force the callback to run again on the next opportunity regardless
|
||||
+ of how fast we're running. */
|
||||
+ _packbuilder->last_progress_report_time = 0;
|
||||
+
|
||||
+ if (stage == fail_stage) {
|
||||
+ int *calls = (int *)payload;
|
||||
+ int n = *calls;
|
||||
+ /* Always decrement, including past zero. This way the error is only
|
||||
+ triggered once, making sure it is picked up immediately. */
|
||||
+ --*calls;
|
||||
+ if (n == 0)
|
||||
+ return GIT_EUSER;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void test_cancel(int n)
|
||||
+{
|
||||
+
|
||||
+ int calls_remaining = n;
|
||||
+ int err;
|
||||
+ git_buf buf = GIT_BUF_INIT;
|
||||
+
|
||||
+ /* Switch to a small repository, so that `packbuilder_cancel_after_n_calls_cb`
|
||||
+ can hack the time to call the callback on every opportunity. */
|
||||
+
|
||||
+ cl_git_pass(git_packbuilder_set_callbacks(_packbuilder, &packbuilder_cancel_after_n_calls_cb, &calls_remaining));
|
||||
+ err = seed_packbuilder();
|
||||
+ if (!err)
|
||||
+ err = git_packbuilder_write_buf(&buf, _packbuilder);
|
||||
+
|
||||
+ cl_assert_equal_i(GIT_EUSER, err);
|
||||
+}
|
||||
+void test_pack_cancel__cancel_after_add_0(void)
|
||||
+{
|
||||
+ fail_stage = GIT_PACKBUILDER_ADDING_OBJECTS;
|
||||
+ test_cancel(0);
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cancel_after_add_1(void)
|
||||
+{
|
||||
+ cl_skip();
|
||||
+ fail_stage = GIT_PACKBUILDER_ADDING_OBJECTS;
|
||||
+ test_cancel(1);
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cancel_after_delta_0(void)
|
||||
+{
|
||||
+ fail_stage = GIT_PACKBUILDER_DELTAFICATION;
|
||||
+ test_cancel(0);
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cancel_after_delta_1(void)
|
||||
+{
|
||||
+ fail_stage = GIT_PACKBUILDER_DELTAFICATION;
|
||||
+ test_cancel(1);
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cancel_after_delta_0_threaded(void)
|
||||
+{
|
||||
+#ifdef GIT_THREADS
|
||||
+ git_packbuilder_set_threads(_packbuilder, 8);
|
||||
+ fail_stage = GIT_PACKBUILDER_DELTAFICATION;
|
||||
+ test_cancel(0);
|
||||
+#else
|
||||
+ cl_skip();
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__cancel_after_delta_1_threaded(void)
|
||||
+{
|
||||
+#ifdef GIT_THREADS
|
||||
+ git_packbuilder_set_threads(_packbuilder, 8);
|
||||
+ fail_stage = GIT_PACKBUILDER_DELTAFICATION;
|
||||
+ test_cancel(1);
|
||||
+#else
|
||||
+ cl_skip();
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static int foreach_cb(void *buf, size_t len, void *payload)
|
||||
+{
|
||||
+ git_indexer *idx = (git_indexer *) payload;
|
||||
+ cl_git_pass(git_indexer_append(idx, buf, len, &_stats));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__foreach(void)
|
||||
+{
|
||||
+ git_indexer *idx;
|
||||
+
|
||||
+ seed_packbuilder();
|
||||
+
|
||||
+#ifdef GIT_EXPERIMENTAL_SHA256
|
||||
+ cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
|
||||
+#else
|
||||
+ cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
|
||||
+#endif
|
||||
+
|
||||
+ cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx));
|
||||
+ cl_git_pass(git_indexer_commit(idx, &_stats));
|
||||
+ git_indexer_free(idx);
|
||||
+}
|
||||
+
|
||||
+static int foreach_cancel_cb(void *buf, size_t len, void *payload)
|
||||
+{
|
||||
+ git_indexer *idx = (git_indexer *)payload;
|
||||
+ cl_git_pass(git_indexer_append(idx, buf, len, &_stats));
|
||||
+ return (_stats.total_objects > 2) ? -1111 : 0;
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__foreach_with_cancel(void)
|
||||
+{
|
||||
+ git_indexer *idx;
|
||||
+
|
||||
+ seed_packbuilder();
|
||||
+
|
||||
+#ifdef GIT_EXPERIMENTAL_SHA256
|
||||
+ cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
|
||||
+#else
|
||||
+ cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
|
||||
+#endif
|
||||
+
|
||||
+ cl_git_fail_with(
|
||||
+ git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111);
|
||||
+ git_indexer_free(idx);
|
||||
+}
|
||||
+
|
||||
+void test_pack_cancel__keep_file_check(void)
|
||||
+{
|
||||
+ assert(!git_disable_pack_keep_file_checks);
|
||||
+ cl_git_pass(git_libgit2_opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, true));
|
||||
+ assert(git_disable_pack_keep_file_checks);
|
||||
+}
|
||||
diff --git a/tests/resources/small.git/HEAD b/tests/resources/small.git/HEAD
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cb089cd89a7d7686d284d8761201649346b5aa1c
|
||||
GIT binary patch
|
||||
literal 23
|
||||
ecmXR)O|w!cN=+-)&qz&7Db~+TEG|hc;sO9;xClW2
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/config b/tests/resources/small.git/config
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..07d359d07cf1ed0c0074fdad71ffff5942f0adfa
|
||||
GIT binary patch
|
||||
literal 66
|
||||
zcmaz}&M!)h<>D+#Eyyp<EXgmbOv^9IO)M!(Eh^5;&r`5fFyP`$%gjm5%}+@M@=A(I
|
||||
MQ@J>k5{uv*03B5png9R*
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/description b/tests/resources/small.git/description
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..498b267a8c7812490d6479839c5577eaaec79d62
|
||||
GIT binary patch
|
||||
literal 73
|
||||
zcmWH|%S+5nO;IRHEyyp<EXgmbv{pz>$t+PQ$;d2LNXyJgRZve!Elw`VEGWs$&r??@
|
||||
Q$yWgB0LrH#Y0~2Y0PnOK(EtDd
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/applypatch-msg.sample b/tests/resources/small.git/hooks/applypatch-msg.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..dcbf8167fa503f96ff6a39c68409007eadc9b1f3
|
||||
GIT binary patch
|
||||
literal 535
|
||||
zcmY+AX;Q;542A#a6e8^~FyI8r&I~hf2QJ{GO6(?HuvEG*+#R{4EI%zhfA8r{j%sh$
|
||||
zHE~E-UtQd8{bq4@*S%jq3@bmxwQDXGv#o!N`o3AHMw3xD)hy0#>&E&zzl%vRffo<B
|
||||
z)-H|+CWHZ~O*S%cfYx9;02_ohIA<Bg(1SxF-6OCb&_lBkf{t<AM9r;%E(Hf#h{|a@
|
||||
z9>mqo=v6>_2NRa#TwDdYvTVQyueO*15Nlo%=#DXgC0bhF3vTa`LQGaO9;jeD$OP?~
|
||||
za$G4Q{z+Q_{5V?5h;a-noM$P{<>Q~j4o7u%#P6^o^16{y*jU=-K8GYD_dUtdj4FSx
|
||||
zSC0C!DvAnv%S!4d<Yg@O<;m`;oSw)=Fz+hrL<mY{rBr8j4pi^88FX3}jKrYUP)>gk
|
||||
XB^)11aoGMJPCqWs%IS0YSv(eBT&%T6
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/commit-msg.sample b/tests/resources/small.git/hooks/commit-msg.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..f3780f92349638ebe32f6baf24c7c3027675d7c9
|
||||
GIT binary patch
|
||||
literal 953
|
||||
zcmaJ<TW`}a6n<`g#Ya}rZCaYOzy?UGG&Tf#VG`?}7@eHtB=MTqneFUS%75oLS;atz
|
||||
zm&iUo=ey->y@-{3h^^Cx;#d0zEA@DDc$nY4ez&|=%jTg@_HU*ub=!!y$xW09TSjlj
|
||||
z(`I@QCsM`!9&80$I98wsQ8yK#)Orb<8re8FjkKh630D$QUDwi~(gkX=RunYm$rDjk
|
||||
zlp%RUSnzA#6yjdG5?T?2DcYKp+v_lts0ljn&bh3J0bD5@N@1UKZ190O6ZeWr-BuZ^
|
||||
zWRebCX%(%=Xoj#(xYk1Cjtr!=tyBesf@m6}8zY6Ijbz9i9ziI_jG9Mv<Cz(ymp*>R
|
||||
zDH*e>^ga9IR?2wrSrAVm;eButj4<aWB@zzNl|1Wp@4;}1O?MUF>Y>7(E2?b~jsu>&
|
||||
zRKCJ7bp#19sqYh627wD%D9R$8=Ml$TNlumDypl~$jBu*G>5fIR^FB0h0Ex&TGZNr>
|
||||
zL5hs1_K>taRb!|ThN9ns7^@4MXKP+6aGI_UK)T-M#rcP$;kN(Vcf#P)+5GzWa{l@J
|
||||
z>-E{`$1iiNVYxq27}<DnwLRXQUG0o_hw&da-s5T#H=`Y9D_8=eTZ?cpWatp#a1vs@
|
||||
z2BjrO)z@aTuI#g#`)oJcnhM7oYLT@~CHX@CNXv4>j;uo%;)r3kJI2xCFF~Ux;$Q%)
|
||||
wjbk6JlDCM`jU&P+UVOvg`|iYl<7~9k>HHB4I;pdlQ=I-^$DrHaN$@lH1?P!0U;qFB
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/fsmonitor-watchman.sample b/tests/resources/small.git/hooks/fsmonitor-watchman.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..41184ebc318c159f51cd1ebe2290559805df89d8
|
||||
GIT binary patch
|
||||
literal 4777
|
||||
zcmbtYYi}F368$Xwipg4lq(BeHMvzvH-4;n7DGJBPqq#tw3aed8+IU5-m)yvL>;Cqh
|
||||
z8FFRGj$`9CA8ao<GaSz2oMCnz4Rv-gw9b@j_$0GQT1?XYi|;S??Y`Z6`Z;}C6#27N
|
||||
z8ShS>J?j^$%==FV``-=rhLcPW`McSytRm~mEO7_&_cAVZrf1fFy*ha@8oe%*-aBYE
|
||||
zcjzZg>LOkgxuUr-XJnHyD;zmPnRaSc#!k_P*d_BttRdc+J6G7za5#+<HG#rlmbrN~
|
||||
z8DwU-3}VABEwM=0VLP@^Dy6ERR5_J6cmg|GEh*M1EliqCGwe^ZT-iZ$2Yc`4!I#WZ
|
||||
z5nGGhn7*jeW=2ydsmfAmm#=8AD<<;TI+#z{Q)kW;yE!%GB6f~7EtEMLdM47Qaz*8=
|
||||
zIObA(VVj-VG{Ax|66d*hi`+bRG>^Y1nkc2Oowk`ya47uUR3Feu?B<phm31&PQB<lt
|
||||
zb{W(W4wf#Bab%|Q_tKPS?3^o=5)Z8^Vh(#slNI}pO(f^|{U0GZhLnycSaNd&h?CaC
|
||||
z0XklU6^<ky6rES9T=na$M8P<_)aKMAMo+UDewAu4wF{#&6diFshiudixAoh|&0<BJ
|
||||
zR>(w;S{(VYzxh}q-=#zP@uxSx{wbyPUMFU;K(06)$o{07&3yI?q{GqMcQ1c_^M<0<
|
||||
zF4acAV)Il-V(rCTC1(;bsZ*}bl8dmejAk~yb`B}!^0;g^(o9kGUfZfDOvyp@x4OQt
|
||||
zSgWh6T|3eq;9MFs8-#z+FDM1h(IjRUP|``PxupgJ7CUHOH90gbgl^2~97`?_X{P))
|
||||
zB*$r1cDlF-%azKND}?Gv`2K8-9v5e`gQoft=j?T<&a13c^!wY_$D`5z-X1g?ty&6-
|
||||
zQN50{8?bUk9AI->^W@~~nkOghHIC2YN+<JiT_ob7ttND1oh`HH28Y+OV~HedG&uB`
|
||||
zy}rA*r_xT#bR`Q7-*)3t*(!Hf?jKzyxk=8hdi3L^d<p<uU9q_<4k&xEr4@YWv_vsW
|
||||
zp(#32bYtA5u|s#1+}h`0kwpz4kUD&+>AXkLQG_2-{Pq3%{`3KUMeG$iIn%%^6*NYb
|
||||
zn|_BdV#C)n4565Vcc<EWC-nglECZGy!j9I4&;hUCzr(?6TftH=0^@!mI^E@y5HZw8
|
||||
ztH&kaSNyg=O6riqR^MPOX6oD__Jz@K;*icS)?m$!p{S$n;*EwlO<L!d7;utu(W9D!
|
||||
zaF!B~xV^2i?wH0s?Lw%Q)(`aPkajs1XojlPv@Y-d5#YFg#KG+!r7A(dJLnkiJMs`p
|
||||
zV|_=d!upN{TsxH1?sZNdzxeHsmtzTV`1{pykJ_~+^*>X;uT8&z3vSi!HXGbUj2B!R
|
||||
zdz~&#<?<tHJql=W&((YpzS06y-Z6Cn^H!*9qH?pOrD~(GV=JJ~z{tpLnGK|xp&C1`
|
||||
zsbn7O86xjF<~G*S1l*;;Bh%6><Up=oKy99?62P^?M&22U6QFRBXLb&u%=Ur<74wRy
|
||||
zMRG!f{AvZ>fk#L-&k$fLwo$4?>12g@AXOKFekuo#6EHB%gmpD?1eyh%N8s{2wGoTu
|
||||
z*@6cEZ^ZW!FAF_|JL`NkV7k}0ow|-2jHwbgH0;c@Dq*o?@&c*HnGdyx6^su8Qk%2{
|
||||
z*ye(dxO*6-&>qn1+zw}tc6;=sOX{4WB=VqjTS^))y1jlX2Q;=e!qMmFA5lC$#;BxC
|
||||
z=Y%tRpWxb+_uQAvAw7Q{HGV#R$xb&udLCzZ+HN?kTyB};1EJ8UlQ5!>5eGW@)RX0n
|
||||
zkjj>EF!3=0Gl^8dzv$B^NMGRxJoqN4A`xq-@wCbrx*u2NmIJ1<fUDQ=*^)h6`vzco
|
||||
z3F+ro$F!F6pc<B;<;isobIgbVGKUBByoQ4#CO({S7g?<Dh0^!7uJ3gxS=6F;+^gQc
|
||||
zeKi4`4`Fm3p|BU2v{M|-u!#QGCXiM=k=%np0<ZOPQqEjP_nneyOdgEuG9IH&YYPtp
|
||||
zKB_dvcYCcyhyT#<uhUEL$o~!TUz;cb&|`uSM{Dkv%&W2lcpYL&kv)tUvVv?&>xZ%H
|
||||
zh;{|4T3(!E9sY#Ni(wUJYs1MmIc9bl)(4Nl3_wD_BWB>i<1S(LX7m*{Q7PU$muMS*
|
||||
zM!%0EZx-Vw=Zey;erC?SNxF;pY@^A%-krqzfLV2meBp1vWdyArFYn`DD19T)Hw(?n
|
||||
z)}{NP(Lk(o*?gl#B@pP7^*r|=;PIDT4|F#{2Hzh-AL0Rv$6uT;<CP7qxbYms@WU7}
|
||||
z%}TsHJ!V_56ZFF{BfI=8jTBxMEATG376pS6a;u1@c?{~sL<N52`U6fuLkz4P@Mb^b
|
||||
z2`Q48y&!C0&A+WRCJAdmo3u2#?eI=si9Vm47$|`m**x<wKkM=QR&g?C63@P5X@xP8
|
||||
zi5QG2b-Fdz%S0%1{kKvL%^RTdpK|SU^VJ7JCmKdwp1`;HRoGM7ef^k_s_}2An=cql
|
||||
za|{IaxQWpdq<ae&x3BOJq+M5QNIk#C{Nv@u>n|WzE4=slK?on@(fZeGhRgQCu56qB
|
||||
z{+n81Az96qnQjMY*-*r-KV*7;Z#4Q<xfjbcBx_6JAN-HP@bq+eI%HhAB9&vLyOap{
|
||||
bw<Ywj(b#kdcCk7dCBY;|DBNpPjIa1F6*dXN
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/post-update.sample b/tests/resources/small.git/hooks/post-update.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..9f95e41a39cf974958277c8881ac6cce405ebb20
|
||||
GIT binary patch
|
||||
literal 246
|
||||
zcmXZVO?HDY3<Ti4Poaiwjq^yGw9DKf7mz^&Ly=V5q$H=W^Rt|p_r9s#9Ea7VERo!9
|
||||
zyT9>uJRJJV$M^KdldiMhj?ImK6~FvwJ*L5a){QoM=L5TYHkGO1$UrO3`a>{?Opw|b
|
||||
zG(#59NQ#jFL9v~vgOVkM@^^(^A}onOE))yWEwhIlk&{ZyseZ^O0b=w8&O=BK{k<5B
|
||||
k^Q-B@eG}LeHrquz%(SVEp_N)VhYZikCW__82JXfD17`J9Qvd(}
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-applypatch.sample b/tests/resources/small.git/hooks/pre-applypatch.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..625837e25f91421b8809a097f4a3103dd387ef31
|
||||
GIT binary patch
|
||||
literal 481
|
||||
zcmY+ATTa6;5Jms9iouO45IBJXEg&Jm9@v1LPHMM_ZR|;#6tQ<EeSrA%_2`_rGr1_8
|
||||
z?aM?yVtIc%-@9SGSk&8x=grP-Lf`7!^=$7xgL=|ysZ}!av6zL~ywui}<2##V6L@!k
|
||||
zy=p^)V7%Wzs-g`9<Y9}^)&uN}BCrXR_T3@Z2$gSJON2`X=mAs+%@7n-2I}ZrP|TFA
|
||||
zvJJGDl3HPLP<@!Q!}zXQvey#qEE#a#$vs97i4=A0stF@YQ)k_ZajaoS^dVYBc&37_
|
||||
zVI(L=X<V335r9~7T<;|HfKF+yM}}LB9d96V)Si;sj(;9Rh$#P>h$71hSXq*MxP;V&
|
||||
zj0cY7SCL=x4`a46sF)C>94Gk%=3q$W2s;j6iHtB2$R0%gix4oK@&T~=ALd_o*CKxt
|
||||
I-`Pv{1Bpzc>;M1&
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-commit.sample b/tests/resources/small.git/hooks/pre-commit.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..10b39b2e26981b8f87ea424e735ef87359066dbb
|
||||
GIT binary patch
|
||||
literal 1706
|
||||
zcmZuxU2ohr5PY_N#pZ0-F<{-<Zkx1j&cMNSQ3FN`GzR*R1O+9oPV`BnOj7q@1pV!u
|
||||
zrF0Hl^i33(yR)-1d-!H%&2|=|^E~_R{N1zNJ-&Zmt-t?iwXv&i+ZN}Km(TX8Q$H4u
|
||||
zd7(m`|1iDmF5k@xV`p;C4zojASmLc}yN0QDZbhN=ri&CEt=XGuN1IwjGJ#a#`t-kG
|
||||
zDqY)}7+Ft|;YKwLYbtg$S(-TBO=x3cP1cd}%f4kB!<6Wu-dCwz-)KDMEuM^_Hh*UC
|
||||
zC`1)|)T<(U6b`+yOH!6p*Ll}@qastwA*dyjsgOf5C=?LTprfORG6O{5L%@S0wyHpj
|
||||
zu|_A-=NWnYYR5m7kvm6|&T~GzoJ_OKR3sgFUgw?ifho^NQhvK#{6g0=&Fh)%n}#m0
|
||||
zk1sNmwb_AMDq};OOGw5|;OyX#?yQMMH6yAk(x$3tjFjHE?c$E2XC_xXav8tnIeIG?
|
||||
zYMI|~MLEVGkuT*>v&v-X^RA+u>k}E$4d&uD7=g_fA8+pNNV=4s0|iD3p<=DTXClTS
|
||||
zXV23tJ;ECmN@M0j@zUAKEYW@3bv!SeYZ8ZH`YQNTApFVNc;F|9r5p4TqGs=>8E?6y
|
||||
zi|gY{iM#PG1nL?UE9YCnWTk72kgZPG*Usqw!~Qd3c?~@w2?%eg@~)+VlSs6N5Yf2^
|
||||
zz;ow<fjf3n`imj7u5lnzt||q9QFM(H@<3EJCK|l5P!$yDfn~U-(5Vu7s+GqxNKyeI
|
||||
zP=-Oa(KH&gK`NhUa`cLj3B8%qL};DR7dk!`A^h&3-hFB6p($5Ufy^tGir)3et}qK4
|
||||
zpkPKYWzC+?=&gw-L6S)S=<lfq)%uLUAa%~81Jf9hk)w~U!DItnoSy`m^}#38M}K-o
|
||||
z!PqisQkV!&z4E*V01ro~qlVK^0BI`pLk6D+)f~*y!hCvwHq8zY9BGh<2s$@b^A<8G
|
||||
zRaqk}&qZyyv&|0QDFPA%h4TgF&vdlc|JUq*=>F#K#r^&KMq1A`oqVGFpD&-!Pv|Rc
|
||||
zO3KSqA@h9nSc%bm`0)Amk6*J}@14J*1-219l%%7D!Pl}UK>|lVi0Dfgu2jN3WC!uL
|
||||
z0ej??b2iSehVgdnWHmZV4kUo*QL#aiIp}U=9x)IXk}JJ7VQ;CI9Rtn5e0VcjbY<bp
|
||||
zv{}WlG6L;H!EzFKdY>cVt+`x5D+svCGD<sXw4|)E|JX43I1_3P(sI4{wj87bPSrNG
|
||||
w!SIr>;Z5hm*<gY+X;)Ryx4=nzaab9m`bwE*^s(%u*E3HbUuOR@+&s_z1=MCi2LJ#7
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-merge-commit.sample b/tests/resources/small.git/hooks/pre-merge-commit.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..d8e8ad4bcf8337f23c78a98537ecab4831301202
|
||||
GIT binary patch
|
||||
literal 473
|
||||
zcmaJ-O;f@!5WV+TJd4B0whSt$H%Dh2t`2u6q1!glCNbGU;n%yxdNsG~zR#WA6xIwy
|
||||
zWEZHoU#u?nykD=Y<HPgeWDkDm^kTof*l(|%^gh!nHrZpo^vhMDjV;E1GD~K7wV*+D
|
||||
zz9lry9T0cHcm_KhDVXYvQ==FrLTT4u=bEr{U1yl7%thf%wJnv<XQZ`ZbQEezaWdS%
|
||||
zI;c?h9a)Y!ux<WK8rQd_aA^?61hv_Pf<t7*z1USuL40FxYz<|hybsO?qnN}aMpcuf
|
||||
z6phFw1%Xx=wUk(m>E$jSEQZ%SQ(}oLgslTvrKK@9Qf#b!hajVFnp9@oIix;NcI9Wk
|
||||
xjnh0ya!AWet{I7YpD;y6HXyzI*lfSvH=o6*7mJZPkuaYpm>vzZ`wyGEBtOQPo|pgt
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-push.sample b/tests/resources/small.git/hooks/pre-push.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..02cbd80c287f959fe33975bb66c56293e3f5b396
|
||||
GIT binary patch
|
||||
literal 1431
|
||||
zcmaJ>U60!~5PUX&#a1@z9B{IIZkjLT0t5kq9#8~D(I5{+8&J~9;#ndUk~-ZT`r|uG
|
||||
z$#K$$J{TsK<m~Lsu9iP+t-0TZ=sa(K+C6);54X>s*LP1}9!GoZ@4I4myMMG_di|of
|
||||
z%?llx{O8TS-#^<H#%^V=)RNv>;(OioEmPy%kwWQBA1OMzV{hsQ8XFzS1k!~YQoLa5
|
||||
zhtP1fA$q6VmMbbAC_9)4I628k*O5J$NR19uHe4QYDK<==I~SQk)Nu%xQ~<Hy8U>KH
|
||||
z53w=!ke(FGb_PpnZfd*+hnXDTn;2*`u^~;?+5C~cn?bRka7NR%06%e6O91{MAgN6J
|
||||
zmlO8{Biw4&wr&&(z4p3eln`E}XR9m9bNYZ7Ibrg(4yZIXrfgD7N*AFD7L3YSM#j}%
|
||||
zo__rOS5fr;@8UM<6cl+cv_$YB$PQ&9dv($eM*))g!_cu!QcSh-mqE9i#QDZT)=o#`
|
||||
z?8!RtE?w6p?GkGZ-6yt_p~5~4ecu|Sf^)6096%h*q-eNiEA1;Xwg)p~Q&iGSG7-IQ
|
||||
z9aII&`ps$WOojFA`*bjG<mBv1n0hcYZWN0~(X01-hx(ExqWqaXgSk*@-GMp|K_3!5
|
||||
z9|O21N3%~izh(4fbp9wzd+!b&7cVwSP5H00)m5ej-(s=Pl#(90UOhn@OA9u+D{i@r
|
||||
za4*CP0I#<d-)-#xq5q-iY5nIef2s5OuQjcA>kFk|E@sHHuD}W^d`7YJ3YE^zrQnqR
|
||||
zGoq?;YGKe)93o|_=^f%3U1KYZGPOXRRxK7w`UUbMMa3<86OmVH!EKP$8RCrn9mWX+
|
||||
zC?9yF!fRVLmud3hF<}x;;sR}f(*r}6Gap3fR6zLHR~kbMgD{98N`L+r&?3p~*0+FX
|
||||
zcAL%j=(SO}xTJUTvA`&Lf`2mv4koPG9&|<CA~EHbWHMoFPwT(&U=7t0`RoFZPO9Kq
|
||||
zwwe$i=T|AXY#hD$aZlNMH`wZ%gwilGJ(zeYpOn*F3cy0XKXio^Sj#WXx=PWV`WGaA
|
||||
B&~*R+
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-rebase.sample b/tests/resources/small.git/hooks/pre-rebase.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..193ee3f127387f469894675f0d621b5bb9c275da
|
||||
GIT binary patch
|
||||
literal 5006
|
||||
zcmb7IX>;2+68$XxiXKL@ma;l5d2^5Ba_rPh_DHI-u1#&_upttZXp;no03$20|NFiM
|
||||
zK#D#xQ>!Z3JkX8T-LDVm!B5j7y_{;JDmmTTef+K1oIiPzeEr+Ai*<2PUgnG4^ZB>p
|
||||
z_fkAvoR1emuf~ri^K$-px=4#D-v<wZ2Xv&$O_eTJh6d4)=DWL(NBs9G{k<+yMMw0T
|
||||
z$VH*-+LM)}u&m^`l8~1nt(3Z;R8v(KbY5#i3z+~8h0D}Xvq&3J8BMWDizPNpaeb~9
|
||||
zBN9bSkthfXzskapf%Zt{*e#}{QaNiaAVZ4{$;;I6<vKNhO@%7P-(;l-x=pPoExHC!
|
||||
zB(hA#cDdD?s4P=!)=-K{<kHAWKetl-8I8wwO<ihJNs-$dEvr;&S_@6E=mNSJ5;mg#
|
||||
zyb)MbqKH<one{qrV;ZQ6WL}yLtyi*ekNLf|uC6M!)Cmq7*l?g0d6`MlE49|}>Y9w&
|
||||
z`bCv#<YfTKtb`!}CyNYd;|(C?vRVQmWOfR9X?FZ#=f$No)^#4>2zVn=YnJyeNey(Y
|
||||
zRh`9vtLw~A+5zsjp|W0Nsa|29Rm!B>OoG5a+vi;ari8O>KkU!KAWg_fa3btK2x*_@
|
||||
z0bEc7J;Ubghm}n9bOi(Sv_B66nQ7U)J7f0fO}<cB8i8vG{r39s_>8Wuf*uorcIgEG
|
||||
zOHc|-V6+HlRhOP}?Cn?@5iwSl43abmBA^2lyL$+cpabCGVES+v^j^FO_}?FIp<qP?
|
||||
z#_?*YMHIkyZxJxS;h@A)WDJ0bN&+F-#_lFjAf^g_Pb#5YXqYe|dZUpa^zI)VOBXQQ
|
||||
zAMhT>%En%Ll?Z*7*}TwrZyg5OSZ9rY-`aU~Mc-jjv{Ll)FLMgtB4ujktfQ`Xhqrka
|
||||
zT=P!A;9w^;Z?PqpLwOLu=cj3L>TdUKw2;DMu)`oVkj}<z_EjO_2uWYuvKG==%Zu?h
|
||||
zJiMVR^c30RbpW}<+z;jjoNC}YI4f6QC7d-08*4mCB1>#bcDx4tYg=j%D`+i{W~fVM
|
||||
zVmZ>W9VMyin9c-0KzI_;iZ-g|OyzuG`Yq%(%dvl;ifnVr0;jWE&S`z|rQu=!yHBBO
|
||||
zx`OJ;oOQ(KKM<$(bC38o>pD0%|HA(E0TRw7qj$fJ_pRN+7Nm>dS<q{AcOz#-;d7_2
|
||||
zL$z(_nhH{vOzT(}>C(gLg{(`t+5Z=?o+}wXU4tHy+&%F&aRhFebeEhR2R5|<c6J);
|
||||
zEY(q5F5<n*XP0|=PtPBn$B)V~d$Os-?&8UlaVe_|jdkzoWNsTP-_uyq4$R6o<h`&@
|
||||
z{loXa{^#TF=NJBYu9qB?hs}x=It_O}ZjX(_wy9@X(lmkRpNi0{8T{O_b_j*JC^_SM
|
||||
zz3G?1$KCNWF-|`Jbx2cQ-y5LW?Z2eikngTZmsx5C(@({8<l)Ue+gIp##Mosfa~iZN
|
||||
zZ|NLN9uE6Xaqpwk+@D+f?$tg2JRCY`pwZwbR9OvEn*zYm`ffKIzl4{r{ZgjfpbuX)
|
||||
z_r0=0y3)T-j$gljPyEJO*6Y<pj7G72aLoqaTpc=#u)*xJcVUm0;k(n;r)^DQNa6Oj
|
||||
zWvlHEGg~lz`Q_8`yQ9<BZ;ylE1Z}bD<8}<uB9Y5lRB=;JUD0h?_)4H&EhJjvwzJx?
|
||||
zr<o_vk&75j_5^d$8Z$_Oc1=R-I_DlNZ2@~81oV*J6%o3RuiCz}^VEW>$#Ycbp^w@t
|
||||
zTl%=f1t=w+WpJzF<|CE@?SCNAz)%9?w33lQ8vrHJqPfH9@}qs*QXOG71W=ylx;wOB
|
||||
zcx!Bj^)Yy6WX$a^vBkBJ5Cob<oubBW+a#9bX{0bkMTX_2sIrs`HMk@$q{dK5h2-g}
|
||||
z({`~#gm#G?c#>qlaDx_B0c<3b+8)f84LCrt;e;qxc+7>VbwVK{skNv!wvBiTa^9Iu
|
||||
zkwP;VK)jH$WJ{`MRwAA9fal!y0dtV;FWg8PTkWU>CwnqD>1ZX2B@;$DlX%C5MI+}{
|
||||
z9xQVnffR*~v2KAUj*hCd<gRCjR7~6Q(vF%VT7j97iv3j4Z0p%mU`7t061~l7b$!#t
|
||||
z3*Pveii}aQ?QD9aiX>gul~`bk#mk`o>zk9)<2Uc8?hUZAEvd!`9em)~$Z)zev>w^8
|
||||
zyAgCP_$&Y)7HSQ84`xG}OeTavaEswwF|8Xpi5iZzZa@hCiv(J-%bfFC&)HLlO+Rhw
|
||||
zG6g?9eL5&A!SuJnQ6}LxG%tU+@vZ`i+!+Rz6iYvsTdhnPo7lW{m-}{hya@viX4)XZ
|
||||
zngaw+j;gloB#|UwI@8sOmQpc`h+bicQJnQIB5eifIMQNgD2+oai33m!34~xU|0Azj
|
||||
zhu$8z+T5^;Pxx@d{N)pzOJLSa^e;aDf$W%N5XcOf!mGC9l9j$Ev2h6N+6ZQC+CJzl
|
||||
zaM7?S!SrFLS2DASjj(h6y1WN3N?|bmqmyzm!&nLoE|`rKBOc_yDF$a#FsUn!IQf(t
|
||||
zdC&Us(kQz*7mv<H12p@UD8XaLXdK{>H^j*^MC@>wTDb}g%~sx*ng#>{@lR=XG-Z5_
|
||||
z#<9*Oh0joMzt;nS)ObAp)347`D=}r-;nV!TbIq&xrGRGsF6fZg+!VkfUei@_&l-M&
|
||||
zPqQ+Dw)RV}+)I8RuqAxa`Pv8e&!_gXS=e2-un>=Ktn}-;%lLZxaVn?Q>yZCb2R3Wk
|
||||
z77zr%;Rq&h|2ncqyKYmFI0148JVY7Q$V5p=dWj<MQ<8r+@QLq+UROk&%quICq^O2C
|
||||
zp(17882jXI)_GaqzAY4AjoB_nh8k*r1mJ>+Qqpu%i|xp2<qF`Tw6&3`h654ceBjZ7
|
||||
z4>C=WaOb2Wudn^h0EcD%$p9YVU1fnoRV9`(cy(vv6K>FXS!2jY>1GnU--7)4usH&K
|
||||
zao*&P^@9~YmUe|ZdLW@C>H;!*<TIU}-!Tw#3oqZA*99}b3&uHiGO<{I6!pMnAiQdS
|
||||
P!fA@Yk4s_DjDP<F98V`a
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/pre-receive.sample b/tests/resources/small.git/hooks/pre-receive.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..32b597f8c32399017c3d7d51134d1f6490ad9575
|
||||
GIT binary patch
|
||||
literal 601
|
||||
zcmZ`#+iu%141Kn~f>Vt3>Nw4M*;=?j(TBD#O@XCv0|MEhA;z}kTFRv@`tPHhp=&Yh
|
||||
zg%Zhg4i7o_k{a5i&f5;tZ==%}^Sn4aD_6%qs<o-wO_Prn;}`SPs_*$C$(7T|$#C3`
|
||||
zPt%-C8gelZ1GqAP8`ZQmg0{8-S9H{R@D>_XAuJt&EumdH4Yu`UjT<s+s_~uXh}qA8
|
||||
zg|_HG)%7Pdc&$7*uR0HF@)~vmFjqyD?XZwCbLen^h5t)sm9<90Oa!@Y%8!~rF8G?W
|
||||
zkzmCF8kMtuuelMHIAlqqnm?72LeGM1J4`w(kX9&%LQn}ForlDLjBoCyvxmo@x3kH^
|
||||
z^loxLyPiDWPo-cBMnsg2M6}kuPGHEGBqVkC{D&9Kt%xFAsTw4QC1$_=fwBl=3dI+e
|
||||
zaSxI}JS}=Z(Ec80eF`!Zq3mqapXI|UN!a)t;@4hcu%Eq2xcoW}%!><-+XHTuHss+b
|
||||
YOmM2;hq8Egm*4=7_P9T{21QBYH*F=mfB*mh
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/prepare-commit-msg.sample b/tests/resources/small.git/hooks/prepare-commit-msg.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..b1970da1b6d3f42f00069fd17c325de72cda812e
|
||||
GIT binary patch
|
||||
literal 1702
|
||||
zcmb_cTW{Mo6n>t6#i?x6xmZ$SFLf{QfG*3r0L?Pg?px55l8$UTGO3bO;spKi{V3XX
|
||||
z))weX0X>M9bNMcZ-6yG%>(n}JI2|25dr<ew@wmMG{l(3lx~bQz>}WZBP@ih?JX^+@
|
||||
zu#5O48P>yRX(m<b*PU*sORp92TCD1dX`%HE+1$w5k<(Ngu7zQ83#MGJR?<<W=d@yL
|
||||
z#heqwo{FmCg0g#x<~R+PBD#}q(MBn;V$x;%UrJPP3*l%XtlvTWChI2SfJ$9e`YvSj
|
||||
zRSOQ?NUgSMLI`3vL48YBHzwzVXoe7v0ef|0YHgV$N@?N(-R)rPqRDrK$n(%+OF$`P
|
||||
zWdjC5N~`#RjV9}aYwQ4_yF5O-$h2`>fDIhYP)doc1&TADZa@ZGpusJ$6G+e$ZMcmC
|
||||
zoOosDQPS}l{H?YPsq(4;0SGkATa9eeqAaDcj<jNAU+LTSmM1jo(ti~T0B7acJnnTX
|
||||
zTarYy;Husdxal0!S<ba8=uu&a*SNYtr7|d7$g-q3_JHER2*oBsVW~i~XXdMx%LW~0
|
||||
zT*960LF<qZ6K&FZ;vGmtyywBU3^Q>q8n2wALbFwU@2i@FAaRV!=uw-nwx1gKn2SvY
|
||||
z>Ff>;2sg!+Hxfkwv1lsiii=p6WenF=5)6LZc<a$zDCD$GRuwvG4Fr+B#h?#9gTbio
|
||||
zk#MdxC@WY%zSGN#i}Ts_#q`bf-{)`7CcWeB*7WlIyHjioJJWw&A5VItPUq3^9!r}S
|
||||
zbykelFV-VFvcr>QaZ=aS_}+-4Y&?!@HWh|<^gJ21!|T@+%On#w6azxPHV}XsRbe*w
|
||||
zR_TZ2XEsQa1lPK~biYqg@0-RW@5J1@=<87cFzEUABdCoFH2CZo?}l(Z*!OFqUxo>K
|
||||
z_d`l#4d9|H6;VPT{X?^{VJ>oL|D7K{BJwwqB>`YcPoGk+9hbvHnoQ{EM|kPgD_`wk
|
||||
zKm4#2xu;-y`RAm!=L_BnLvJ8$AZm8@?)v<%vwvsw8AF2x6!mTT;c72A_~U9nIq0ST
|
||||
zv)N0!I!^1p=g8-RQfx5)E_Mb_4I2vtQpI30XZ&t<!9D6nI|;V7YR3)l6=S~QhuwLQ
|
||||
g$e&^kTY-M99*<-Iw@(78*M5W!4}U}|8YyMx3->-9h5!Hn
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/push-to-checkout.sample b/tests/resources/small.git/hooks/push-to-checkout.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..a80611e18896f212c390d845e49a3f6d5693b41d
|
||||
GIT binary patch
|
||||
literal 2840
|
||||
zcmai0U31$u5PXh)#YOS7cE^-rw@uolNhe9&aUS|HtvhX>G$45tVUYj>fRdF?|9kfU
|
||||
zNR~aG=E)WbEbeyq7JTw}ZuHIE2kUtL<<n;$&G!2F^Je|kx2ug=4L5!H^!ogx`7o$&
|
||||
z%Il(3zAe6<oe$^F=A|}s`8}CDp*M#3M)gC-)LOeDUpYMl3YNy9R)I-T)pE7sy09aj
|
||||
zJ7%&5PnSB-F#2{jc><WLR{I2izuK%VHc+{hRfXe<^_q)8RjcE(6WX+F2)iAtDtI{x
|
||||
ztAHVBq)eSp_E^xcV^i_5KLIHA$g{zEjh?rsacu+(Eyvve2~Kmw%;n3g(kWB56j~Js
|
||||
z<yE5tYUsAR&PY0wgRvM8x!zgLX8SI!eVY&}YZ|>AoeCNptd-NM1aZLhESzC;I`+Ns
|
||||
zfmNNjdAp^W8#Q*}l>CT7RB9F5(BbI8ly2l~+E};JW|>&d1)=epZ-8vm8ppkbEVn#R
|
||||
zt30a5A-c(YQR8eM5%;|UAnO>rt!&@x@G@yp+92%w-}%(5P_+P&Wf_zb$f-Qrl5(7z
|
||||
z2ah(bkE;!DK(&aAMuQ%1TS>ai?wSXCOCSj=_}8x4IbCx^$}9q)<W{Y<9o<WqZo^oV
|
||||
z3bR;Qa%VT-M~kU@2n{=+=)C!MD`12;@<F*EtPfV3K#g^1%&ggH?4{m<R$WEKcUI4%
|
||||
zl6{ik6Bo46pmNjdXg5@?hn;SjG$}rr3Gy#-BGgVD$8oD)OcK(oqca)L_kk)UBZ_&6
|
||||
z*ourb#Yc8l3J+uSda_Y$GY--5Zp3QK9w^?P%E0xb57?fY+Q#+KU4)+R>whwv)SBt|
|
||||
zg#MX4;;Oau`m=MI9(^&zPbueY@~>3*ixX%mvR5m_1&nAg@ZKvY1E$O}&EtLiG;mhV
|
||||
z1xhMIm~fGjmf_#{62f`y;09?I7M1W2tWQvz<}i9lR>OpQyUJi45_&*pQus&EkwY<>
|
||||
zI|ZAx=*3i9a-)g)hXkvO7>UJ5MNgL(Z+-wpXVcgbSgpmFmbf1~DPA(OVGI&FNLeIE
|
||||
zNH!_aiH$vsif$_j7=T2{cS(!DOI`~bn@)vSd-0d7xL=DF;UNP|tW}4i<qWTSNCe|y
|
||||
zg9kV&L9g;FhC@tvsVu#V-brqShHy2qZpA!gg{ZTY>h>DvHtu9tY_pbJ6x(6E*hxgC
|
||||
zzNDao%qlr-IE%YGbS4hF!n!on7#W3$bX-_hbZAaws^nHu#)Dx=WzdbJ>AKzAy@T$x
|
||||
zSWE^x9+|TEHVEPyaPYa0DOChp?AeHSBBDbZNokQpAY{lE!7geZI=jV)G^2@<iI(N4
|
||||
zJLJjy@Y<VI$yq;3bVpJICW3D?YDMDl4Oe5pDf{d`i1_3Qx%4uX`$dOz<9e}jm2B-u
|
||||
z8-?%!7XuiNF2O&MAdl-iw{drG+$F^zT2Z7WRV#c6;IRZEf>l)&91Zb1+`T+oq9wWF
|
||||
zRV~kGTGce0O~p^6mj{kT5kL(pv>r;Lvd7VDX*P>A^Th`$3cWO<svk?_?FeP@458*2
|
||||
zA1PqUOdd%VP5&4~ocLK16{1GLll64c=mU81RMFstpnMoLuI7hNIE4N)U%h*#<Fz{C
|
||||
z9#>0<l7lRrls|W(8=W1O80P~6+U7<4BqC}N4-4GR3w#{O7YmH?JxwJfru2d?e){$5
|
||||
z@5R+`7Z;1)FW;OkE-(HPisCS;5F4O^Q>L81p4Ysdo3ZP1(SrR-peEdTo;-@bkB((G
|
||||
zPHYQXUL!@Q$e(OQ;R9r%@Afz+50I7>*^^c&&|E*r-jN)LH=pM4AqMwWxSv|nqjddE
|
||||
Z4{_hwv8!W(<d3>T<BC%y-6O5i(|^OS%`gA}
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/sendemail-validate.sample b/tests/resources/small.git/hooks/sendemail-validate.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..effa6f54f2a5c1f0cebe258bf4805904be4b4852
|
||||
GIT binary patch
|
||||
literal 2365
|
||||
zcmb_dU2oe)5PUX&#g-Nv2{5JDX_MA~3%Iq?8g*kpRgpYZIFU=~BI=I5J6e{T{`bz^
|
||||
zk+$48h#x9Ika!=nv$M0y{clD}-j1x(hDWbnzP?l2k8j?TH{brS+Nf21yPm)Nczma>
|
||||
zYw`X3V>TCdnSD1ru8&`j=2DIPbCT@SnIgUw>$+lEYP}+x8(BMYnr=iT3*ndq)xzaV
|
||||
z>I+qjv}vC#8_9M+b1p#uNS0M0)q<p>8!3p_LRQ0MA3M`!2foxzRUjbFY@}O~(ki=S
|
||||
zqscnq8cU*dY)D$$cqE}n)V0yIk>CNKHCrndOtSP*HbOb;nbwAHSb;R+gs^?^Dve%)
|
||||
zoW}t(*D}$>O3ab0TS^-;J|u&sb-PkZzo#kn*#xYt(;<xzKW(YtQZ$u23?yV#kyh1~
|
||||
z@+Idh;EG5jXx8@%<;Y_W8SA=|T;MPQ)TB!!<QcbU)YR4)79eeeg4|vp-8jm%Dl3^I
|
||||
zRS7+i3>FGuwzSb^g&RDiGcOz9TB;Hu`nJh)$W=C=XCSm2AY=$w3G3P-V#Oo+N*;#2
|
||||
z4ijJ-pBZ=;T(RTgp_HYrD!uW-dTMfkuqY5jwOy)~gM;#=P^i{!l7`pXTS^s(&^{RU
|
||||
zydaw}OpS#^D1cXM8?FW+fh`t7D(g;yr6|}fdaNtZBx3hlK~IpkTu3!Qq%R+zAo#<L
|
||||
zU&m+XIFB0>t}Bs8^3$vHD+-TGT@`F>H1Cc#WAVW;&$S6%fE2d6@kLS0g&ihIM{}0z
|
||||
z8#XhD>b>3{(BH|Px7}&lJ4%y1v<t$W+!F|W@<gaU4;MqSHKR(wdML<XnCv;zaPrSi
|
||||
zxVCvek26-bf#Q!H+uAgy_{e_1UZCq>(CihZJx@8MPoGdl*BJGD;usf*iS7%;{Joe;
|
||||
zNFuBa>*~o&qETDPo~u&~$FxE1xb^x&(CbE`Y3GfsibL2rl+L;>P6j&Y3U>K$mkp*6
|
||||
zd`Q{<^+^&;GskGjwD-%!boR&i-TC<Uvy02w+l$Nb?B}aL-%ZDpluqd=K_@}z*fyuV
|
||||
zzAs1Hf?3v$k!X7GTc8Q=r`WJ_Uu=>A9UOR|@=GYb5x#<f&WSMH%mCJU<#=7=qFdL6
|
||||
zG?Wz&6z&J<@I(B>+dhd7fkaVIR^pol`Mv+rUbmZ43dVL6^S7g3{NsPiG$iy$5EDB%
|
||||
z6KIgnb$H(n&t3e4E6d4V7w^B?JS}JkG)PM6+X3Co`SQs($O*AA+MG~{S7RJ=cy-l&
|
||||
z>~%3y`tjfx2>uOu<lDGWewcb=oL@}B@B6FCZ?oxSJWldrm%UfOduahk%C0H>tB_^s
|
||||
ziwG=e=ch|FQ0IkN91US7rhdQkXhwwt$gU0WEVDjo=IPb+?6PC=s8}J*ua(Ms))`UL
|
||||
fi$|vMHn?H<rred|1&u#kOoJ`%vx)-*g-ZSfgGvdP
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/hooks/update.sample b/tests/resources/small.git/hooks/update.sample
|
||||
new file mode 100755
|
||||
index 0000000000000000000000000000000000000000..c3430f6fe27e572a1cebdb2f2bec70add0642a60
|
||||
GIT binary patch
|
||||
literal 3707
|
||||
zcmb_fU2oeq6n(aS#jRq*br9K3y0z;^QgkUc^kKlTrB6js&@yE)mPu8l<0$L?`wmIT
|
||||
zrsXba))@gJi@e|G+<SfSXe`CeSQ}OG@sr8ZTUlQ{dzM}Q@O-hBi}GeUom`#X%FiYH
|
||||
zX?m4Rna-0RN2lfK)A3ZuvHcz$L<jUn62D=~vfz{}wIH2VqBLX_O$(JSXeF7H$}q!c
|
||||
zWY}C&R;eX%X?P{%d;|>_tSE3ettp-hLlsZCxaLX8(nU;bVRB;Ce6@s#eu2|WvLz>-
|
||||
zvy(&>Gyfp@+BtKnpqWkKi^+v{4jn_pNw_zeuxE<mRXKx8G3;9pl+45&4~hHW!G@wo
|
||||
za7?X(0B}HbX*ExkDmas*xzV)FxygC8AL?2Z1x-0QJqS@qn8sD7r{bm30@<%eL_gOw
|
||||
z;~85O$Xw2AS}Qp)5ViRUe3|ir8;&&I<B7Y6^!kkNyYXF4EY(b8_5DsTYn_&?wkdEz
|
||||
z0y$tADo<&}nGs5kg2-J=0KlEGPb(%<An(pXY{K`qIZCuwiT|2{8JD&5o_~`o6<;dD
|
||||
zi@J#zCE4={8j%<uy|iutvHu1QKo5Tno-BAF2FwD%%O#UDDum=w!;!PNe-cOFNX4)5
|
||||
zd>TifiGO|)w}OANj2n2D^K=o3j6P6uOL70#cbA{uzWXDlk1wr9GV1X(2W{RuTvjXV
|
||||
zCmd<W?kH^?PXjkbF`XZtwu1B+%4@ZvHIwGpJ*8@8`MWAhq^B|Hj1lzj3R8bVuMpNb
|
||||
zz4Gzk!3T3bY;WEGIww&kq9BYW6EP*q$K|EB-@TH(Fjtz*`HMTO?i+3E;5tdSah&xZ
|
||||
z+t!x4K7)dpy5wiJhlJz~8qF|r8a&-SV7^I3C@_q=P`yt@_x_F-;PQR)fzP<zNN>8u
|
||||
zH%V`94=q3)Dk)PHNrnFC(T1)Om6f{Usj;u1R->&XoCYVK2V3ZlgZuF?N}1+33<P7e
|
||||
z<0yVF?Qoa{l#7q(3&jv=Ab)gpM8A7`p%3InNzSxy)ZER2U0C#9zKpnLY0I?>OER*x
|
||||
z*9Z=L=zI8CN>A_^jYjt0F$psO$sL=38q5q|SG)qCN6{^>RFh5E&l5GZ$pEahnF&d+
|
||||
z5c>64t}uJPkf~_!VUj#&N%nC-gUMj%=@B=!V>&}xtj2%@-mOm#rQUSJ3(ccmc+fza
|
||||
znZ#uxF>N?QN5UrIEd!5RgHEf<eGg}P45aAs(Xs6u!XW9r1I*E6XJ^1movX@xYLuPz
|
||||
z|7xBN4z@b}#x>W#;(nKYF+D<*rdshJ$X-z2OZ2X;)nn@KSVdVhaA?}@3;6gZxb4<W
|
||||
z`9sa`0lR_azMX|=t_(FvG@%w2);9P}SG0u&K1(*oX3};~=<<!N*F$UTSxD{V&6mgL
|
||||
ztw9Ntc2eOF@c!OJytNC4T^#)Ien7-`dI{6s#co~0f^E3J<0Ty)l3xq2u@Y8DXTK>v
|
||||
zozoWSr{{+!h}zGpumG3H`=AvWpm^9kW;J$Jp^Xl*?8ckr`fqN%c|Z;VC0|cM4vSrk
|
||||
zH_O8Yvh85nvJp^;``wo8=z0f`FWg?`>gO#y1hjX1{}rTlg9rwIKia8eyGexA3GnuR
|
||||
z`Rg~XZoW;0pA)vI8=p5!+6sIn#C^FCvR>ffv39h6SCNi9v);%WD;WZ`of_MgwyRWy
|
||||
z-yY%n*Y>X8<Sf+RyB|Sr2YG@1w~%U$o`(5EDkJ|3$u=eMZA&_wxEsy<Xxh2k^tP?4
|
||||
RGx&ZHQs^8zuIpu!=pQhfp8Eg*
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/info/exclude b/tests/resources/small.git/info/exclude
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a5196d1be8fb59edf8062bef36d3a602e0812139
|
||||
GIT binary patch
|
||||
literal 240
|
||||
zcmXYqK?=e!6h!x)VxWtv*mf_t5?px$aS_{}Hj?C*<cHXeXE&AZhT*-L3ZoI&*l1%Z
|
||||
zqG?zr3TvQGZ__}H4(u*%p*rI=cU!%ya5ugfGATh66$IJHgu1Gs0-<N;$V+SsdE)?u
|
||||
zIq;i$f#WE4f$_MWicZjMEob9LWKMR#iwZq54~QgST^6=i%u0lUkJu-_J**QBMq}ZG
|
||||
Wth_)NDbl|`oQr&HAFQ5h`0jqAIZ*BZ
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/objects/88/f9a6eaa2cf008b9bc92847178621f21fa99f3e b/tests/resources/small.git/objects/88/f9a6eaa2cf008b9bc92847178621f21fa99f3e
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7d80b8d78e0dc55669d831a6638f48ec9fed0982
|
||||
GIT binary patch
|
||||
literal 50
|
||||
zcmV-20L}k+0V^p=O;s>9W-v4`Ff%bx$Vkn}$!Ay}rnY6F$m-Kg*KD_+;Lx#g4|^&N
|
||||
I02NaX#p`nv=Kufz
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b b/tests/resources/small.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..822bc151862ec3763cf2d3fa2372b93bbd3a4b65
|
||||
GIT binary patch
|
||||
literal 30
|
||||
mcmb<m^geacKghr&@q@?NlP9kSYMj?U<r(;diNWtH+YSKNt_|)0
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/objects/c6/97d4f7a6eac8d7b131673c340bd3cc5bac14d4 b/tests/resources/small.git/objects/c6/97d4f7a6eac8d7b131673c340bd3cc5bac14d4
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5adfa88cc6b00bb19f2031b8ab61f6d07f9ccdb8
|
||||
GIT binary patch
|
||||
literal 130
|
||||
zcmV-|0Db>>0i}&W3IZ_@1U=^!a~EV1casc=c+{&un1qQN*i9hD|0|m(2n|iwp*q%W
|
||||
z%N;b$hu%cM`$TMo*~EnC1BFP&Pfj~;jZVKXQ96s_PhV<-XAROi+@-v8dBLUa`!;GB
|
||||
k^i<X>XlEv8$>R)1G>9th&t3j;s7J{?^9n<zzF|~BaA?ar-~a#s
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/tests/resources/small.git/refs/heads/master b/tests/resources/small.git/refs/heads/master
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4eb36d22298f060fd324155ab854d9d6486fc498
|
||||
GIT binary patch
|
||||
literal 41
|
||||
ucmV~$!4Uu;2m`Rc)5uXl$AMP&AHjriQg~T$i(A>|7U^`%mXoWC24Q^m!3%@{
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
@@ -55,22 +55,18 @@ readonly NIX_INSTALLED_NIX="@nix@"
|
||||
readonly NIX_INSTALLED_CACERT="@cacert@"
|
||||
#readonly NIX_INSTALLED_NIX="/nix/store/j8dbv5w6jl34caywh2ygdy88knx1mdf7-nix-2.3.6"
|
||||
#readonly NIX_INSTALLED_CACERT="/nix/store/7dxhzymvy330i28ii676fl1pqwcahv2f-nss-cacert-3.49.2"
|
||||
EXTRACTED_NIX_PATH="$(dirname "$0")"
|
||||
readonly EXTRACTED_NIX_PATH
|
||||
readonly EXTRACTED_NIX_PATH="$(dirname "$0")"
|
||||
|
||||
# allow to override identity change command
|
||||
NIX_BECOME=${NIX_BECOME:-sudo}
|
||||
readonly NIX_BECOME
|
||||
readonly NIX_BECOME=${NIX_BECOME:-sudo}
|
||||
|
||||
ROOT_HOME=~root
|
||||
readonly ROOT_HOME
|
||||
readonly ROOT_HOME=~root
|
||||
|
||||
if [ -t 0 ] && [ -z "${NIX_INSTALLER_YES:-}" ]; then
|
||||
IS_HEADLESS='no'
|
||||
readonly IS_HEADLESS='no'
|
||||
else
|
||||
IS_HEADLESS='yes'
|
||||
readonly IS_HEADLESS='yes'
|
||||
fi
|
||||
readonly IS_HEADLESS
|
||||
|
||||
headless() {
|
||||
if [ "$IS_HEADLESS" = "yes" ]; then
|
||||
@@ -160,7 +156,6 @@ EOF
|
||||
}
|
||||
|
||||
nix_user_for_core() {
|
||||
# shellcheck disable=SC2059
|
||||
printf "$NIX_BUILD_USER_NAME_TEMPLATE" "$1"
|
||||
}
|
||||
|
||||
@@ -386,12 +381,10 @@ _sudo() {
|
||||
|
||||
# Ensure that $TMPDIR exists if defined.
|
||||
if [[ -n "${TMPDIR:-}" ]] && [[ ! -d "${TMPDIR:-}" ]]; then
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -m 0700 -p "${TMPDIR:-}"
|
||||
fi
|
||||
|
||||
SCRATCH=$(mktemp -d)
|
||||
readonly SCRATCH
|
||||
readonly SCRATCH=$(mktemp -d)
|
||||
finish_cleanup() {
|
||||
rm -rf "$SCRATCH"
|
||||
}
|
||||
@@ -684,8 +677,7 @@ create_directories() {
|
||||
# hiding behind || true, and the general state
|
||||
# should be one the user can repair once they
|
||||
# figure out where chown is...
|
||||
local get_chr_own
|
||||
get_chr_own="$(PATH="$(getconf PATH 2>/dev/null)" command -vp chown)"
|
||||
local get_chr_own="$(PATH="$(getconf PATH 2>/dev/null)" command -vp chown)"
|
||||
if [[ -z "$get_chr_own" ]]; then
|
||||
get_chr_own="$(command -v chown)"
|
||||
fi
|
||||
@@ -923,11 +915,9 @@ configure_shell_profile() {
|
||||
fi
|
||||
|
||||
if [ -e "$profile_target" ]; then
|
||||
{
|
||||
shell_source_lines
|
||||
cat "$profile_target"
|
||||
} | _sudo "extend your $profile_target with nix-daemon settings" \
|
||||
tee "$profile_target"
|
||||
shell_source_lines \
|
||||
| _sudo "extend your $profile_target with nix-daemon settings" \
|
||||
tee -a "$profile_target"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -1023,7 +1013,6 @@ main() {
|
||||
|
||||
# Set profile targets after OS-specific scripts are loaded
|
||||
if command -v poly_configure_default_profile_targets > /dev/null 2>&1; then
|
||||
# shellcheck disable=SC2207
|
||||
PROFILE_TARGETS=($(poly_configure_default_profile_targets))
|
||||
else
|
||||
PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc")
|
||||
|
||||
@@ -39,7 +39,7 @@ create_systemd_proxy_env() {
|
||||
vars="http_proxy https_proxy ftp_proxy all_proxy no_proxy HTTP_PROXY HTTPS_PROXY FTP_PROXY ALL_PROXY NO_PROXY"
|
||||
for v in $vars; do
|
||||
if [ "x${!v:-}" != "x" ]; then
|
||||
echo "Environment=${v}=$(escape_systemd_env "${!v}")"
|
||||
echo "Environment=${v}=$(escape_systemd_env ${!v})"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../.version
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libstore-tests/data/content-address
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libstore-tests/data/derivation
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libstore-tests/data/derived-path
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libutil-tests/data/hash
|
||||
@@ -1,107 +0,0 @@
|
||||
# Run with:
|
||||
# meson test --suite json-schema
|
||||
# Run with: (without shell / configure)
|
||||
# nix build .#nix-json-schema-checks
|
||||
|
||||
project(
|
||||
'nix-json-schema-checks',
|
||||
version : files('.version'),
|
||||
meson_version : '>= 1.1',
|
||||
license : 'LGPL-2.1-or-later',
|
||||
)
|
||||
|
||||
fs = import('fs')
|
||||
|
||||
# Note: The 'jsonschema' package provides the 'jv' command
|
||||
jv = find_program('jv', required : true)
|
||||
|
||||
# The schema directory is a committed symlink to the actual schema location
|
||||
schema_dir = meson.current_source_dir() / 'schema'
|
||||
|
||||
# Get all example files
|
||||
schemas = [
|
||||
{
|
||||
'stem' : 'hash',
|
||||
'schema' : schema_dir / 'hash-v1.yaml',
|
||||
'files' : [
|
||||
'sha256-base64.json',
|
||||
'sha256-base16.json',
|
||||
'sha256-nix32.json',
|
||||
'blake3-base64.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'content-address',
|
||||
'schema' : schema_dir / 'content-address-v1.yaml',
|
||||
'files' : [
|
||||
'text.json',
|
||||
'nar.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'store-path',
|
||||
'schema' : schema_dir / 'store-path-v1.yaml',
|
||||
'files' : [
|
||||
'simple.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'derivation',
|
||||
'schema' : schema_dir / 'derivation-v3.yaml',
|
||||
'files' : [
|
||||
'dyn-dep-derivation.json',
|
||||
'simple-derivation.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'derivation',
|
||||
'schema' : schema_dir / 'derivation-v3.yaml#/$defs/output',
|
||||
'files' : [
|
||||
'output-caFixedFlat.json',
|
||||
'output-caFixedNAR.json',
|
||||
'output-caFixedText.json',
|
||||
'output-caFloating.json',
|
||||
'output-deferred.json',
|
||||
'output-impure.json',
|
||||
'output-inputAddressed.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
'stem' : 'deriving-path',
|
||||
'schema' : schema_dir / 'deriving-path-v1.yaml',
|
||||
'files' : [
|
||||
'single_opaque.json',
|
||||
'single_built.json',
|
||||
'single_built_built.json',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
# Validate each example against the schema
|
||||
foreach schema : schemas
|
||||
stem = schema['stem']
|
||||
schema_file = schema['schema']
|
||||
if '#' not in schema_file
|
||||
# Validate the schema itself against JSON Schema Draft 04
|
||||
test(
|
||||
stem + '-schema-valid',
|
||||
jv,
|
||||
args : [
|
||||
'http://json-schema.org/draft-04/schema',
|
||||
schema_file,
|
||||
],
|
||||
suite : 'json-schema',
|
||||
)
|
||||
endif
|
||||
foreach example : schema['files']
|
||||
test(
|
||||
stem + '-example-' + fs.stem(example),
|
||||
jv,
|
||||
args : [
|
||||
schema_file,
|
||||
files(stem / example),
|
||||
],
|
||||
suite : 'json-schema',
|
||||
)
|
||||
endforeach
|
||||
endforeach
|
||||
@@ -1,54 +0,0 @@
|
||||
# Run with: nix build .#nix-json-schema-checks
|
||||
{
|
||||
lib,
|
||||
mkMesonDerivation,
|
||||
|
||||
meson,
|
||||
ninja,
|
||||
jsonschema,
|
||||
|
||||
# Configuration Options
|
||||
|
||||
version,
|
||||
}:
|
||||
|
||||
mkMesonDerivation (finalAttrs: {
|
||||
pname = "nix-json-schema-checks";
|
||||
inherit version;
|
||||
|
||||
workDir = ./.;
|
||||
fileset = lib.fileset.unions [
|
||||
../../.version
|
||||
../../doc/manual/source/protocols/json/schema
|
||||
../../src/libutil-tests/data/hash
|
||||
../../src/libstore-tests/data/content-address
|
||||
../../src/libstore-tests/data/store-path
|
||||
../../src/libstore-tests/data/derivation
|
||||
../../src/libstore-tests/data/derived-path
|
||||
./.
|
||||
];
|
||||
|
||||
outputs = [ "out" ];
|
||||
|
||||
passthru.externalNativeBuildInputs = [
|
||||
jsonschema
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
]
|
||||
++ finalAttrs.passthru.externalNativeBuildInputs;
|
||||
|
||||
doCheck = true;
|
||||
|
||||
mesonCheckFlags = [ "--print-errorlogs" ];
|
||||
|
||||
postInstall = ''
|
||||
touch $out
|
||||
'';
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
})
|
||||
@@ -1 +0,0 @@
|
||||
../../doc/manual/source/protocols/json/schema
|
||||
@@ -1 +0,0 @@
|
||||
../../src/libstore-tests/data/store-path
|
||||
@@ -83,22 +83,12 @@ nlohmann::json SingleBuiltPath::Built::toJSON(const StoreDirConfig & store) cons
|
||||
|
||||
nlohmann::json SingleBuiltPath::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
return std::visit(
|
||||
overloaded{
|
||||
[&](const SingleBuiltPath::Opaque & o) -> nlohmann::json { return store.printStorePath(o.path); },
|
||||
[&](const SingleBuiltPath::Built & b) { return b.toJSON(store); },
|
||||
},
|
||||
raw());
|
||||
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
|
||||
}
|
||||
|
||||
nlohmann::json BuiltPath::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
return std::visit(
|
||||
overloaded{
|
||||
[&](const BuiltPath::Opaque & o) -> nlohmann::json { return store.printStorePath(o.path); },
|
||||
[&](const BuiltPath::Built & b) { return b.toJSON(store); },
|
||||
},
|
||||
raw());
|
||||
return std::visit([&](const auto & buildable) { return buildable.toJSON(store); }, raw());
|
||||
}
|
||||
|
||||
RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
|
||||
@@ -117,11 +107,10 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
|
||||
"the derivation '%s' has unrealised output '%s' (derived-path.cc/toRealisedPaths)",
|
||||
store.printStorePath(p.drvPath->outPath()),
|
||||
outputName);
|
||||
DrvOutput key{*drvOutput, outputName};
|
||||
auto thisRealisation = store.queryRealisation(key);
|
||||
auto thisRealisation = store.queryRealisation(DrvOutput{*drvOutput, outputName});
|
||||
assert(thisRealisation); // We’ve built it, so we must
|
||||
// have the realisation
|
||||
res.insert(Realisation{*thisRealisation, std::move(key)});
|
||||
res.insert(*thisRealisation);
|
||||
} else {
|
||||
res.insert(outputPath);
|
||||
}
|
||||
|
||||
@@ -350,20 +350,6 @@ struct MixEnvironment : virtual Args
|
||||
void setEnviron();
|
||||
};
|
||||
|
||||
struct MixNoCheckSigs : virtual Args
|
||||
{
|
||||
CheckSigsFlag checkSigs = CheckSigs;
|
||||
|
||||
MixNoCheckSigs()
|
||||
{
|
||||
addFlag({
|
||||
.longName = "no-check-sigs",
|
||||
.description = "Do not require that paths are signed by trusted keys.",
|
||||
.handler = {&checkSigs, NoCheckSigs},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void completeFlakeInputAttrPath(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
|
||||
@@ -69,7 +69,7 @@ struct InstallableFlake : InstallableValue
|
||||
*/
|
||||
std::vector<ref<eval_cache::AttrCursor>> getCursors(EvalState & state) override;
|
||||
|
||||
ref<flake::LockedFlake> getLockedFlake() const;
|
||||
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
|
||||
|
||||
FlakeRef nixpkgsFlakeRef() const;
|
||||
};
|
||||
@@ -87,4 +87,6 @@ static inline FlakeRef defaultNixpkgsFlakeRef()
|
||||
return FlakeRef::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", "nixpkgs"}});
|
||||
}
|
||||
|
||||
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, std::shared_ptr<flake::LockedFlake> lockedFlake);
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -185,16 +185,16 @@ std::vector<ref<eval_cache::AttrCursor>> InstallableFlake::getCursors(EvalState
|
||||
return res;
|
||||
}
|
||||
|
||||
ref<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
||||
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
|
||||
{
|
||||
if (!_lockedFlake) {
|
||||
flake::LockFlags lockFlagsApplyConfig = lockFlags;
|
||||
// FIXME why this side effect?
|
||||
lockFlagsApplyConfig.applyNixConfig = true;
|
||||
_lockedFlake = make_ref<flake::LockedFlake>(lockFlake(flakeSettings, *state, flakeRef, lockFlagsApplyConfig));
|
||||
_lockedFlake =
|
||||
std::make_shared<flake::LockedFlake>(lockFlake(flakeSettings, *state, flakeRef, lockFlagsApplyConfig));
|
||||
}
|
||||
// _lockedFlake is now non-null but still just a shared_ptr
|
||||
return ref<flake::LockedFlake>(_lockedFlake);
|
||||
return _lockedFlake;
|
||||
}
|
||||
|
||||
FlakeRef InstallableFlake::nixpkgsFlakeRef() const
|
||||
|
||||
@@ -342,7 +342,8 @@ void completeFlakeRefWithFragment(
|
||||
parseFlakeRef(fetchSettings, expandTilde(flakeRefS), std::filesystem::current_path().string());
|
||||
|
||||
auto evalCache = openEvalCache(
|
||||
*evalState, make_ref<flake::LockedFlake>(lockFlake(flakeSettings, *evalState, flakeRef, lockFlags)));
|
||||
*evalState,
|
||||
std::make_shared<flake::LockedFlake>(lockFlake(flakeSettings, *evalState, flakeRef, lockFlags)));
|
||||
|
||||
auto root = evalCache->getRoot();
|
||||
|
||||
@@ -442,6 +443,42 @@ static StorePath getDeriver(ref<Store> store, const Installable & i, const Store
|
||||
return *derivers.begin();
|
||||
}
|
||||
|
||||
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, std::shared_ptr<flake::LockedFlake> lockedFlake)
|
||||
{
|
||||
auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
|
||||
? lockedFlake->getFingerprint(state.store, state.fetchSettings)
|
||||
: std::nullopt;
|
||||
auto rootLoader = [&state, lockedFlake]() {
|
||||
/* For testing whether the evaluation cache is
|
||||
complete. */
|
||||
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
|
||||
throw Error("not everything is cached, but evaluation is not allowed");
|
||||
|
||||
auto vFlake = state.allocValue();
|
||||
flake::callFlake(state, *lockedFlake, *vFlake);
|
||||
|
||||
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
|
||||
|
||||
auto aOutputs = vFlake->attrs()->get(state.symbols.create("outputs"));
|
||||
assert(aOutputs);
|
||||
|
||||
return aOutputs->value;
|
||||
};
|
||||
|
||||
if (fingerprint) {
|
||||
auto search = state.evalCaches.find(fingerprint.value());
|
||||
if (search == state.evalCaches.end()) {
|
||||
search =
|
||||
state.evalCaches
|
||||
.emplace(fingerprint.value(), make_ref<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader))
|
||||
.first;
|
||||
}
|
||||
return search->second;
|
||||
} else {
|
||||
return make_ref<nix::eval_cache::EvalCache>(std::nullopt, state, rootLoader);
|
||||
}
|
||||
}
|
||||
|
||||
Installables SourceExprCommand::parseInstallables(ref<Store> store, std::vector<std::string> ss)
|
||||
{
|
||||
Installables result;
|
||||
@@ -567,28 +604,28 @@ std::vector<BuiltPathWithResult> Installable::build(
|
||||
|
||||
static void throwBuildErrors(std::vector<KeyedBuildResult> & buildResults, const Store & store)
|
||||
{
|
||||
std::vector<std::pair<const KeyedBuildResult *, const KeyedBuildResult::Failure *>> failed;
|
||||
std::vector<KeyedBuildResult> failed;
|
||||
for (auto & buildResult : buildResults) {
|
||||
if (auto * failure = buildResult.tryGetFailure()) {
|
||||
failed.push_back({&buildResult, failure});
|
||||
if (!buildResult.success()) {
|
||||
failed.push_back(buildResult);
|
||||
}
|
||||
}
|
||||
|
||||
auto failedResult = failed.begin();
|
||||
if (failedResult != failed.end()) {
|
||||
if (failed.size() == 1) {
|
||||
failedResult->second->rethrow();
|
||||
failedResult->rethrow();
|
||||
} else {
|
||||
StringSet failedPaths;
|
||||
for (; failedResult != failed.end(); failedResult++) {
|
||||
if (!failedResult->second->errorMsg.empty()) {
|
||||
if (!failedResult->errorMsg.empty()) {
|
||||
logError(
|
||||
ErrorInfo{
|
||||
.level = lvlError,
|
||||
.msg = failedResult->second->errorMsg,
|
||||
.msg = failedResult->errorMsg,
|
||||
});
|
||||
}
|
||||
failedPaths.insert(failedResult->first->path.to_string(store));
|
||||
failedPaths.insert(failedResult->path.to_string(store));
|
||||
}
|
||||
throw Error("build of %s failed", concatStringsSep(", ", quoteStrings(failedPaths)));
|
||||
}
|
||||
@@ -658,14 +695,12 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
|
||||
auto buildResults = store->buildPathsWithResults(pathsToBuild, bMode, evalStore);
|
||||
throwBuildErrors(buildResults, *store);
|
||||
for (auto & buildResult : buildResults) {
|
||||
// If we didn't throw, they must all be sucesses
|
||||
auto & success = std::get<nix::BuildResult::Success>(buildResult.inner);
|
||||
for (auto & aux : backmap[buildResult.path]) {
|
||||
std::visit(
|
||||
overloaded{
|
||||
[&](const DerivedPath::Built & bfd) {
|
||||
std::map<std::string, StorePath> outputs;
|
||||
for (auto & [outputName, realisation] : success.builtOutputs)
|
||||
for (auto & [outputName, realisation] : buildResult.builtOutputs)
|
||||
outputs.emplace(outputName, realisation.outPath);
|
||||
res.push_back(
|
||||
{aux.installable,
|
||||
|
||||
@@ -95,7 +95,6 @@ this_library = library(
|
||||
'nixcmd',
|
||||
sources,
|
||||
config_priv_h,
|
||||
soversion : nix_soversion,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -669,7 +669,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
|
||||
ss << "No documentation found.\n\n";
|
||||
}
|
||||
|
||||
auto markdown = ss.view();
|
||||
auto markdown = toView(ss);
|
||||
logger->cout(trim(renderMarkdownToTerminal(markdown)));
|
||||
|
||||
} else
|
||||
@@ -760,7 +760,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
|
||||
void NixRepl::initEnv()
|
||||
{
|
||||
env = &state->mem.allocEnv(envSize);
|
||||
env = &state->allocEnv(envSize);
|
||||
env->up = &state->baseEnv;
|
||||
displ = 0;
|
||||
staticEnv->vars.clear();
|
||||
@@ -869,8 +869,14 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)
|
||||
|
||||
Expr * NixRepl::parseString(std::string s)
|
||||
{
|
||||
return state->parseExprFromString(std::move(s), state->rootPath("."), staticEnv);
|
||||
}
|
||||
|
||||
void NixRepl::evalString(std::string s, Value & v)
|
||||
{
|
||||
Expr * e;
|
||||
try {
|
||||
return state->parseExprFromString(std::move(s), state->rootPath("."), staticEnv);
|
||||
e = parseString(s);
|
||||
} catch (ParseError & e) {
|
||||
if (e.msg().find("unexpected end of file") != std::string::npos)
|
||||
// For parse errors on incomplete input, we continue waiting for the next line of
|
||||
@@ -879,11 +885,6 @@ Expr * NixRepl::parseString(std::string s)
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void NixRepl::evalString(std::string s, Value & v)
|
||||
{
|
||||
Expr * e = parseString(s);
|
||||
e->eval(*state, *env, v);
|
||||
state->forceValue(v, v.determinePos(noPos));
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixexprc',
|
||||
sources,
|
||||
soversion : nix_soversion,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "nix_api_util_internal.h"
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
# include <boost/unordered/concurrent_flat_map.hpp>
|
||||
# include <mutex>
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -137,7 +137,7 @@ nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Sto
|
||||
|
||||
void nix_eval_state_builder_free(nix_eval_state_builder * builder)
|
||||
{
|
||||
operator delete(builder, static_cast<std::align_val_t>(alignof(nix_eval_state_builder)));
|
||||
delete builder;
|
||||
}
|
||||
|
||||
nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_builder * builder)
|
||||
@@ -203,24 +203,32 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
|
||||
|
||||
void nix_state_free(EvalState * state)
|
||||
{
|
||||
operator delete(state, static_cast<std::align_val_t>(alignof(EvalState)));
|
||||
delete state;
|
||||
}
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
boost::concurrent_flat_map<
|
||||
std::unordered_map<
|
||||
const void *,
|
||||
unsigned int,
|
||||
std::hash<const void *>,
|
||||
std::equal_to<const void *>,
|
||||
traceable_allocator<std::pair<const void * const, unsigned int>>>
|
||||
nix_refcounts{};
|
||||
nix_refcounts;
|
||||
|
||||
std::mutex nix_refcount_lock;
|
||||
|
||||
nix_err nix_gc_incref(nix_c_context * context, const void * p)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
nix_refcounts.insert_or_visit({p, 1}, [](auto & kv) { kv.second++; });
|
||||
std::scoped_lock lock(nix_refcount_lock);
|
||||
auto f = nix_refcounts.find(p);
|
||||
if (f != nix_refcounts.end()) {
|
||||
f->second++;
|
||||
} else {
|
||||
nix_refcounts[p] = 1;
|
||||
}
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -231,12 +239,12 @@ nix_err nix_gc_decref(nix_c_context * context, const void * p)
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
bool fail = true;
|
||||
nix_refcounts.erase_if(p, [&](auto & kv) {
|
||||
fail = false;
|
||||
return !--kv.second;
|
||||
});
|
||||
if (fail)
|
||||
std::scoped_lock lock(nix_refcount_lock);
|
||||
auto f = nix_refcounts.find(p);
|
||||
if (f != nix_refcounts.end()) {
|
||||
if (--f->second == 0)
|
||||
nix_refcounts.erase(f);
|
||||
} else
|
||||
throw std::runtime_error("nix_gc_decref: object was not referenced");
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nix/expr/attr-set.hh"
|
||||
#include "nix/expr/eval-error.hh"
|
||||
#include "nix/util/configuration.hh"
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
@@ -89,8 +90,13 @@ static void nix_c_primop_wrapper(
|
||||
f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
|
||||
|
||||
if (ctx.last_err_code != NIX_OK) {
|
||||
/* TODO: Throw different errors depending on the error code */
|
||||
state.error<nix::EvalError>("Error from custom function: %s", *ctx.last_err).atPos(pos).debugThrow();
|
||||
if (ctx.last_err_code == NIX_ERR_RECOVERABLE) {
|
||||
state.error<nix::RecoverableEvalError>("Recoverable error from custom function: %s", *ctx.last_err)
|
||||
.atPos(pos)
|
||||
.debugThrow();
|
||||
} else {
|
||||
state.error<nix::EvalError>("Error from custom function: %s", *ctx.last_err).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
|
||||
if (!vTmp.isValid()) {
|
||||
@@ -177,6 +183,8 @@ ValueType nix_get_type(nix_c_context * context, const nix_value * value)
|
||||
switch (v.type()) {
|
||||
case nThunk:
|
||||
return NIX_TYPE_THUNK;
|
||||
case nFailed:
|
||||
return NIX_TYPE_FAILED;
|
||||
case nInt:
|
||||
return NIX_TYPE_INT;
|
||||
case nFloat:
|
||||
@@ -326,10 +334,6 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
assert(v.type() == nix::nList);
|
||||
if (ix >= v.listSize()) {
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "list index out of bounds");
|
||||
return nullptr;
|
||||
}
|
||||
auto * p = v.listView()[ix];
|
||||
nix_gc_incref(nullptr, p);
|
||||
if (p != nullptr)
|
||||
@@ -339,26 +343,6 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_value *
|
||||
nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
assert(v.type() == nix::nList);
|
||||
if (ix >= v.listSize()) {
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "list index out of bounds");
|
||||
return nullptr;
|
||||
}
|
||||
auto * p = v.listView()[ix];
|
||||
nix_gc_incref(nullptr, p);
|
||||
// Note: intentionally NOT calling forceValue() to keep the element lazy
|
||||
return as_nix_value_ptr(p);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
|
||||
{
|
||||
if (context)
|
||||
@@ -379,27 +363,6 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_value *
|
||||
nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
assert(v.type() == nix::nAttrs);
|
||||
nix::Symbol s = state->state.symbols.create(name);
|
||||
auto attr = v.attrs()->get(s);
|
||||
if (attr) {
|
||||
nix_gc_incref(nullptr, attr->value);
|
||||
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
|
||||
return as_nix_value_ptr(attr->value);
|
||||
}
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
|
||||
return nullptr;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name)
|
||||
{
|
||||
if (context)
|
||||
@@ -416,28 +379,13 @@ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalS
|
||||
NIXC_CATCH_ERRS_RES(false);
|
||||
}
|
||||
|
||||
static void collapse_attrset_layer_chain_if_needed(nix::Value & v, EvalState * state)
|
||||
{
|
||||
auto & attrs = *v.attrs();
|
||||
if (attrs.isLayered()) {
|
||||
auto bindings = state->state.buildBindings(attrs.size());
|
||||
std::ranges::copy(attrs, std::back_inserter(bindings));
|
||||
v.mkAttrs(bindings);
|
||||
}
|
||||
}
|
||||
|
||||
nix_value *
|
||||
nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name)
|
||||
nix_value * nix_get_attr_byidx(
|
||||
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
collapse_attrset_layer_chain_if_needed(v, state);
|
||||
if (i >= v.attrs()->size()) {
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds");
|
||||
return nullptr;
|
||||
}
|
||||
const nix::Attr & a = (*v.attrs())[i];
|
||||
*name = state->state.symbols[a.name].c_str();
|
||||
nix_gc_incref(nullptr, a.value);
|
||||
@@ -447,38 +395,13 @@ nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_value * nix_get_attr_byidx_lazy(
|
||||
nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name)
|
||||
const char *
|
||||
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
collapse_attrset_layer_chain_if_needed(v, state);
|
||||
if (i >= v.attrs()->size()) {
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds (Nix C API contract violation)");
|
||||
return nullptr;
|
||||
}
|
||||
const nix::Attr & a = (*v.attrs())[i];
|
||||
*name = state->state.symbols[a.name].c_str();
|
||||
nix_gc_incref(nullptr, a.value);
|
||||
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
|
||||
return as_nix_value_ptr(a.value);
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
const char * nix_get_attr_name_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_in(value);
|
||||
collapse_attrset_layer_chain_if_needed(v, state);
|
||||
if (i >= v.attrs()->size()) {
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "attribute index out of bounds (Nix C API contract violation)");
|
||||
return nullptr;
|
||||
}
|
||||
const nix::Attr & a = (*v.attrs())[i];
|
||||
return state->state.symbols[a.name].c_str();
|
||||
}
|
||||
@@ -679,7 +602,7 @@ nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * b
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto & v = check_value_not_null(value);
|
||||
nix::Symbol s = bb->builder.symbols.get().create(name);
|
||||
nix::Symbol s = bb->builder.state.get().symbols.create(name);
|
||||
bb->builder.insert(s, &v);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
|
||||
@@ -32,7 +32,8 @@ typedef enum {
|
||||
NIX_TYPE_ATTRS,
|
||||
NIX_TYPE_LIST,
|
||||
NIX_TYPE_FUNCTION,
|
||||
NIX_TYPE_EXTERNAL
|
||||
NIX_TYPE_EXTERNAL,
|
||||
NIX_TYPE_FAILED,
|
||||
} ValueType;
|
||||
|
||||
// forward declarations
|
||||
@@ -265,24 +266,9 @@ ExternalValue * nix_get_external(nix_c_context * context, nix_value * value);
|
||||
*/
|
||||
nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
|
||||
|
||||
/** @brief Get the ix'th element of a list without forcing evaluation of the element
|
||||
*
|
||||
* Returns the list element without forcing its evaluation, allowing access to lazy values.
|
||||
* The list value itself must already be evaluated.
|
||||
*
|
||||
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect (must be an evaluated list)
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] ix list element to get
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
nix_value *
|
||||
nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int ix);
|
||||
|
||||
/** @brief Get an attr by name
|
||||
*
|
||||
* Use nix_gc_decref when you're done with the pointer
|
||||
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] state nix evaluator state
|
||||
@@ -291,21 +277,6 @@ nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalSt
|
||||
*/
|
||||
nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
|
||||
|
||||
/** @brief Get an attribute value by attribute name, without forcing evaluation of the attribute's value
|
||||
*
|
||||
* Returns the attribute value without forcing its evaluation, allowing access to lazy values.
|
||||
* The attribute set value itself must already be evaluated.
|
||||
*
|
||||
* Use nix_gc_decref when you're done with the pointer
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect (must be an evaluated attribute set)
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] name attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
nix_value *
|
||||
nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
|
||||
|
||||
/** @brief Check if an attribute name exists on a value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
@@ -315,21 +286,11 @@ nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalS
|
||||
*/
|
||||
bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name);
|
||||
|
||||
/** @brief Get an attribute by index
|
||||
/** @brief Get an attribute by index in the sorted bindings
|
||||
*
|
||||
* Also gives you the name.
|
||||
*
|
||||
* Attributes are returned in an unspecified order which is NOT suitable for
|
||||
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
|
||||
* is responsible for sorting the attributes or storing them in an ordered map to
|
||||
* ensure deterministic behavior in your application.
|
||||
*
|
||||
* @note When Nix does sort attributes, which it does for virtually all intermediate
|
||||
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
|
||||
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
|
||||
* applying this same ordering for consistency.
|
||||
*
|
||||
* Use nix_gc_decref when you're done with the pointer
|
||||
* Owned by the GC. Use nix_gc_decref when you're done with the pointer
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] state nix evaluator state
|
||||
@@ -337,50 +298,12 @@ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalS
|
||||
* @param[out] name will store a pointer to the attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
nix_value *
|
||||
nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name);
|
||||
nix_value * nix_get_attr_byidx(
|
||||
nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i, const char ** name);
|
||||
|
||||
/** @brief Get an attribute by index, without forcing evaluation of the attribute's value
|
||||
/** @brief Get an attribute name by index in the sorted bindings
|
||||
*
|
||||
* Also gives you the name.
|
||||
*
|
||||
* Returns the attribute value without forcing its evaluation, allowing access to lazy values.
|
||||
* The attribute set value itself must already have been evaluated.
|
||||
*
|
||||
* Attributes are returned in an unspecified order which is NOT suitable for
|
||||
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
|
||||
* is responsible for sorting the attributes or storing them in an ordered map to
|
||||
* ensure deterministic behavior in your application.
|
||||
*
|
||||
* @note When Nix does sort attributes, which it does for virtually all intermediate
|
||||
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
|
||||
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
|
||||
* applying this same ordering for consistency.
|
||||
*
|
||||
* Use nix_gc_decref when you're done with the pointer
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect (must be an evaluated attribute set)
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] i attribute index
|
||||
* @param[out] name will store a pointer to the attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
nix_value * nix_get_attr_byidx_lazy(
|
||||
nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name);
|
||||
|
||||
/** @brief Get an attribute name by index
|
||||
*
|
||||
* Returns the attribute name without forcing evaluation of the attribute's value.
|
||||
*
|
||||
* Attributes are returned in an unspecified order which is NOT suitable for
|
||||
* reproducible operations. In Nix's domain, reproducibility is paramount. The caller
|
||||
* is responsible for sorting the attributes or storing them in an ordered map to
|
||||
* ensure deterministic behavior in your application.
|
||||
*
|
||||
* @note When Nix does sort attributes, which it does for virtually all intermediate
|
||||
* operations and outputs, it uses byte-wise lexicographic order (equivalent to
|
||||
* lexicographic order by Unicode scalar value for valid UTF-8). We recommend
|
||||
* applying this same ordering for consistency.
|
||||
* Useful when you want the name but want to avoid evaluation.
|
||||
*
|
||||
* Owned by the nix EvalState
|
||||
* @param[out] context Optional, stores error information
|
||||
@@ -389,7 +312,8 @@ nix_value * nix_get_attr_byidx_lazy(
|
||||
* @param[in] i attribute index
|
||||
* @return name, NULL in case of errors
|
||||
*/
|
||||
const char * nix_get_attr_name_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i);
|
||||
const char *
|
||||
nix_get_attr_name_byidx(nix_c_context * context, const nix_value * value, EvalState * state, unsigned int i);
|
||||
|
||||
/**@}*/
|
||||
/** @name Initializers
|
||||
|
||||
@@ -26,20 +26,11 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
LibExprTest(ref<Store> store, auto && makeEvalSettings)
|
||||
LibExprTest()
|
||||
: LibStoreTest()
|
||||
, evalSettings(makeEvalSettings(readOnlyMode))
|
||||
, state({}, store, fetchSettings, evalSettings, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
LibExprTest()
|
||||
: LibExprTest(openStore("dummy://"), [](bool & readOnlyMode) {
|
||||
EvalSettings settings{readOnlyMode};
|
||||
settings.nixPath = {};
|
||||
return settings;
|
||||
})
|
||||
{
|
||||
evalSettings.nixPath = {};
|
||||
}
|
||||
|
||||
Value eval(std::string input, bool forceValue = true)
|
||||
|
||||
@@ -44,7 +44,6 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nix-expr-test-support',
|
||||
sources,
|
||||
soversion : nix_soversion,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/expr/tests/libexpr.hh"
|
||||
#include "nix/util/memory-source-accessor.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -175,41 +174,4 @@ TEST_F(EvalStateTest, getBuiltin_fail)
|
||||
ASSERT_THROW(state.getBuiltin("nonexistent"), EvalError);
|
||||
}
|
||||
|
||||
class PureEvalTest : public LibExprTest
|
||||
{
|
||||
public:
|
||||
PureEvalTest()
|
||||
: LibExprTest(openStore("dummy://", {{"read-only", "false"}}), [](bool & readOnlyMode) {
|
||||
EvalSettings settings{readOnlyMode};
|
||||
settings.pureEval = true;
|
||||
settings.restrictEval = true;
|
||||
return settings;
|
||||
})
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PureEvalTest, pathExists)
|
||||
{
|
||||
ASSERT_THAT(eval("builtins.pathExists /."), IsFalse());
|
||||
ASSERT_THAT(eval("builtins.pathExists /nix"), IsFalse());
|
||||
ASSERT_THAT(eval("builtins.pathExists /nix/store"), IsFalse());
|
||||
|
||||
{
|
||||
std::string contents = "Lorem ipsum";
|
||||
|
||||
StringSource s{contents};
|
||||
auto path = state.store->addToStoreFromDump(
|
||||
s, "source", FileSerialisationMethod::Flat, ContentAddressMethod::Raw::Text, HashAlgorithm::SHA256);
|
||||
auto printed = store->printStorePath(path);
|
||||
|
||||
ASSERT_THROW(eval(fmt("builtins.readFile %s", printed)), RestrictedPathError);
|
||||
ASSERT_THAT(eval(fmt("builtins.pathExists %s", printed)), IsFalse());
|
||||
|
||||
ASSERT_THROW(eval("builtins.readDir /."), RestrictedPathError);
|
||||
state.allowPath(path); // FIXME: This shouldn't behave this way.
|
||||
ASSERT_THAT(eval("builtins.readDir /."), IsAttrsOfSize(0));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/tests/test-main.hh"
|
||||
#include "nix/util/config-global.hh"
|
||||
#include <cstdlib>
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/util/logging.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
auto res = testMainForBuidingPre(argc, argv);
|
||||
if (res)
|
||||
return res;
|
||||
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
|
||||
printError("test-build-remote: not supported in libexpr unit tests");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
|
||||
settings.buildHook = {};
|
||||
|
||||
#ifdef __linux__ // should match the conditional around sandboxBuildDir declaration.
|
||||
|
||||
// When building and testing nix within the host's Nix sandbox, our store dir will be located in the host's
|
||||
// sandboxBuildDir, e.g.: Host
|
||||
// storeDir = /nix/store
|
||||
// sandboxBuildDir = /build
|
||||
// This process
|
||||
// storeDir = /build/foo/bar/store
|
||||
// sandboxBuildDir = /build
|
||||
// However, we have a rule that the store dir must not be inside the storeDir, so we need to pick a different
|
||||
// sandboxBuildDir.
|
||||
settings.sandboxBuildDir = "/test-build-dir-instead-of-usual-build-dir";
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Avoid this error, when already running in a sandbox:
|
||||
// sandbox-exec: sandbox_apply: Operation not permitted
|
||||
settings.sandboxMode = smDisabled;
|
||||
setEnv("_NIX_TEST_NO_SANDBOX", "1");
|
||||
#endif
|
||||
|
||||
// For pipe operator tests in trivial.cc
|
||||
experimentalFeatureSettings.set("experimental-features", "pipe-operators");
|
||||
|
||||
@@ -423,55 +423,6 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_return_thunk)
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badReturnThunk"));
|
||||
}
|
||||
|
||||
static void primop_with_nix_err_key(
|
||||
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret)
|
||||
{
|
||||
nix_set_err_msg(context, NIX_ERR_KEY, "Test error from primop");
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_primop_nix_err_key_conversion)
|
||||
{
|
||||
// Test that NIX_ERR_KEY from a custom primop gets converted to a generic EvalError
|
||||
//
|
||||
// RATIONALE: NIX_ERR_KEY must not be propagated from custom primops because it would
|
||||
// create semantic confusion. NIX_ERR_KEY indicates missing keys/indices in C API functions
|
||||
// (like nix_get_attr_byname, nix_get_list_byidx). If custom primops could return NIX_ERR_KEY,
|
||||
// an evaluation error would be indistinguishable from an actual missing attribute.
|
||||
//
|
||||
// For example, if nix_get_attr_byname returned NIX_ERR_KEY when the attribute is present
|
||||
// but the value evaluation fails, callers expecting NIX_ERR_KEY to mean "missing attribute"
|
||||
// would incorrectly handle evaluation failures as missing attributes. In places where
|
||||
// missing attributes are tolerated (like optional attributes), this would cause the
|
||||
// program to continue after swallowing the error, leading to silent failures.
|
||||
PrimOp * primop = nix_alloc_primop(
|
||||
ctx, primop_with_nix_err_key, 1, "testErrorPrimop", nullptr, "a test primop that sets NIX_ERR_KEY", nullptr);
|
||||
assert_ctx_ok();
|
||||
nix_value * primopValue = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_primop(ctx, primopValue, primop);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_value * arg = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_int(ctx, arg, 42);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_value * result = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_value_call(ctx, state, primopValue, arg, result);
|
||||
|
||||
// Verify that NIX_ERR_KEY gets converted to NIX_ERR_NIX_ERROR (generic evaluation error)
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("Error from custom function"));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("Test error from primop"));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("testErrorPrimop"));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, primopValue);
|
||||
nix_gc_decref(ctx, arg);
|
||||
nix_gc_decref(ctx, result);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
|
||||
{
|
||||
nix_value * n = nix_alloc_value(ctx, state);
|
||||
@@ -487,30 +438,104 @@ TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)
|
||||
ASSERT_EQ(3, rInt);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_attrset_update)
|
||||
// The following is a test case for retryable thunks.
|
||||
// This is a requirement for the current way in which NixOps4 evaluates its deployment expressions.
|
||||
// An alternative strategy could be implemented, but unwinding the stack may be a more efficient way to deal with many
|
||||
// suspensions/resumptions, compared to e.g. using a thread or coroutine stack for each suspended dependency. This test
|
||||
// models the essential bits of a deployment tool that uses such a strategy.
|
||||
|
||||
// State for the retryable primop - simulates deployment resource availability
|
||||
struct DeploymentResourceState
|
||||
{
|
||||
nix_expr_eval_from_string(ctx, state, "{ a = 0; b = 2; } // { a = 1; b = 3; } // { a = 2; }", ".", value);
|
||||
assert_ctx_ok();
|
||||
bool vm_created = false;
|
||||
};
|
||||
|
||||
ASSERT_EQ(nix_get_attrs_size(ctx, value), 2);
|
||||
assert_ctx_ok();
|
||||
std::array<std::pair<std::string_view, nix_value *>, 2> values;
|
||||
for (unsigned int i = 0; i < 2; ++i) {
|
||||
const char * name;
|
||||
values[i].second = nix_get_attr_byidx(ctx, value, state, i, &name);
|
||||
assert_ctx_ok();
|
||||
values[i].first = name;
|
||||
static void primop_load_resource_input(
|
||||
void * user_data, nix_c_context * context, EvalState * state, nix_value ** args, nix_value * ret)
|
||||
{
|
||||
assert(context);
|
||||
assert(state);
|
||||
auto * resource_state = static_cast<DeploymentResourceState *>(user_data);
|
||||
|
||||
// Get the resource input name argument
|
||||
std::string input_name;
|
||||
if (nix_get_string(context, args[0], OBSERVE_STRING(input_name)) != NIX_OK)
|
||||
return;
|
||||
|
||||
// Only handle "vm_id" input - throw for anything else
|
||||
if (input_name != "vm_id") {
|
||||
std::string error_msg = "unknown resource input: " + input_name;
|
||||
nix_set_err_msg(context, NIX_ERR_NIX_ERROR, error_msg.c_str());
|
||||
return;
|
||||
}
|
||||
std::sort(values.begin(), values.end(), [](const auto & lhs, const auto & rhs) { return lhs.first < rhs.first; });
|
||||
|
||||
nix_value * a = values[0].second;
|
||||
ASSERT_EQ("a", values[0].first);
|
||||
ASSERT_EQ(nix_get_int(ctx, a), 2);
|
||||
if (resource_state->vm_created) {
|
||||
// VM has been created, return the ID
|
||||
nix_init_string(context, ret, "vm-12345");
|
||||
} else {
|
||||
// VM not created yet, fail with dependency error
|
||||
nix_set_err_msg(context, NIX_ERR_RECOVERABLE, "VM not yet created");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_thunk_re_evaluation_after_deployment)
|
||||
{
|
||||
// This test demonstrates NixOps4's requirement: a thunk calling a primop should be
|
||||
// re-evaluable when deployment resources become available that were not available initially.
|
||||
|
||||
DeploymentResourceState resource_state;
|
||||
|
||||
PrimOp * primop = nix_alloc_primop(
|
||||
ctx,
|
||||
primop_load_resource_input,
|
||||
1,
|
||||
"loadResourceInput",
|
||||
nullptr,
|
||||
"load a deployment resource input",
|
||||
&resource_state);
|
||||
assert_ctx_ok();
|
||||
nix_value * b = values[1].second;
|
||||
ASSERT_EQ("b", values[1].first);
|
||||
ASSERT_EQ(nix_get_int(ctx, b), 3);
|
||||
|
||||
nix_value * primopValue = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_primop(ctx, primopValue, primop);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_value * inputName = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_string(ctx, inputName, "vm_id");
|
||||
assert_ctx_ok();
|
||||
|
||||
// Create a single thunk by using nix_init_apply instead of nix_value_call
|
||||
// This creates a lazy application that can be forced multiple times
|
||||
nix_value * thunk = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
nix_init_apply(ctx, thunk, primopValue, inputName);
|
||||
assert_ctx_ok();
|
||||
|
||||
// First force: VM not created yet, should fail
|
||||
nix_value_force(ctx, state, thunk);
|
||||
ASSERT_EQ(NIX_ERR_NIX_ERROR, nix_err_code(ctx));
|
||||
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("VM not yet created"));
|
||||
|
||||
// Clear the error context for the next attempt
|
||||
nix_c_context_free(ctx);
|
||||
ctx = nix_c_context_create();
|
||||
|
||||
// Simulate deployment process: VM gets created
|
||||
resource_state.vm_created = true;
|
||||
|
||||
// Second force of the SAME thunk: this is where the "failed" value issue appears
|
||||
// With failed value caching, this should fail because the thunk is marked as permanently failed
|
||||
// Without failed value caching (or with retryable failures), this should succeed
|
||||
nix_value_force(ctx, state, thunk);
|
||||
|
||||
// If we get here without error, the thunk was successfully re-evaluated
|
||||
assert_ctx_ok();
|
||||
|
||||
std::string result;
|
||||
nix_get_string(ctx, thunk, OBSERVE_STRING(result));
|
||||
assert_ctx_ok();
|
||||
ASSERT_STREQ("vm-12345", result.c_str());
|
||||
}
|
||||
|
||||
} // namespace nixC
|
||||
|
||||
@@ -162,114 +162,6 @@ TEST_F(nix_api_expr_test, nix_build_and_init_list)
|
||||
nix_gc_decref(ctx, intValue);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_get_list_byidx_large_indices)
|
||||
{
|
||||
// Create a small list to test extremely large out-of-bounds access
|
||||
ListBuilder * builder = nix_make_list_builder(ctx, state, 2);
|
||||
nix_value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
nix_list_builder_insert(ctx, builder, 0, intValue);
|
||||
nix_list_builder_insert(ctx, builder, 1, intValue);
|
||||
nix_make_list(ctx, builder, value);
|
||||
nix_list_builder_free(builder);
|
||||
|
||||
// Test extremely large indices that would definitely crash without bounds checking
|
||||
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 1000000));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, UINT_MAX / 2));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, UINT_MAX / 2 + 1000000));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, intValue);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_get_list_byidx_lazy)
|
||||
{
|
||||
// Create a list with a throwing lazy element, an already-evaluated int, and a lazy function call
|
||||
|
||||
// 1. Throwing lazy element - create a function application thunk that will throw when forced
|
||||
nix_value * throwingFn = nix_alloc_value(ctx, state);
|
||||
nix_value * throwingValue = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(
|
||||
ctx,
|
||||
state,
|
||||
R"(
|
||||
_: throw "This should not be evaluated by the lazy accessor"
|
||||
)",
|
||||
"<test>",
|
||||
throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 2. Already evaluated int (not lazy)
|
||||
nix_value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 3. Lazy function application that would compute increment 5 = 6
|
||||
nix_value * lazyApply = nix_alloc_value(ctx, state);
|
||||
nix_value * incrementFn = nix_alloc_value(ctx, state);
|
||||
nix_value * argFive = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
|
||||
assert_ctx_ok();
|
||||
nix_init_int(ctx, argFive, 5);
|
||||
|
||||
// Create a lazy application: (x: x + 1) 5
|
||||
nix_init_apply(ctx, lazyApply, incrementFn, argFive);
|
||||
assert_ctx_ok();
|
||||
|
||||
ListBuilder * builder = nix_make_list_builder(ctx, state, 3);
|
||||
nix_list_builder_insert(ctx, builder, 0, throwingValue);
|
||||
nix_list_builder_insert(ctx, builder, 1, intValue);
|
||||
nix_list_builder_insert(ctx, builder, 2, lazyApply);
|
||||
nix_make_list(ctx, builder, value);
|
||||
nix_list_builder_free(builder);
|
||||
|
||||
// Test 1: Lazy accessor should return the throwing element without forcing evaluation
|
||||
nix_value * lazyThrowingElement = nix_get_list_byidx_lazy(ctx, value, state, 0);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lazyThrowingElement);
|
||||
|
||||
// Verify the element is still lazy by checking that forcing it throws
|
||||
nix_value_force(ctx, state, lazyThrowingElement);
|
||||
assert_ctx_err();
|
||||
ASSERT_THAT(
|
||||
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
|
||||
|
||||
// Test 2: Lazy accessor should return the already-evaluated int
|
||||
nix_value * intElement = nix_get_list_byidx_lazy(ctx, value, state, 1);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, intElement);
|
||||
ASSERT_EQ(42, nix_get_int(ctx, intElement));
|
||||
|
||||
// Test 3: Lazy accessor should return the lazy function application without forcing
|
||||
nix_value * lazyFunctionElement = nix_get_list_byidx_lazy(ctx, value, state, 2);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lazyFunctionElement);
|
||||
|
||||
// Force the lazy function application - should compute 5 + 1 = 6
|
||||
nix_value_force(ctx, state, lazyFunctionElement);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(6, nix_get_int(ctx, lazyFunctionElement));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, throwingFn);
|
||||
nix_gc_decref(ctx, throwingValue);
|
||||
nix_gc_decref(ctx, intValue);
|
||||
nix_gc_decref(ctx, lazyApply);
|
||||
nix_gc_decref(ctx, incrementFn);
|
||||
nix_gc_decref(ctx, argFive);
|
||||
nix_gc_decref(ctx, lazyThrowingElement);
|
||||
nix_gc_decref(ctx, intElement);
|
||||
nix_gc_decref(ctx, lazyFunctionElement);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_build_and_init_attr_invalid)
|
||||
{
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byname(ctx, nullptr, state, 0));
|
||||
@@ -352,225 +244,6 @@ TEST_F(nix_api_expr_test, nix_build_and_init_attr)
|
||||
free(out_name);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_get_attr_byidx_large_indices)
|
||||
{
|
||||
// Create a small attribute set to test extremely large out-of-bounds access
|
||||
const char ** out_name = (const char **) malloc(sizeof(char *));
|
||||
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 2);
|
||||
nix_value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
nix_bindings_builder_insert(ctx, builder, "test", intValue);
|
||||
nix_make_attrs(ctx, value, builder);
|
||||
nix_bindings_builder_free(builder);
|
||||
|
||||
// Test extremely large indices that would definitely crash without bounds checking
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, 1000000, out_name));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, UINT_MAX / 2, out_name));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, value, state, UINT_MAX / 2 + 1000000, out_name));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
|
||||
// Test nix_get_attr_name_byidx with large indices too
|
||||
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, 1000000));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, UINT_MAX / 2));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, value, state, UINT_MAX / 2 + 1000000));
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, intValue);
|
||||
free(out_name);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_get_attr_byname_lazy)
|
||||
{
|
||||
// Create an attribute set with a throwing lazy attribute, an already-evaluated int, and a lazy function call
|
||||
|
||||
// 1. Throwing lazy element - create a function application thunk that will throw when forced
|
||||
nix_value * throwingFn = nix_alloc_value(ctx, state);
|
||||
nix_value * throwingValue = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(
|
||||
ctx,
|
||||
state,
|
||||
R"(
|
||||
_: throw "This should not be evaluated by the lazy accessor"
|
||||
)",
|
||||
"<test>",
|
||||
throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 2. Already evaluated int (not lazy)
|
||||
nix_value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 3. Lazy function application that would compute increment 7 = 8
|
||||
nix_value * lazyApply = nix_alloc_value(ctx, state);
|
||||
nix_value * incrementFn = nix_alloc_value(ctx, state);
|
||||
nix_value * argSeven = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
|
||||
assert_ctx_ok();
|
||||
nix_init_int(ctx, argSeven, 7);
|
||||
|
||||
// Create a lazy application: (x: x + 1) 7
|
||||
nix_init_apply(ctx, lazyApply, incrementFn, argSeven);
|
||||
assert_ctx_ok();
|
||||
|
||||
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 3);
|
||||
nix_bindings_builder_insert(ctx, builder, "throwing", throwingValue);
|
||||
nix_bindings_builder_insert(ctx, builder, "normal", intValue);
|
||||
nix_bindings_builder_insert(ctx, builder, "lazy", lazyApply);
|
||||
nix_make_attrs(ctx, value, builder);
|
||||
nix_bindings_builder_free(builder);
|
||||
|
||||
// Test 1: Lazy accessor should return the throwing attribute without forcing evaluation
|
||||
nix_value * lazyThrowingAttr = nix_get_attr_byname_lazy(ctx, value, state, "throwing");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lazyThrowingAttr);
|
||||
|
||||
// Verify the attribute is still lazy by checking that forcing it throws
|
||||
nix_value_force(ctx, state, lazyThrowingAttr);
|
||||
assert_ctx_err();
|
||||
ASSERT_THAT(
|
||||
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
|
||||
|
||||
// Test 2: Lazy accessor should return the already-evaluated int
|
||||
nix_value * intAttr = nix_get_attr_byname_lazy(ctx, value, state, "normal");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, intAttr);
|
||||
ASSERT_EQ(42, nix_get_int(ctx, intAttr));
|
||||
|
||||
// Test 3: Lazy accessor should return the lazy function application without forcing
|
||||
nix_value * lazyFunctionAttr = nix_get_attr_byname_lazy(ctx, value, state, "lazy");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lazyFunctionAttr);
|
||||
|
||||
// Force the lazy function application - should compute 7 + 1 = 8
|
||||
nix_value_force(ctx, state, lazyFunctionAttr);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(8, nix_get_int(ctx, lazyFunctionAttr));
|
||||
|
||||
// Test 4: Missing attribute should return NULL with NIX_ERR_KEY
|
||||
nix_value * missingAttr = nix_get_attr_byname_lazy(ctx, value, state, "nonexistent");
|
||||
ASSERT_EQ(nullptr, missingAttr);
|
||||
ASSERT_EQ(NIX_ERR_KEY, nix_err_code(ctx));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, throwingFn);
|
||||
nix_gc_decref(ctx, throwingValue);
|
||||
nix_gc_decref(ctx, intValue);
|
||||
nix_gc_decref(ctx, lazyApply);
|
||||
nix_gc_decref(ctx, incrementFn);
|
||||
nix_gc_decref(ctx, argSeven);
|
||||
nix_gc_decref(ctx, lazyThrowingAttr);
|
||||
nix_gc_decref(ctx, intAttr);
|
||||
nix_gc_decref(ctx, lazyFunctionAttr);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_get_attr_byidx_lazy)
|
||||
{
|
||||
// Create an attribute set with a throwing lazy attribute, an already-evaluated int, and a lazy function call
|
||||
|
||||
// 1. Throwing lazy element - create a function application thunk that will throw when forced
|
||||
nix_value * throwingFn = nix_alloc_value(ctx, state);
|
||||
nix_value * throwingValue = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(
|
||||
ctx,
|
||||
state,
|
||||
R"(
|
||||
_: throw "This should not be evaluated by the lazy accessor"
|
||||
)",
|
||||
"<test>",
|
||||
throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_init_apply(ctx, throwingValue, throwingFn, throwingFn);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 2. Already evaluated int (not lazy)
|
||||
nix_value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 99);
|
||||
assert_ctx_ok();
|
||||
|
||||
// 3. Lazy function application that would compute increment 10 = 11
|
||||
nix_value * lazyApply = nix_alloc_value(ctx, state);
|
||||
nix_value * incrementFn = nix_alloc_value(ctx, state);
|
||||
nix_value * argTen = nix_alloc_value(ctx, state);
|
||||
|
||||
nix_expr_eval_from_string(ctx, state, "x: x + 1", "<test>", incrementFn);
|
||||
assert_ctx_ok();
|
||||
nix_init_int(ctx, argTen, 10);
|
||||
|
||||
// Create a lazy application: (x: x + 1) 10
|
||||
nix_init_apply(ctx, lazyApply, incrementFn, argTen);
|
||||
assert_ctx_ok();
|
||||
|
||||
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, 3);
|
||||
nix_bindings_builder_insert(ctx, builder, "a_throwing", throwingValue);
|
||||
nix_bindings_builder_insert(ctx, builder, "b_normal", intValue);
|
||||
nix_bindings_builder_insert(ctx, builder, "c_lazy", lazyApply);
|
||||
nix_make_attrs(ctx, value, builder);
|
||||
nix_bindings_builder_free(builder);
|
||||
|
||||
// Proper usage: first get the size and gather all attributes into a map
|
||||
unsigned int attrCount = nix_get_attrs_size(ctx, value);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(3u, attrCount);
|
||||
|
||||
// Gather all attributes into a map (proper contract usage)
|
||||
std::map<std::string, nix_value *> attrMap;
|
||||
const char * name;
|
||||
|
||||
for (unsigned int i = 0; i < attrCount; i++) {
|
||||
nix_value * attr = nix_get_attr_byidx_lazy(ctx, value, state, i, &name);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, attr);
|
||||
attrMap[std::string(name)] = attr;
|
||||
}
|
||||
|
||||
// Now test the gathered attributes
|
||||
ASSERT_EQ(3u, attrMap.size());
|
||||
ASSERT_TRUE(attrMap.count("a_throwing"));
|
||||
ASSERT_TRUE(attrMap.count("b_normal"));
|
||||
ASSERT_TRUE(attrMap.count("c_lazy"));
|
||||
|
||||
// Test 1: Throwing attribute should be lazy
|
||||
nix_value * throwingAttr = attrMap["a_throwing"];
|
||||
nix_value_force(ctx, state, throwingAttr);
|
||||
assert_ctx_err();
|
||||
ASSERT_THAT(
|
||||
nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("This should not be evaluated by the lazy accessor"));
|
||||
|
||||
// Test 2: Normal attribute should be already evaluated
|
||||
nix_value * normalAttr = attrMap["b_normal"];
|
||||
ASSERT_EQ(99, nix_get_int(ctx, normalAttr));
|
||||
|
||||
// Test 3: Lazy function should compute when forced
|
||||
nix_value * lazyAttr = attrMap["c_lazy"];
|
||||
nix_value_force(ctx, state, lazyAttr);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(11, nix_get_int(ctx, lazyAttr));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, throwingFn);
|
||||
nix_gc_decref(ctx, throwingValue);
|
||||
nix_gc_decref(ctx, intValue);
|
||||
nix_gc_decref(ctx, lazyApply);
|
||||
nix_gc_decref(ctx, incrementFn);
|
||||
nix_gc_decref(ctx, argTen);
|
||||
for (auto & pair : attrMap) {
|
||||
nix_gc_decref(ctx, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_init)
|
||||
{
|
||||
// Setup
|
||||
|
||||
@@ -195,18 +195,18 @@ TEST_F(PrimOpTest, unsafeGetAttrPos)
|
||||
auto v = eval(expr);
|
||||
ASSERT_THAT(v, IsAttrsOfSize(3));
|
||||
|
||||
auto file = v.attrs()->get(createSymbol("file"));
|
||||
auto file = v.attrs()->find(createSymbol("file"));
|
||||
ASSERT_NE(file, nullptr);
|
||||
ASSERT_THAT(*file->value, IsString());
|
||||
auto s = baseNameOf(file->value->string_view());
|
||||
ASSERT_EQ(s, "foo.nix");
|
||||
|
||||
auto line = v.attrs()->get(createSymbol("line"));
|
||||
auto line = v.attrs()->find(createSymbol("line"));
|
||||
ASSERT_NE(line, nullptr);
|
||||
state.forceValue(*line->value, noPos);
|
||||
ASSERT_THAT(*line->value, IsIntEq(4));
|
||||
|
||||
auto column = v.attrs()->get(createSymbol("column"));
|
||||
auto column = v.attrs()->find(createSymbol("column"));
|
||||
ASSERT_NE(column, nullptr);
|
||||
state.forceValue(*column->value, noPos);
|
||||
ASSERT_THAT(*column->value, IsIntEq(3));
|
||||
@@ -246,7 +246,7 @@ TEST_F(PrimOpTest, removeAttrsRetains)
|
||||
{
|
||||
auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
ASSERT_NE(v.attrs()->get(createSymbol("y")), nullptr);
|
||||
ASSERT_NE(v.attrs()->find(createSymbol("y")), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(PrimOpTest, listToAttrsEmptyList)
|
||||
@@ -266,7 +266,7 @@ TEST_F(PrimOpTest, listToAttrs)
|
||||
{
|
||||
auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto key = v.attrs()->get(createSymbol("key"));
|
||||
auto key = v.attrs()->find(createSymbol("key"));
|
||||
ASSERT_NE(key, nullptr);
|
||||
ASSERT_THAT(*key->value, IsIntEq(123));
|
||||
}
|
||||
@@ -275,7 +275,7 @@ TEST_F(PrimOpTest, intersectAttrs)
|
||||
{
|
||||
auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
auto b = v.attrs()->find(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(3));
|
||||
}
|
||||
@@ -293,11 +293,11 @@ TEST_F(PrimOpTest, functionArgs)
|
||||
auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||
|
||||
auto x = v.attrs()->get(createSymbol("x"));
|
||||
auto x = v.attrs()->find(createSymbol("x"));
|
||||
ASSERT_NE(x, nullptr);
|
||||
ASSERT_THAT(*x->value, IsFalse());
|
||||
|
||||
auto y = v.attrs()->get(createSymbol("y"));
|
||||
auto y = v.attrs()->find(createSymbol("y"));
|
||||
ASSERT_NE(y, nullptr);
|
||||
ASSERT_THAT(*y->value, IsTrue());
|
||||
}
|
||||
@@ -307,13 +307,13 @@ TEST_F(PrimOpTest, mapAttrs)
|
||||
auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
auto a = v.attrs()->find(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
ASSERT_THAT(*a->value, IsThunk());
|
||||
state.forceValue(*a->value, noPos);
|
||||
ASSERT_THAT(*a->value, IsIntEq(10));
|
||||
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
auto b = v.attrs()->find(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsThunk());
|
||||
state.forceValue(*b->value, noPos);
|
||||
@@ -642,7 +642,7 @@ class ToStringPrimOpTest : public PrimOpTest,
|
||||
|
||||
TEST_P(ToStringPrimOpTest, toString)
|
||||
{
|
||||
const auto & [input, output] = GetParam();
|
||||
const auto [input, output] = GetParam();
|
||||
auto v = eval(input);
|
||||
ASSERT_THAT(v, IsStringEq(output));
|
||||
}
|
||||
@@ -798,7 +798,7 @@ class CompareVersionsPrimOpTest : public PrimOpTest,
|
||||
|
||||
TEST_P(CompareVersionsPrimOpTest, compareVersions)
|
||||
{
|
||||
const auto & [expression, expectation] = GetParam();
|
||||
auto [expression, expectation] = GetParam();
|
||||
auto v = eval(expression);
|
||||
ASSERT_THAT(v, IsIntEq(expectation));
|
||||
}
|
||||
@@ -834,16 +834,16 @@ class ParseDrvNamePrimOpTest
|
||||
|
||||
TEST_P(ParseDrvNamePrimOpTest, parseDrvName)
|
||||
{
|
||||
const auto & [input, expectedName, expectedVersion] = GetParam();
|
||||
auto [input, expectedName, expectedVersion] = GetParam();
|
||||
const auto expr = fmt("builtins.parseDrvName \"%1%\"", input);
|
||||
auto v = eval(expr);
|
||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||
|
||||
auto name = v.attrs()->get(createSymbol("name"));
|
||||
auto name = v.attrs()->find(createSymbol("name"));
|
||||
ASSERT_TRUE(name);
|
||||
ASSERT_THAT(*name->value, IsStringEq(expectedName));
|
||||
|
||||
auto version = v.attrs()->get(createSymbol("version"));
|
||||
auto version = v.attrs()->find(createSymbol("version"));
|
||||
ASSERT_TRUE(version);
|
||||
ASSERT_THAT(*version->value, IsStringEq(expectedVersion));
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ TEST_F(TrivialExpressionTest, updateAttrs)
|
||||
{
|
||||
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(2));
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
auto a = v.attrs()->find(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
ASSERT_THAT(*a->value, IsIntEq(3));
|
||||
|
||||
auto b = v.attrs()->get(createSymbol("b"));
|
||||
auto b = v.attrs()->find(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(2));
|
||||
}
|
||||
@@ -176,7 +176,7 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
|
||||
auto v = eval(expr);
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
|
||||
auto a = v.attrs()->get(createSymbol("a"));
|
||||
auto a = v.attrs()->find(createSymbol("a"));
|
||||
ASSERT_NE(a, nullptr);
|
||||
|
||||
ASSERT_THAT(*a->value, IsThunk());
|
||||
@@ -184,11 +184,11 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
|
||||
|
||||
ASSERT_THAT(*a->value, IsAttrsOfSize(2));
|
||||
|
||||
auto b = a->value->attrs()->get(createSymbol("b"));
|
||||
auto b = a->value->attrs()->find(createSymbol("b"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||
|
||||
auto c = a->value->attrs()->get(createSymbol("c"));
|
||||
auto c = a->value->attrs()->find(createSymbol("c"));
|
||||
ASSERT_NE(c, nullptr);
|
||||
ASSERT_THAT(*c->value, IsIntEq(2));
|
||||
}
|
||||
@@ -330,7 +330,7 @@ TEST_F(TrivialExpressionTest, bindOr)
|
||||
{
|
||||
auto v = eval("{ or = 1; }");
|
||||
ASSERT_THAT(v, IsAttrsOfSize(1));
|
||||
auto b = v.attrs()->get(createSymbol("or"));
|
||||
auto b = v.attrs()->find(createSymbol("or"));
|
||||
ASSERT_NE(b, nullptr);
|
||||
ASSERT_THAT(*b->value, IsIntEq(1));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace testing;
|
||||
struct ValuePrintingTests : LibExprTest
|
||||
{
|
||||
template<class... A>
|
||||
void test(Value & v, std::string_view expected, A... args)
|
||||
void test(Value v, std::string_view expected, A... args)
|
||||
{
|
||||
std::stringstream out;
|
||||
v.print(state, out, args...);
|
||||
@@ -625,11 +625,10 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsElided)
|
||||
vThree.mkInt(3);
|
||||
|
||||
builder.insert(state.symbols.create("three"), &vThree);
|
||||
Value vAttrs2;
|
||||
vAttrs2.mkAttrs(builder.finish());
|
||||
vAttrs.mkAttrs(builder.finish());
|
||||
|
||||
test(
|
||||
vAttrs2,
|
||||
vAttrs,
|
||||
"{ one = " ANSI_CYAN "1" ANSI_NORMAL "; " ANSI_FAINT "«2 attributes elided»" ANSI_NORMAL " }",
|
||||
PrintOptions{.ansiColors = true, .maxAttrs = 1});
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user