netrc-rs
A lightweight Rust library that parses .netrc files into typed host, login, and macro structs.
Repository Health
Technical Analysis
netrc-rs is a small, dependency-free Rust crate for reading the classic Unix .netrc file format used by tools like curl, ftp, and other network clients to store per-host credentials. It exposes a single Netrc::parse entry point that consumes any std::io::BufRead source and returns a structured Netrc value containing per-host Machine records (login, password, account, port), an optional default machine, and any macdef macro blocks defined in the file.
The crate is built entirely on the standard library, so it drops cleanly into CLI tools, HTTP clients, or FTP automation scripts that need curl-compatible netrc lookup without pulling in extra dependencies. Parse errors are typed and carry line numbers, making malformed netrc files easy to diagnose.
What You Get
- A single
Netrc::parse<A: BufRead>function that parses any buffered byte stream into a structuredNetrcvalue - Per-host
Machinerecords exposinglogin,password,account, andportfields - Support for the
defaultmachine directive as a fallback credential set - Extraction of
macdefmacro blocks as named, raw multi-line command strings - A typed
Errorenum (Io/Parse) with line-number context for malformed entries - Zero external dependencies — implemented entirely on the Rust standard library
Common Use Cases
- A command-line HTTP or FTP client reads
~/.netrcto look up stored credentials for a given host before making a request - A custom Rust HTTP client adds curl-compatible automatic authentication by parsing the user’s netrc file
- A config-validation tool parses a
.netrcfile and reports line-numbered syntax errors to help users fix malformed entries - An FTP automation script extracts
macdefblocks to drive scripted upload/download command sequences
Under The Hood
Architecture
The crate is a single-module parser: a Lexer wraps a BufRead source and tokenizes each line into whitespace-separated words via an internal Tokens cursor, while Netrc::parse drives a loop that pulls words from the lexer and dispatches them through parse_entry, which mutates a MachineRef-tracked “current machine” (Nothing / Default / Host(index)) using a with_current_machine! macro to fetch a mutable reference via find_machine. Data flows linearly from byte stream to line buffer to tokens to the final Netrc struct with no intermediate AST or two-pass parse, appropriate for the format’s small grammar; the token model in Lexer/Tokens is the one abstraction every parse_entry match arm depends on.
Tech Stack
The crate declares zero external dependencies in Cargo.toml and targets pre-2018 Rust editions, evidenced by its use of the try! macro rather than the ? operator. It builds with plain cargo build/cargo test, and CI is configured via a legacy .travis.yml rather than GitHub Actions, consistent with the project’s 2014-2020 development window. The public API is fully synchronous and generic over std::io::BufRead, so it works equally in blocking CLI tools and embedded library code without pulling in an async runtime.
Code Quality
Six inline #[cfg(test)] unit tests cover basic host parsing, macdef blocks, the default machine fallback, and three distinct error paths (unknown entry, unexpected EOF, missing machine context, unparsable port) using BufReader<&[u8]> fixtures — solid coverage for the crate’s small surface area. Error handling is explicit and typed through a two-variant Error enum propagated with try!, and there is no clippy/rustfmt configuration or dedicated lint CI job visible, reflecting a crate that hasn’t been touched since its last 2020 commit. Naming is idiomatic snake_case/PascalCase Rust and the code has no unsafe blocks.
API Design
The public surface is a single call: Netrc::parse(reader) returns a Result<Netrc> with plain hosts: Vec<(String, Machine)>, default: Option<Machine>, and macros: Vec<(String, String)> fields, needing no configuration or builder step to get started, and the doc comment on parse doubles as a runnable doctest. Parse errors carry both a message and a line number, which is a genuinely useful debugging aid over offset-only errors. The crate doesn’t offer streaming iteration, serde integration, or generic extensibility, so it stays a straightforward, no-frills implementation of a well-understood file format rather than doing something alternatives can’t.