guix-scheme 0.2.0

Read, edit, and generate Guix Scheme files (channels.scm, system config.scm) from Rust
Documentation
# guix-scheme

[![CI](https://github.com/franzos/guix-scheme/actions/workflows/ci.yml/badge.svg)](https://github.com/franzos/guix-scheme/actions/workflows/ci.yml)

Read/write Guix Scheme files from Rust: parse and edit `channels.scm` without losing comments or formatting, and generate `operating-system` configurations. Built on a lossless S-expression concrete syntax tree, so untouched parts of a file survive edits byte-for-byte.

| Crate | Purpose | | |
|-------|---------|---|---|
| `guix-scheme` | Typed views over Guix files: channels read/add/remove, operating-system builder, record field access | [![Crates.io](https://img.shields.io/crates/v/guix-scheme.svg)](https://crates.io/crates/guix-scheme) | [![Docs.rs](https://docs.rs/guix-scheme/badge.svg)](https://docs.rs/guix-scheme) |
| `scheme-edit` | Generic lossless Scheme CST parser and editor (toml_edit-style), no Guix specifics | [![Crates.io](https://img.shields.io/crates/v/scheme-edit.svg)](https://crates.io/crates/scheme-edit) | [![Docs.rs](https://docs.rs/scheme-edit/badge.svg)](https://docs.rs/scheme-edit) |

## Editing channels.scm

```rust
use guix_scheme::{Channel, ChannelsFile};

let src = std::fs::read_to_string("channels.scm")?;
let mut cf = ChannelsFile::parse(&src)?;

cf.add_channel(&Channel {
    name: "pantherx".into(),
    url: "https://codeberg.org/gofranz/panther.git".into(),
    branch: Some("master".into()),
    commit: None,
    introduction_commit: Some("54b4056ac571611892c743b65f4c47dc298c49da".into()),
    introduction_fingerprint: Some("A36A D41E ECC7 A871 1003  5D24 524F EB1A 9D33 C9CB".into()),
})?;

cf.remove_channel("nonguix")?;
std::fs::write("channels.scm", cf.to_string())?;
```

Comments, indentation, and everything you didn't touch come back byte-identical.

## A note on what this is (and isn't)

Parsing Guix Scheme from Rust is not ideal, and this crate cannot validate content. It's a poor man's workaround for when Guix isn't available, or when you'd rather read and write these files from Rust. Scheme and Guix are a full language and application; `guix-scheme` is just a dumb parser. It won't tell you if something is missing (a module import, a required field) or otherwise wrong. If you need real validation, feed the result through Guix itself (see the `guile-check` feature below for a partial check).

## Generating an operating-system

```rust
use guix_scheme::os_builder::{FsDevice, OsBuilder, OsFlavor};

let config = OsBuilder::new(OsFlavor::Guix, "my-box", "Europe/Berlin", "en_US.utf8")
    .bootloader_efi("/boot/efi")
    .file_system("/", FsDevice::Label("root".into()), "ext4", false)
    .user("franz", "Franz", &["wheel", "netdev", "audio", "video"])
    .services_field("%desktop-services")
    .build();
```

## Feature flags

- `guile-check` (guix-scheme): validate generated/edited source by feeding it through a real `guile` reader. Off by default; requires `guile` on `PATH` at runtime.

## MSRV

Rust 1.70 (2021 edition). Verified to build on 1.70; also tested on current stable.

## Fixture sources

The test corpus (35 files under `scheme-edit/tests/fixtures/`) is copied verbatim
from GNU Guix, libguix, guix-install, and community configuration repos found via
[awesome-guix](https://github.com/franzos/awesome-guix). Each file keeps its
original copyright and license. Full credits:
[scheme-edit/tests/fixtures/SOURCES.md](scheme-edit/tests/fixtures/SOURCES.md).

## License

Licensed under either of [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE) at your option.