Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[net]
retry = 2

[http]
timeout = 30
68 changes: 54 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ concurrency:

jobs:
verify:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

Expand All @@ -32,7 +32,7 @@ jobs:
toolchain: "1.97.0"
components: rustfmt, clippy

- name: Verify Zed and Cargo metadata agree
- name: Verify Cargo and Zed ownership boundaries
shell: bash
run: |
set -euo pipefail
Expand All @@ -41,24 +41,60 @@ jobs:
from pathlib import Path

with Path("Cargo.toml").open("rb") as handle:
cargo = tomllib.load(handle)["package"]
cargo = tomllib.load(handle)
with Path(".zpkg.toml").open("rb") as handle:
zed = tomllib.load(handle)["package"]
zed = tomllib.load(handle)

assert cargo["name"] == zed["name"]
assert cargo["version"] == zed["version"]
assert cargo["description"] == zed["description"]
assert cargo["license"] == zed["license"]
assert cargo["repository"] == zed["repository"]["url"]
assert cargo["readme"] == "README.md"
assert zed["org"] == "zed-pkg-test"
cargo_package = cargo["package"]
zed_package = zed["package"]
assert cargo_package["name"] == zed_package["name"]
assert cargo_package["version"] == zed_package["version"] == "1.0.1"
assert cargo_package["description"] == zed_package["description"]
assert cargo_package["license"] == zed_package["license"]
assert cargo_package["repository"] == zed["package"]["repository"]["url"]
assert cargo_package["readme"] == "README.md"
assert cargo_package["rust-version"] == "1.88"
assert zed_package["org"] == "zed-pkg-test"

# crates.io dependencies and Cargo features stay native to Cargo.
assert cargo["dependencies"] == {"itoa": "=1.0.18"}
assert cargo["features"] == {"default": [], "uppercase": []}
assert "dependencies" not in zed
assert zed["publish"]["exclude"] == ["Cargo.lock"]
PY

- name: Format, lint, and test
- name: Format, lint, and test both feature sets
shell: bash
run: |
set -euo pipefail
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets
cargo test --all-targets --all-features

- name: Verify Cargo resolves registry provenance independently
shell: bash
run: |
set -euo pipefail
cargo metadata --locked --format-version 1 > "$RUNNER_TEMP/cargo-metadata.json"
python3 - "$RUNNER_TEMP/cargo-metadata.json" <<'PY'
import json
import sys
from pathlib import Path

metadata = json.loads(Path(sys.argv[1]).read_text())
packages = {package["name"]: package for package in metadata["packages"]}
assert packages["rust-lib"]["source"] is None
assert packages["rust-lib"]["version"] == "1.0.1"
assert packages["itoa"]["version"] == "1.0.18"
assert packages["itoa"]["source"].startswith("registry+")
resolve = metadata["resolve"]
assert resolve is not None
root = next(node for node in resolve["nodes"] if node["id"] == resolve["root"])
assert {dep["name"] for dep in root["deps"]} == {"itoa"}
PY
test ! -e .zpkg.lock

- name: Audit Cargo package contents
shell: bash
Expand All @@ -72,13 +108,17 @@ jobs:
cat "$RUNNER_TEMP/package-files.txt"
grep -Fxq Cargo.toml "$RUNNER_TEMP/package-files.txt"
grep -Fxq README.md "$RUNNER_TEMP/package-files.txt"
grep -Fxq scripts/zed-smoke.sh "$RUNNER_TEMP/package-files.txt"
grep -Fxq src/lib.rs "$RUNNER_TEMP/package-files.txt"
grep -Fxq Cargo.lock "$RUNNER_TEMP/package-files.txt"
if grep -Eq '(^|/)(target|\.zed)/' "$RUNNER_TEMP/package-files.txt"; then
if grep -Eq '(^|/)(target|\.zed|\.vendor)/' "$RUNNER_TEMP/package-files.txt"; then
echo "Cargo package contains build or local Zed state" >&2
exit 1
fi
cargo package --allow-dirty
test ! -e .zpkg.lock
rm -f Cargo.lock
test -z "$(git status --porcelain --untracked-files=all)"

- name: Upload package-content diagnostics
if: ${{ always() }}
Expand Down
6 changes: 5 additions & 1 deletion .zpkg.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
[package]
org = "zed-pkg-test"
name = "rust-lib"
version = "1.0.0"
version = "1.0.1"
description = "A Rust crate sourced via zed (complements cargo/crates.io)."
license = "MIT"

[package.repository]
vcs = "git"
url = "https://github.com/zed-pkg-test/rust-lib"

# Cargo-native dependencies remain in Cargo.toml/Cargo.lock. A Zed
# [dependencies] table is intentionally absent because it names Zed packages,
# not crates.io packages.
[publish]
exclude = ["Cargo.lock"]
smoke_test = 'sh "$ZED_PKG_TEST_TARGET/scripts/zed-smoke.sh"'
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## 1.0.1

- add the exact Cargo registry dependency `itoa = 1.0.18`;
- add the optional `uppercase` Cargo feature;
- certify default/all-feature builds and Cargo package contents;
- certify a separate locked/offline Cargo consumer installed through Zed;
- document the `.zpkg.toml` versus `Cargo.toml` ownership boundary.
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
[package]
name = "rust-lib"
version = "1.0.0"
version = "1.0.1"
edition = "2021"
rust-version = "1.88"
description = "A Rust crate sourced via zed (complements cargo/crates.io)."
license = "MIT"
repository = "https://github.com/zed-pkg-test/rust-lib"
readme = "README.md"

[features]
default = []
uppercase = []

[dependencies]
itoa = "=1.0.18"

[lib]
name = "rust_lib"
path = "src/lib.rs"
46 changes: 44 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
# rust-lib (zed-pkg-test/rust-lib)
# rust-lib (`zed-pkg-test/rust-lib`)

A Rust crate published to the zed registry. Consumers add it as a cargo **path** dependency pointing at their `[install].dir` (`.vendor/.zed/zed-pkg-test/rust-lib`), sourced via zed; crates.io keeps owning everything else.
A real Rust crate published through the Zed package registry while retaining
ordinary Cargo semantics.

## Interoperability contract

- Zed owns distribution and materializes the crate under the consumer's
`[install].dir`, normally `.vendor/.zed/zed-pkg-test/rust-lib`.
- Cargo consumes that materialization as a normal `path` dependency.
- `Cargo.toml` owns crates.io dependencies and Cargo features.
- `.zpkg.toml` owns Zed package identity and Zed-to-Zed dependencies; crates.io
packages are deliberately not repeated there.
- Library source does not track `Cargo.lock`, matching standard Cargo library
practice. Binary consumers do track their own lockfile.

Version `1.0.1` depends on the exact crates.io package `itoa = 1.0.18`. The
`format_count` API proves that dependency is present after Zed publication and
installation. The optional `uppercase` feature is used by the companion
`zed-pkg-test/rust-app` fixture to prove Cargo resolver-v2 feature separation
between target and build dependencies.

A consumer uses both package managers explicitly:

```toml
# Cargo.toml
[dependencies]
rust-lib = {
path = ".vendor/.zed/zed-pkg-test/rust-lib",
features = ["uppercase"]
}
```

```toml
# .zpkg.toml
[install]
dir = ".vendor/.zed"

[dependencies]
"zed-pkg-test/rust-lib" = "^1.0.0"
```

The Zed publish smoke test builds a separate Cargo application with this path
dependency plus an independent crates.io dependency, locks it, runs it, and
replays it offline without creating a Zed lockfile in the Cargo-only consumer.
31 changes: 31 additions & 0 deletions docs/cargo-interop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Cargo interoperability contract

This fixture proves that Zed package distribution and Cargo dependency
resolution remain separate, composable layers.

## Ownership

- `.zpkg.toml` identifies the Zed package and any Zed package dependencies.
- `Cargo.toml` identifies crates.io, Git, and Cargo path dependencies plus Cargo
features.
- library source does not track `Cargo.lock`;
- a consuming binary owns its exact Cargo lock;
- `.zpkg.lock` and `Cargo.lock` may coexist and neither package manager rewrites
the other's lockfile.

## Certified scenario

`rust-lib` is published and installed through Zed. Its Cargo manifest depends on
`itoa = 1.0.18`. The publish smoke test then creates an external binary that:

1. points Cargo at the installed Zed package using a path dependency;
2. enables the `uppercase` Cargo feature;
3. declares its own independent `unicode-ident = 1.0.24` crates.io dependency;
4. generates and retains a Cargo lock;
5. verifies Cargo metadata contains one path package and two registry packages;
6. runs with `--locked`; and
7. replays with `--locked --offline` without creating `.zpkg.lock`.

The companion `rust-app` fixture extends this with normal/build dependency
feature separation, Zed symlink/copy modes, dual-lock immutability, and
cross-platform Cargo execution.
28 changes: 23 additions & 5 deletions scripts/zed-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,38 @@ cat >"$smoke_root/Cargo.toml" <<EOF
name = "zed-pkg-rust-smoke"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies]
rust-lib = { path = "$ZED_PKG_TEST_TARGET" }
rust-lib = { path = "$ZED_PKG_TEST_TARGET", features = ["uppercase"] }
unicode-ident = "=1.0.24"
EOF

cat >"$smoke_root/src/main.rs" <<'EOF'
fn main() {
assert_eq!(
rust_lib::greet("r2g"),
"hello r2g from zed-pkg-test/rust-lib"
"HELLO R2G FROM ZED-PKG-TEST/RUST-LIB"
);
assert_eq!(rust_lib::format_count(1_000_001), "1000001");
assert!(unicode_ident::is_xid_start('Δ'));
}
EOF

CARGO_TARGET_DIR="$smoke_root/target" cargo run \
--quiet \
--manifest-path "$smoke_root/Cargo.toml"
cd "$smoke_root"
CARGO_TARGET_DIR="$smoke_root/target" cargo generate-lockfile
cp Cargo.lock Cargo.lock.expected
CARGO_TARGET_DIR="$smoke_root/target" cargo metadata \
--locked \
--format-version 1 >metadata.json

grep -Fq '"name":"rust-lib"' metadata.json
grep -Fq '"name":"itoa"' metadata.json
grep -Fq '"name":"unicode-ident"' metadata.json
grep -Fq 'registry+https://github.com/rust-lang/crates.io-index' Cargo.lock

test ! -e .zpkg.lock
CARGO_TARGET_DIR="$smoke_root/target" cargo run --locked --quiet
CARGO_TARGET_DIR="$smoke_root/target" cargo run --locked --offline --quiet
cmp Cargo.lock.expected Cargo.lock
test ! -e .zpkg.lock
40 changes: 35 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@
//! The one thing this zed-sourced crate exports.
//! Cargo crate fixture distributed through the Zed package registry.

/// Return a greeting that identifies the immutable Zed package namespace.
///
/// The optional `uppercase` Cargo feature intentionally changes only the
/// consumer-facing target build. Cargo resolver v2 can therefore prove that a
/// normal dependency and a build dependency may use separate feature sets even
/// when both point at the same Zed-materialized crate.
pub fn greet(who: &str) -> String {
format!("hello {who} from zed-pkg-test/rust-lib")
let message = format!("hello {who} from zed-pkg-test/rust-lib");
#[cfg(feature = "uppercase")]
let message = message.to_uppercase();
message
}

/// Format an integer through a real crates.io dependency.
///
/// This keeps the fixture small while proving that a crate installed by Zed can
/// retain ordinary Cargo registry dependencies without duplicating them in
/// `.zpkg.toml`.
pub fn format_count(value: u64) -> String {
let mut buffer = itoa::Buffer::new();
buffer.format(value).to_owned()
}

#[cfg(test)]
mod tests {
use super::greet;
use super::{format_count, greet};

#[test]
fn greet_identifies_the_immutable_zed_package_namespace() {
assert_eq!(
greet("consumer"),
let expected = if cfg!(feature = "uppercase") {
"HELLO CONSUMER FROM ZED-PKG-TEST/RUST-LIB"
} else {
"hello consumer from zed-pkg-test/rust-lib"
};
assert_eq!(greet("consumer"), expected);
}

#[test]
fn cargo_registry_dependency_is_exercised() {
assert_eq!(
format_count(18_446_744_073_709_551_615),
"18446744073709551615"
);
}
}
10 changes: 10 additions & 0 deletions tests/feature_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#[test]
fn cargo_feature_and_registry_dependency_are_publicly_usable() {
let expected = if cfg!(feature = "uppercase") {
"HELLO INTEGRATION FROM ZED-PKG-TEST/RUST-LIB"
} else {
"hello integration from zed-pkg-test/rust-lib"
};
assert_eq!(rust_lib::greet("integration"), expected);
assert_eq!(rust_lib::format_count(4_294_967_296), "4294967296");
}
Loading