Skip to content

Commit e4f016b

Browse files
authored
Merge pull request GitoxideLabs#2400 from GitoxideLabs/gix-error
More of `gix-error`
2 parents c149c60 + f860c0b commit e4f016b

16 files changed

Lines changed: 532 additions & 176 deletions

File tree

.claude/instructions.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Claude Code Instructions for Gitoxide
2+
3+
See [.github/copilot-instructions.md](../.github/copilot-instructions.md) for project conventions,
4+
architecture decisions, error handling patterns, and development practices.
5+
6+
## Quick Reference
7+
8+
- `cargo test -p <crate-name>` to test a specific crate
9+
- `cargo check -p gix` to check the main crate with default features
10+
- `just check` to build all code in suitable configurations
11+
- `just test` to run all tests, clippy, and journey tests
12+
- `cargo fmt` to format all code
13+
- `cargo clippy --workspace --all-targets -- -D warnings -A unknown-lints --no-deps` to lint all code

.github/copilot-instructions.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,53 @@ This repository contains `gitoxide` - a pure Rust implementation of Git. This do
55
## Project Overview
66

77
- **Language**: Rust (MSRV documented in gix/Cargo.toml)
8-
- **Structure**: Cargo workspace with multiple crates (gix-*, gitoxide-core, etc.)
8+
- **Structure**: Cargo workspace with multiple crates (gix-\*, gitoxide-core, etc.)
99
- **Main crates**: `gix` (library entrypoint), `gitoxide` binary (CLI tools: `gix` and `ein`)
1010
- **Purpose**: Provide a high-performance, safe Git implementation with both library and CLI interfaces
1111

1212
## Development Practices
1313

1414
### Test-First Development
15+
1516
- Protect against regression and make implementing features easy
1617
- Keep it practical - the Rust compiler handles mundane things
1718
- Use git itself as reference implementation; run same tests against git where feasible
1819
- Never use `.unwrap()` in production code, avoid it in tests in favor of `.expect()` or `?`. Use `gix_testtools::Result` most of the time.
1920
- Use `.expect("why")` with context explaining why expectations should hold, but only if it's relevant to the test.
2021

2122
### Error Handling
23+
2224
- Handle all errors, never `unwrap()`
2325
- Provide error chains making it easy to understand what went wrong
24-
- Use `thiserror` for libraries generally
2526
- Binaries may use `anyhow::Error` exhaustively (user-facing errors)
2627

28+
#### `gix-error` (preferred for plumbing crates)
29+
30+
Plumbing crates are migrating from `thiserror` enums to `gix-error`. Check whether a crate already
31+
uses `gix-error` (look at its `Cargo.toml`); if it does, follow the patterns below. If it still uses
32+
`thiserror`, keep using `thiserror` for consistency within that crate.
33+
34+
- **Error type alias**: `pub type Error = gix_error::Exn<gix_error::Message>;`
35+
- **Static messages**: `gix_error::message("something failed")`
36+
- **Formatted messages**: `gix_error::message!("failed to read {path}")`
37+
- **Wrapping callee errors with context**: `.or_raise(|| message("context about what failed"))?`
38+
- **Standalone error (no callee)**: `Err(message("something went wrong").raise())`
39+
- **Wrapping an `impl Error` with context**: `err.and_raise(message("context"))`
40+
- **Closure/callback bounds**: use `Result<T, Exn>` (bare), not `Exn<Message>`;
41+
inside the function, convert with `.or_raise(|| message("..."))?`;
42+
inside the closure, convert typed to bare with `.or_erased()`
43+
- **`Exn<E>` does NOT implement `std::error::Error`** — this is by design.
44+
- To convert: use `.into_error()` to get `gix_error::Error` (which does implement `std::error::Error`)
45+
- Example: `std::io::Error::other(exn.into_error())`
46+
- **In tests** returning `gix_testtools::Result` (= `Result<(), Box<dyn Error>>`), `Exn` can't be used
47+
with `?` directly — use `.map_err(|e| e.into_error())?`
48+
- **Common imports**: `use gix_error::{message, ErrorExt, ResultExt};`
49+
- See `gix-error/src/lib.rs` module docs for a full migration guide from `thiserror`
50+
2751
### Commit Messages
52+
2853
Follow "purposeful conventional commits" style:
54+
2955
- Use conventional commit prefixes ONLY if message should appear in changelog
3056
- Breaking changes MUST use suffix `!`: `change!:`, `remove!:`, `rename!:`
3157
- Features/fixes visible to users: `feat:`, `fix:`
@@ -36,67 +62,78 @@ Follow "purposeful conventional commits" style:
3662
- `change!: rename Foo to Bar. (#123)`
3763

3864
### Code Style
65+
3966
- Follow existing patterns in the codebase
4067
- No `.unwrap()` - use `.expect("context")` if you are sure this can't fail.
4168
- Prefer references in plumbing crates to avoid expensive clones
4269
- Use `gix_features::threading::*` for interior mutability primitives
4370

4471
### Path Handling
72+
4573
- Paths are byte-oriented in git (even on Windows via MSYS2 abstraction)
4674
- Use `gix::path::*` utilities to convert git paths (`BString`) to `OsStr`/`Path` or use custom types
4775

4876
## Building and Testing
4977

5078
### Quick Commands
79+
5180
- `just test` - Run all tests, clippy, journey tests, and try building docs
5281
- `just check` - Build all code in suitable configurations
5382
- `just clippy` - Run clippy on all crates
5483
- `cargo test` - Run unit tests only
5584

5685
### Build Variants
86+
5787
- `cargo build --release` - Default build (big but pretty, ~2.5min)
5888
- `cargo build --release --no-default-features --features lean` - Lean build (~1.5min)
5989
- `cargo build --release --no-default-features --features small` - Minimal deps (~46s)
6090

6191
### Test Best Practices
92+
6293
- Run tests before making changes to understand existing issues
6394
- Use `GIX_TEST_IGNORE_ARCHIVES=1` when testing on macOS/Windows
6495
- Journey tests validate CLI behavior end-to-end
6596

6697
## Architecture Decisions
6798

6899
### Plumbing vs Porcelain
100+
69101
- **Plumbing crates**: Low-level, take references, expose mutable parts as arguments
70102
- **Porcelain (gix)**: High-level, convenient, may clone Repository for user convenience
71103
- Platforms: cheap to create, keep reference to Repository
72104
- Caches: more expensive, clone `Repository` or free of lifetimes
73105

74106
### Options vs Context
107+
75108
- Use `Options` for branching behavior configuration (can be defaulted)
76109
- Use `Context` for data required for operation (cannot be defaulted)
77110

78111
## Crate Organization
79112

80113
### Common Crates
114+
81115
- `gix`: Main library entrypoint (porcelain)
82116
- `gix-object`, `gix-ref`, `gix-config`: Core git data structures
83117
- `gix-odb`, `gix-pack`: Object database and pack handling
84118
- `gix-diff`, `gix-merge`, `gix-status`: Operations
85119
- `gitoxide-core`: Shared CLI functionality
86120

87121
## Documentation
122+
88123
- High-level docs: README.md, CONTRIBUTING.md, DEVELOPMENT.md
89124
- Crate status: crate-status.md
90125
- Stability guide: STABILITY.md
91126
- Always update docs if directly related to code changes
92127

93128
## CI and Releases
129+
94130
- Ubuntu-latest git version is the compatibility target
95131
- `cargo smart-release` for releases (driven by commit messages)
96132
- Split breaking changes into separate commits per affected crate if one commit-message wouldn't be suitable for all changed crates.
97133
- First commit: breaking change only; second commit: adaptations
98134

99135
## When Suggesting Changes
136+
100137
1. Understand the plumbing vs porcelain distinction
101138
2. Check existing patterns in similar crates
102139
3. Follow error handling conventions strictly

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-archive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ gix-date = { version = "^0.13.0", path = "../gix-date" }
3535
flate2 = { version = "1.1.8", optional = true, default-features = false, features = ["zlib-rs"] }
3636
rawzip = { version = "0.4.3", optional = true }
3737

38-
thiserror = "2.0.18"
38+
gix-error = { version = "^0.0.0", path = "../gix-error" }
3939
bstr = { version = "1.12.0", default-features = false }
4040

4141
tar = { version = "0.4.38", optional = true }

gix-archive/src/lib.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,7 @@
1919
use bstr::BString;
2020

2121
/// The error returned by [`write_stream()`].
22-
#[derive(Debug, thiserror::Error)]
23-
#[allow(missing_docs)]
24-
pub enum Error {
25-
#[error(transparent)]
26-
Io(#[from] std::io::Error),
27-
#[error(transparent)]
28-
NextStreamEntry(#[from] gix_worktree_stream::entry::Error),
29-
#[error("The internal format cannot be used as an archive, it's merely a debugging tool")]
30-
InternalFormatMustNotPersist,
31-
#[error("Support for the format '{wanted:?}' was not compiled in")]
32-
SupportNotCompiledIn { wanted: Format },
33-
#[error("Cannot create a zip archive if output stream does not support seek")]
34-
ZipWithoutSeek,
35-
#[error("Cannot use modification as it is not within the supported bounds")]
36-
InvalidModificationTime(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
37-
}
22+
pub type Error = gix_error::Exn<gix_error::Message>;
3823

3924
/// The supported container formats for use in [`write_stream()`].
4025
#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]

0 commit comments

Comments
 (0)