Thanks to visit codestin.com
Credit goes to lib.rs

6 releases

Uses new Rust 2024

0.1.6 Jan 6, 2026
0.1.5 Jan 6, 2026
0.1.4 Dec 29, 2025

#625 in Network programming

MIT license

800KB
19K SLoC

πŸ‡ΊπŸ‡Έ English Β· πŸ‡¨πŸ‡³ δΈ­ζ–‡       |      Table of Contents

svn-rs

A Rust async client for Subversion svn:// (ra_svn) β€” a modern alternative to libsvn_ra_svn.


Features

  • Async-first svn:// (ra_svn) client (no working copy).
  • Optional svn+ssh:// via SSH tunnel (ssh feature; runs svnserve -t over SSH).
  • 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:

cargo add svn

Or in Cargo.toml:

[dependencies]
svn = "0.1"

You also need an async runtime. The examples below use tokio:

[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).

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):

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.

svn+ssh:// (SSH tunnel)

Enable the ssh feature to connect using svn+ssh:// URLs (runs svnserve -t over SSH using russh):

svn = { version = "0.1", features = ["ssh"] }
use std::path::PathBuf;
use svn::{RaSvnClient, SshAuth, SshConfig, SvnUrl};

# #[tokio::main] async fn main() -> svn::Result<()> {
let url = SvnUrl::parse("svn+ssh://example.com/repo")?;
let ssh = SshConfig::new(SshAuth::KeyFile {
    path: PathBuf::from("~/.ssh/id_ed25519"),
    passphrase: None,
});

let client = RaSvnClient::new(url, None, None).with_ssh_config(ssh);
let mut session = client.open_session().await?;
let head = session.get_latest_rev().await?;
println!("{head}");
# Ok(()) }

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.

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:

RUST_LOG=svn=debug

Compatibility

  • Protocol: ra_svn v2 (svn://, and svn+ssh:// with the ssh feature).
  • IPv6: supported via bracketed URLs (for example svn://[::1]/repo).
  • MSRV: Rust 1.92.0 (see Cargo.toml).
  • Optional serde support via the serde feature.
  • Optional Cyrus SASL support via cyrus-sasl (runtime libsasl2).
  • Optional SSH tunnel support via ssh (russh).

Security

  • svn:// is plain TCP (no native TLS).
  • svn+ssh:// uses SSH for transport encryption and authentication.
  • 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:

cargo test --all-features

Interop tests against a real svnserve (requires svn, svnadmin, svnserve):

SVN_INTEROP=1 cargo test --all-features --test interop_svnserve -- --nocapture

Limitations

  • Not a working copy client (no checkout / update of a local working copy).
  • No native TLS (see Security).
  • The ssh feature supports a subset of ~/.ssh/config and ssh-agent (no ProxyJump/ProxyCommand).

License

Licensed under the MIT license. See LICENSE.

Dependencies

~9–45MB
~575K SLoC