Get started¶
This page walks one full session against a local mock server: prepare a version directory, publish it, name it, consume it, break the transfer and resume it.
No Nexus installation is needed: the repository ships mock-nexus, a mock Nexus raw server.
Prerequisites¶
- Rust 1.88+ through
rustup, the only hard requirement. justis optional and only wraps the recipes below.
Install¶
It prints the version you installed.
Start a throwaway Nexus¶
The mock-nexus binary serves one failure scenario at a time.
atomic is the correct-server scenario: PUT/GET/HEAD, Range: bytes=N- resume, 404 on unknown paths.
From a repository checkout, cargo run -p mock-nexus -- atomic --port 8080 runs the same server without the install step.
Everything below talks to that process.
In a real deployment the URL is your repository, for example https://nexus.example.com/repository/raw-main/, and credentials travel per call (see the CLI reference).
Prepare a version directory¶
Any directory works: every relative path under it becomes an artifact name.
dist/1.4.0/
├── app-1.4.0.zip
├── bom/
│ └── linux-x86_64.json
├── manifest.json # (1)!
└── pinned.xml
- An ordinary uploaded artifact.
Nothing in
nxrreads it:downneeds repeatable--nameor--ls, a refusal you will trigger later in this tour.
- Source directory first, destination URL second. No config file, no login step: the whole instruction is on one line.
$ nxr up dist/1.4.0/ http://127.0.0.1:8080/1.4.0/ --claim-first manifest.json
plan: 4 to upload, 0 to download, 0 up to date
↑ manifest.json ok
↑ bom/linux-x86_64.json ok
↑ pinned.xml ok
↑ app-1.4.0.zip ok
uploaded 4, downloaded 0, skipped 0
With --claim-first that name uploads first, alone: the file is an ordinary artifact, and claim-first only fixes its order.
The remaining ok lines print in completion order, so your ordering may differ.
No marker step appears anywhere because up generated every <name>.sha256 from the bytes before uploading.
The markers are ordinary sha256sum -c lines, and up leaves a copy next to your files:
$ cat dist/1.4.0/app-1.4.0.zip.sha256
405e28e8bcf3d4a6a1098029dacc54c7ba14d9b08ecf2b3e15c377c0b896636a app-1.4.0.zip
Run the same command again and nothing transfers, because the server already holds byte-identical copies with equal markers:
$ nxr up dist/1.4.0/ http://127.0.0.1:8080/1.4.0/
plan: 0 to upload, 0 to download, 4 up to date
○ app-1.4.0.zip skipped
○ bom/linux-x86_64.json skipped
○ manifest.json skipped
○ pinned.xml skipped
uploaded 0, downloaded 0, skipped 4
A publishing job can be retried blindly: finished names are skipped, missing ones transfer, and a name whose server marker diverges from your bytes stops the run with exit 1.
Name the version¶
A channel is a token file at any URL.
latest is just the most common name.
--if-forward compares tokens in dotted-numeric version order, so an older token never replaces a newer one:
$ nxr channel set http://127.0.0.1:8080/latest 1.4.0 --if-forward
channel: set http://127.0.0.1:8080/latest → 1.4.0
$ nxr channel set http://127.0.0.1:8080/latest 1.3.0 --if-forward
channel: kept http://127.0.0.1:8080/latest at 1.4.0 (forward-only)
$ nxr channel get http://127.0.0.1:8080/latest
1.4.0
Consume the version¶
Point down at the version URL and name what you want.
It fetches exactly the named artifacts, hashes each stream on the fly, checks the digest against the server marker, and only then renames the file into place:
$ nxr down http://127.0.0.1:8080/1.4.0/ vendor/app/ --name app-1.4.0.zip --name pinned.xml --name bom/linux-x86_64.json
plan: 0 to upload, 3 to download, 0 up to date
↓ pinned.xml ok
↓ bom/linux-x86_64.json ok
↓ app-1.4.0.zip ok
uploaded 0, downloaded 3, skipped 0
Each artifact arrives with its own <name>.sha256 sibling, so the result verifies offline:
Break it on purpose¶
Call down with neither --name nor --ls and it refuses to guess instead of inventing a name list:
$ nxr down http://127.0.0.1:8080/1.3.0/ vendor/old/
error: cannot enumerate: http://127.0.0.1:8080/1.3.0/: no --name/--names-from/--ls given
hint: repeat --name, use --names-from FILE, or use --ls when the server has the search API
Every failure prints this way: the kind, the facts, and a hint: line naming the next check.
When it breaks catalogues them all.
Now interrupt a transfer mid-flight.
Run a second mock in its slow scenario, which writes response bodies in small delayed chunks, and kill down three seconds in (timeout stands in for Ctrl-C):
$ mock-nexus slow --chunk-delay-ms 300 --chunk-size 2048 --port 8095 &
listening http://127.0.0.1:8095
$ printf 'app-1.4.0.zip\npinned.xml\nbom/linux-x86_64.json\n' > names.txt
$ nxr up dist/1.4.0/ http://127.0.0.1:8095/1.4.0/ >/dev/null
$ timeout 3 nxr down http://127.0.0.1:8095/1.4.0/ vendor/resume/ --names-from names.txt
plan: 0 to upload, 3 to download, 0 up to date
↓ pinned.xml ok
↓ bom/linux-x86_64.json ok
$ echo $?
124
$ ls -A vendor/resume/
.nxr-part-a83c001a1e7ecaa7bc6bca25eaec0a83
bom
pinned.xml
pinned.xml.sha256
Two names finished, and the third died as a hidden part file (.nxr-part-<hash>).
A part file never reaches its final path, so the directory holds no half-written artifact.
Repeat the same command: resume is the default, so no flag is needed.
Finished names are skipped, and the part file continues through a Range: bytes=N- request:
$ nxr down http://127.0.0.1:8095/1.4.0/ vendor/resume/ --names-from names.txt
plan: 0 to upload, 1 to download, 2 up to date
○ bom/linux-x86_64.json skipped
○ pinned.xml skipped
↓ app-1.4.0.zip ok
uploaded 0, downloaded 1, skipped 2
The part file is gone, app-1.4.0.zip is complete, and verify passes:
Next steps¶
- For producers, publish a version shows markers, refusals, channels and a nightly pattern against a real server.
- For consumers, consume artifacts covers enumeration sources, subsets and offline verification.
- For pipelines, use in CI shows NDJSON events, exit codes and masked credentials.
- Every flag of every command: CLI reference.