about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-12-20T16·58+0300
committerclbot <clbot@tvl.fyi>2022-12-21T14·31+0000
commitb3c34c3c6104824733baae2d892eeabd423681a2 (patch)
treed9b07cc6689dee7c5697e018cfbfe33fd3c9433b
parenta95dea719f1b44231c485e52816c5fff4cfe42dd (diff)
docs(tvix/nar): document how to use NAR writer r/5451
This is done in the form of some comments on the functions, as well as
a functional doctest that writes a single file to a NAR.

Change-Id: Ic97ebd439e91d6b076685807fe70de098ec02575
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7599
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
-rw-r--r--tvix/nar/src/lib.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/tvix/nar/src/lib.rs b/tvix/nar/src/lib.rs
index 89cf6fdb19..62d2be5014 100644
--- a/tvix/nar/src/lib.rs
+++ b/tvix/nar/src/lib.rs
@@ -1,15 +1,51 @@
+//! Implements an interface for writing the Nix archive format (NAR).
+//!
+//! NAR files (and their hashed representations) are used in C++ Nix for
+//! addressing fixed-output derivations and a variety of other things.
+//!
+//! NAR files can be output to any type that implements [`Write`], and content
+//! can be read from any type that implementes [`BufRead`].
+//!
+//! Writing a single file might look like this:
+//!
+//! ```rust
+//! # use std::io::BufReader;
+//! # let some_file: Vec<u8> = vec![0, 1, 2, 3, 4];
+//!
+//! // Output location to write the NAR to.
+//! let mut sink: Vec<u8> = Vec::new();
+//!
+//! // Instantiate writer for this output location.
+//! let mut nar = tvix_nar::open(&mut sink)?;
+//!
+//! // Acquire metadata for the single file to output, and pass it in a
+//! // `BufRead`-implementing type.
+//!
+//! let executable = false;
+//! let size = some_file.len() as u64;
+//! let mut reader = BufReader::new(some_file.as_slice());
+//! nar.file(executable, size, &mut reader)?;
+//! # Ok::<(), std::io::Error>(())
+//! ```
+
 use std::io::{self, BufRead, ErrorKind::UnexpectedEof, Write};
 
 mod wire;
 
+/// Convenience type alias for types implementing [`Write`].
 pub type Writer<'a> = dyn Write + 'a;
 
+/// Create a new NAR, writing the output to the specified writer.
 pub fn open<'a, 'w: 'a>(writer: &'a mut Writer<'w>) -> io::Result<Node<'a, 'w>> {
     let mut node = Node { writer };
     node.write(&wire::TOK_NAR)?;
     Ok(node)
 }
 
+/// Single node in a NAR file.
+///
+/// A NAR can be thought of as a tree of nodes represented by this type. Each
+/// node can be a file, a symlink or a directory containing other nodes.
 pub struct Node<'a, 'w: 'a> {
     writer: &'a mut Writer<'w>,
 }
@@ -26,6 +62,7 @@ impl<'a, 'w> Node<'a, 'w> {
         }
     }
 
+    /// Make this node a symlink.
     pub fn symlink(mut self, target: &str) -> io::Result<()> {
         debug_assert!(
             target.len() <= wire::MAX_TARGET_LEN,
@@ -46,6 +83,7 @@ impl<'a, 'w> Node<'a, 'w> {
         Ok(())
     }
 
+    /// Make this node a single file.
     pub fn file(mut self, executable: bool, size: u64, reader: &mut dyn BufRead) -> io::Result<()> {
         self.write(if executable {
             &wire::TOK_EXE
@@ -76,6 +114,8 @@ impl<'a, 'w> Node<'a, 'w> {
         Ok(())
     }
 
+    /// Make this node a directory, the content of which is set using the
+    /// resulting [`Directory`] value.
     pub fn directory(mut self) -> io::Result<Directory<'a, 'w>> {
         self.write(&wire::TOK_DIR)?;
         Ok(Directory::new(self))
@@ -92,6 +132,7 @@ fn into_name(_name: &str) -> Name {
     _name.to_owned()
 }
 
+/// Content of a NAR node that represents a directory.
 pub struct Directory<'a, 'w> {
     node: Node<'a, 'w>,
     prev_name: Option<Name>,
@@ -105,6 +146,10 @@ impl<'a, 'w> Directory<'a, 'w> {
         }
     }
 
+    /// Add an entry to the directory.
+    ///
+    /// The entry is simply another [`Node`], which can then be filled like the
+    /// root of a NAR (including, of course, by nesting directories).
     pub fn entry(&mut self, name: &str) -> io::Result<Node<'_, 'w>> {
         debug_assert!(
             name.len() <= wire::MAX_NAME_LEN,
@@ -146,6 +191,10 @@ impl<'a, 'w> Directory<'a, 'w> {
         })
     }
 
+    /// Close a directory and write terminators for the directory to the NAR.
+    ///
+    /// **Important:** This *must* be called when all entries have been written
+    /// in a directory, otherwise the resulting NAR file will be invalid.
     pub fn close(mut self) -> io::Result<()> {
         if self.prev_name.is_some() {
             self.node.write(&wire::TOK_PAR)?;