<div align="right">
<span style="color:#999;">πΊπΈ English</span> Β·
</div>
<h1 align="center"><code>svn-rs</code></h1>
<p align="center">A Rust async client for Subversion <code>svn://</code> (<code>ra_svn</code>) β a modern alternative to <code>libsvn_ra_svn</code>.</p>
<div align="center">
<a href="https://crates.io/crates/svn">
<img src="https://img.shields.io/crates/v/svn.svg" alt="crates.io version">
</a>
<a href="https://docs.rs/svn">
<img src="https://img.shields.io/docsrs/svn?logo=rust" alt="docs.rs docs">
</a>
<a href="https://github.com/lvillis/svn-rs/actions">
<img src="https://github.com/lvillis/svn-rs/actions/workflows/ci.yaml/badge.svg" alt="CI status">
</a>
<a href="rust-toolchain.toml">
<img src="https://img.shields.io/badge/MSRV-1.92.0-informational" alt="MSRV 1.92.0">
</a>
<a href="LICENSE">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license">
</a>
<a href="https://crates.io/crates/svn">
<img src="https://img.shields.io/crates/dr/svn?color=ba86eb" alt="downloads">
</a>
</div>
---
<a id="table-of-contents"></a>
## Features
- Async-first `svn://` (`ra_svn`) client (no working copy).
- High-level API: `RaSvnClient` / `RaSvnSession`.
- Structured server errors (`code/message/file/line`) with command context.
- `serde` feature for public data types.
- Optional `cyrus-sasl` feature for Cyrus SASL auth + negotiated SASL security
layer (requires a system-provided `libsasl2` at runtime).
## Installation
Add the crate:
```bash
cargo add svn
```
Or in `Cargo.toml`:
```toml
[dependencies]
svn = "0.1"
```
You also need an async runtime. The examples below use `tokio`:
```toml
[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
## Quick start
The `RaSvnClient` type is a reusable configuration; use it to create a connected
`RaSvnSession` (which owns a single TCP connection).
```rust,no_run
use std::time::Duration;
use svn::{RaSvnClient, SvnUrl};
#[tokio::main]
async fn main() -> svn::Result<()> {
let url = SvnUrl::parse("svn://example.com/repo")?;
let client = RaSvnClient::new(url, None, None)
.with_connect_timeout(Duration::from_secs(10))
.with_read_timeout(Duration::from_secs(30))
.with_write_timeout(Duration::from_secs(30));
let mut session = client.open_session().await?;
let latest = session.get_latest_rev().await?;
println!("HEAD = {latest}");
Ok(())
}
```
## Configuration
`RaSvnClient` is cheap to clone and provides builder-style methods:
- `with_connect_timeout(Duration)`
- `with_read_timeout(Duration)`
- `with_write_timeout(Duration)`
- `with_ra_client(String)` (sent during handshake)
In general, prefer reusing a single `RaSvnSession` for multiple operations to
avoid repeated reconnect + handshake.
## Authentication
This crate supports `svn://` authentication mechanisms commonly offered by
`svnserve`:
- `ANONYMOUS`
- `PLAIN` (username + password)
- `CRAM-MD5` (username + password)
Pass `username`/`password` when creating `RaSvnClient`. If the server requires an
unsupported mechanism, operations return `SvnError::AuthUnavailable`.
To enable Cyrus SASL (and the optional SASL security layer), enable the
`cyrus-sasl` feature (requires `libsasl2` installed on the system at runtime):
```toml
svn = { version = "0.1", features = ["cyrus-sasl"] }
```
Notes:
- With `cyrus-sasl`, this crate dynamically loads the system Cyrus SASL library
(`libsasl2`) at runtime. If it is not available, SASL authentication is
unavailable and requests may fail with `SvnError::AuthUnavailable`.
- The SASL security layer is not TLS (no certificates); it is an optional
integrity/encryption layer negotiated as part of SASL, depending on the
mechanism and server configuration.
- When `cyrus-sasl` is disabled (the default), the crate stays `unsafe`-free.
## Supported operations
This crate focuses on `ra_svn` protocol v2 and currently supports:
- Read: `get-latest-rev`, `get-dated-rev`, `get-file`, `get-dir`, `log`, `list`,
`check-path`, `stat`, `get-mergeinfo`, `get-deleted-rev`, `get-locations`,
`get-location-segments`, `get-file-revs`, `rev-prop`, `rev-proplist`,
`proplist`, `propget`, `get-iprops`, locks listing (`get-lock`, `get-locks`).
- Report/editor flows: `update`, `switch`, `status`, `diff`, `replay`,
`replay-range`.
- Write: `change-rev-prop`, `change-rev-prop2`, `lock`/`unlock` (including
`*-many`), and a low-level `commit` API driven by `EditorCommand`.
For full API docs and examples, see https://docs.rs/svn.
## Errors
All APIs return `svn::Result<T>` (an alias for `Result<T, SvnError>`). Server-side
failures are returned as `SvnError::Server(ServerError)` and include a structured
error chain and command context.
```rust,no_run
use svn::{RaSvnClient, SvnError, SvnUrl};
#[tokio::main]
async fn main() {
let url = SvnUrl::parse("svn://example.com/repo").unwrap();
let client = RaSvnClient::new(url, None, None);
let err = client.get_latest_rev().await.unwrap_err();
match err {
SvnError::Server(server) => {
eprintln!("server: {server}");
for item in &server.chain {
eprintln!(" code={} msg={:?} file={:?} line={:?}", item.code, item.message, item.file, item.line);
}
}
other => eprintln!("error: {other}"),
}
}
```
## Logging
This crate uses `tracing` for debug logging. Enable logs in your application
(for example with `tracing-subscriber`) and set an appropriate filter:
```text
RUST_LOG=svn=debug
```
## Compatibility
- Protocol: `ra_svn` v2 (`svn://` only).
- MSRV: Rust `1.92.0` (see `Cargo.toml`).
- Optional `serde` support via the `serde` feature.
- Optional Cyrus SASL support via `cyrus-sasl` (runtime `libsasl2`).
## Security
- `svn://` is plain TCP (no native TLS).
- `PLAIN` sends credentials without encryption unless you use a secure tunnel
(VPN / SSH port forwarding / stunnel) or negotiate a SASL security layer.
- Even with `CRAM-MD5`, repository traffic is still unencrypted unless a tunnel
or SASL security layer is used.
## Testing
Unit tests and property tests:
```bash
cargo test --all-features
```
Interop tests against a real `svnserve` (requires `svn`, `svnadmin`, `svnserve`):
```bash
SVN_INTEROP=1 cargo test --all-features --test interop_svnserve -- --nocapture
```
## Limitations
- No `svn+ssh://` support.
- Not a working copy client (no checkout / update of a local working copy).
- No native TLS (see [Security](#security)).
## License
Licensed under the MIT license. See `LICENSE`.