about summary refs log tree commit diff
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2024-03-03 17:25:58 +0100
committerProfpatsch <mail@profpatsch.de>2024-03-03 17:26:18 +0100
commit6e9330977b8a0ca10195f16645053e1838a46beb (patch)
tree41de2d4abcd0035cb85af87f6c8d167c5ccfbe0b
parent03ce9742fc6dd47cce89270d863a461e947e1fef (diff)
pkgs/profpatsch/nman: put functions into struct context
so that we can add a global debug flag
-rw-r--r--pkgs/profpatsch/nman/nman.rs313
1 files changed, 160 insertions, 153 deletions
diff --git a/pkgs/profpatsch/nman/nman.rs b/pkgs/profpatsch/nman/nman.rs
index db2bfe32..a3fbfc57 100644
--- a/pkgs/profpatsch/nman/nman.rs
+++ b/pkgs/profpatsch/nman/nman.rs
@@ -23,6 +23,7 @@ enum CliResult<'a> {
 
 fn main() {
     use CliResult::*;
+    // let main = Main{is_debug: false};
     let (opts, args) : (Vec<String>, Vec<String>) =
             std::env::args().partition(|s| s.starts_with("-"));
 
@@ -57,7 +58,7 @@ fn main() {
         },
         Action(action) => match action {
             CliAction::Man(attr, section, page) =>
-            match open_man_page(attr, section, page) {
+            match Main::open_man_page(attr, section, page) {
                 Ok(_) => (),
                 Err(t) => {
                     let msg = t.msg();
@@ -228,175 +229,181 @@ impl<'a> DrvWithOutput<'a> {
     }
 }
 
+struct Main {
+    // is_debug: bool
+}
 
-/// This function implements the main operation of `nman`:
-/// It instantiates the given attribute to get all outputs
-/// of the described derivation and checks the outputs
-/// for the desired man page using `build_man_page`.
-/// Finally the man page is opened using `man(1)`.
-/// Both GNU's `man-db` and OpenBSD's `mandoc` work
-/// (any man implementation that implements `-l` should
-/// for that matter).
-fn open_man_page<'a>(attr: &'a str, section: Option<&'a str>, page: &'a str) -> Result<(), NmanError<'a>> {
-    let tmpdir = TempDir::new("nman").map_err(NmanError::IO)?;
-    // TODO(sterni): allow selecting other base package sets,
-    //               like <vuizvui>, /home/lukas/src/nix/nixpkgs, …
-    let expr = format!("with (import <nixpkgs> {{}}); builtins.map (o: {}.\"${{o}}\") {}.outputs", attr, attr);
-    let inst = debug_log_command(
-                        Command::new("nix-instantiate")
-                            .arg("-E")
-                            .arg(expr)
-                            .arg("--add-root")
-                            .arg(tmpdir.as_ref().join("instantiation-result"))
-                            .arg("--indirect")
-                            .stderr(Stdio::inherit()))
-                       .and_then(|cmd| cmd.output())
-                       .map_err(|_| NmanError::Execution("nix-instantiate"))?;
-
-    if !inst.status.success() {
-        return Err(NmanError::Instantiate(attr, inst.status));
-    }
-
-    let mut drvs: Vec<DrvWithOutput> =
-            inst.stdout.split(|c| char::from(*c) == '\n')
-                .filter_map(DrvWithOutput::parse).collect();
+impl Main {
+
+    /// This function implements the main operation of `nman`:
+    /// It instantiates the given attribute to get all outputs
+    /// of the described derivation and checks the outputs
+    /// for the desired man page using `build_man_page`.
+    /// Finally the man page is opened using `man(1)`.
+    /// Both GNU's `man-db` and OpenBSD's `mandoc` work
+    /// (any man implementation that implements `-l` should
+    /// for that matter).
+    fn open_man_page<'a>(attr: &'a str, section: Option<&'a str>, page: &'a str) -> Result<(), NmanError<'a>> {
+        let tmpdir = TempDir::new("nman").map_err(NmanError::IO)?;
+        // TODO(sterni): allow selecting other base package sets,
+        //               like <vuizvui>, /home/lukas/src/nix/nixpkgs, …
+        let expr = format!("with (import <nixpkgs> {{}}); builtins.map (o: {}.\"${{o}}\") {}.outputs", attr, attr);
+        let inst = debug_log_command(
+                            Command::new("nix-instantiate")
+                                .arg("-E")
+                                .arg(expr)
+                                .arg("--add-root")
+                                .arg(tmpdir.as_ref().join("instantiation-result"))
+                                .arg("--indirect")
+                                .stderr(Stdio::inherit()))
+                        .and_then(|cmd| cmd.output())
+                        .map_err(|_| NmanError::Execution("nix-instantiate"))?;
+
+        if !inst.status.success() {
+            return Err(NmanError::Instantiate(attr, inst.status));
+        }
 
-    if drvs.len() <= 0 {
-        return Err(NmanError::ParseError("nix-instantiate"));
-    }
+        let mut drvs: Vec<DrvWithOutput> =
+                inst.stdout.split(|c| char::from(*c) == '\n')
+                    .filter_map(DrvWithOutput::parse).collect();
 
-    // the sort order is such that the outputs where we
-    // expect the man page to be are checked first.
-    // This means we realise the least amount of outputs
-    // necessary
-    //
-    // TODO(sterni): change sorting depending on section:
-    //               "3" and "3p" should prioritize DevMan
-    drvs.sort_unstable_by(|a, b| a.output.cmp(&b.output));
-
-    for drv in drvs {
-        let man_file = build_man_page(drv, section, page, &tmpdir)?;
-
-        match man_file {
-            None => continue,
-            Some(f) => {
-                let res = debug_log_command(Command::new("man")
-                                  .arg("-l").arg(f))
-                                  .and_then(|cmd| cmd.spawn())
-                                  .and_then(|mut c| c.wait())
-                                  .map(|c| c.success());
-
-                return match res {
-                    Ok(true) => Ok(()),
-                    Ok(false) => Err(NmanError::Man),
-                    Err(_) => Err(NmanError::Execution("man")),
-                };
-            },
+        if drvs.len() <= 0 {
+            return Err(NmanError::ParseError("nix-instantiate"));
         }
-    }
-
-    Err(NmanError::NotFound(page, section))
-}
 
+        // the sort order is such that the outputs where we
+        // expect the man page to be are checked first.
+        // This means we realise the least amount of outputs
+        // necessary
+        //
+        // TODO(sterni): change sorting depending on section:
+        //               "3" and "3p" should prioritize DevMan
+        drvs.sort_unstable_by(|a, b| a.output.cmp(&b.output));
+
+        for drv in drvs {
+            let man_file = Main::build_man_page(drv, section, page, &tmpdir)?;
+
+            match man_file {
+                None => continue,
+                Some(f) => {
+                    let res = debug_log_command(Command::new("man")
+                                    .arg("-l").arg(f))
+                                    .and_then(|cmd| cmd.spawn())
+                                    .and_then(|mut c| c.wait())
+                                    .map(|c| c.success());
+
+                    return match res {
+                        Ok(true) => Ok(()),
+                        Ok(false) => Err(NmanError::Man),
+                        Err(_) => Err(NmanError::Execution("man")),
+                    };
+                },
+            }
+        }
 
-/// Realises the given derivation output using `nix-store --realise` and
-/// checks if the man page described by `section` and `page` can be found
-/// within it. If that is the case, the path to is returned. If it can't
-/// be found, `None` is returned. `Err` is only used to describe unrecoverable
-/// errors.
-///
-/// `section == None` indicates that the section is not given. `build_man_page`
-/// then searches all man section directories for any matching page. If multiple
-/// matches exist, the one with an alphanumerically lower section is preferred,
-/// e. g. section 1 is preferred over section 3.
-fn build_man_page<'a>(drv: DrvWithOutput, section: Option<&str>, page: &str, tempdir: &TempDir) -> Result<Option<PathBuf>, NmanError<'a>> {
-    let build = debug_log_command(
-                            Command::new("nix-store")
-                            .arg("--realise")
-                            .arg(drv.render())
-                            .arg("--add-root")
-                            .arg(tempdir.as_ref().join("build-result"))
-                            .arg("--indirect")
-                            .stderr(Stdio::inherit()))
-                            .and_then(|cmd| cmd.output())
-                            .map_err(|_| NmanError::Execution("nix-store"))?;
-
-    if !build.status.success() {
-        return Err(NmanError::Build(drv.render(), build.status));
+        Err(NmanError::NotFound(page, section))
     }
 
-    // get the first line of the output, usually only one line
-    // is printed, but this way we also get rid of the trailing '\n'
-    let first_path = build.stdout.split(|c| char::from(*c) == '\n')
-                          .next().filter(|l| l.len() > 0)
-                          .ok_or(NmanError::ParseError("nix-store"))?;
 
-    let mut path = PathBuf::from(OsStr::from_bytes(first_path));
-    path.push("share/man");
+    /// Realises the given derivation output using `nix-store --realise` and
+    /// checks if the man page described by `section` and `page` can be found
+    /// within it. If that is the case, the path to is returned. If it can't
+    /// be found, `None` is returned. `Err` is only used to describe unrecoverable
+    /// errors.
+    ///
+    /// `section == None` indicates that the section is not given. `build_man_page`
+    /// then searches all man section directories for any matching page. If multiple
+    /// matches exist, the one with an alphanumerically lower section is preferred,
+    /// e. g. section 1 is preferred over section 3.
+    fn build_man_page<'a>(drv: DrvWithOutput, section: Option<&str>, page: &str, tempdir: &TempDir) -> Result<Option<PathBuf>, NmanError<'a>> {
+        let build = debug_log_command(
+                                Command::new("nix-store")
+                                .arg("--realise")
+                                .arg(drv.render())
+                                .arg("--add-root")
+                                .arg(tempdir.as_ref().join("build-result"))
+                                .arg("--indirect")
+                                .stderr(Stdio::inherit()))
+                                .and_then(|cmd| cmd.output())
+                                .map_err(|_| NmanError::Execution("nix-store"))?;
+
+        if !build.status.success() {
+            return Err(NmanError::Build(drv.render(), build.status));
+        }
 
-    // no share/man, no man pages
-    if !path.exists() {
-        return Ok(None);
-    }
+        // get the first line of the output, usually only one line
+        // is printed, but this way we also get rid of the trailing '\n'
+        let first_path = build.stdout.split(|c| char::from(*c) == '\n')
+                            .next().filter(|l| l.len() > 0)
+                            .ok_or(NmanError::ParseError("nix-store"))?;
 
-    // expected sub directory of share/man or, if no section
-    // is given, all potential sub directories
-    let mut section_dirs: Vec<(OsString, PathBuf)> =
-        match section {
-            Some(s) => {
-                let dir_name = OsString::from(format!("man{}", s));
-                let dir_path = path.join(dir_name.as_os_str());
-
-                if dir_path.exists() {
-                    vec![(dir_name, dir_path)]
-                } else {
-                    Vec::new()
-                }
-            },
-            None => {
-                read_dir(path.as_path())
-                    .map_err(NmanError::IO)?
-                    .filter_map(|entry| entry.ok())
-                    .map(|e| (e.file_name(), e.path()))
-                    .collect()
-            },
-        };
+        let mut path = PathBuf::from(OsStr::from_bytes(first_path));
+        path.push("share/man");
+
+        // no share/man, no man pages
+        if !path.exists() {
+            return Ok(None);
+        }
 
-    // sorting should be ascending in terms of numerics,
-    // apart from that, not many requirements
-    section_dirs.sort_unstable_by(|(n1, _), (n2, _)| n1.cmp(n2));
-
-    for (dir_name, dir) in section_dirs {
-        // separate "man" prefix from section indicator,
-        // while validating the particular sub directory
-        let parsed_man_dir = dir_name.to_str()
-            .filter(|d| d.len() > 3)
-            .map(|d| d.split_at(3));
-
-        match parsed_man_dir {
-            Some(("man", s)) => {
-                // we have a valid man dir, check if it contains our page
-                let dir_content = read_dir(dir).map_err(NmanError::IO)?;
-
-                for entry in dir_content {
-                    let file = entry.map_err(NmanError::IO)?;
-                    let mmatch =
-                        file.file_name().to_str()
-                            .map(|f| match_man_page_file(f, s, page));
-
-                    if mmatch.unwrap_or(false) {
-                        return Ok(Some(file.path()))
+        // expected sub directory of share/man or, if no section
+        // is given, all potential sub directories
+        let mut section_dirs: Vec<(OsString, PathBuf)> =
+            match section {
+                Some(s) => {
+                    let dir_name = OsString::from(format!("man{}", s));
+                    let dir_path = path.join(dir_name.as_os_str());
+
+                    if dir_path.exists() {
+                        vec![(dir_name, dir_path)]
+                    } else {
+                        Vec::new()
                     }
-                }
-            },
-            _ => continue,
+                },
+                None => {
+                    read_dir(path.as_path())
+                        .map_err(NmanError::IO)?
+                        .filter_map(|entry| entry.ok())
+                        .map(|e| (e.file_name(), e.path()))
+                        .collect()
+                },
+            };
+
+        // sorting should be ascending in terms of numerics,
+        // apart from that, not many requirements
+        section_dirs.sort_unstable_by(|(n1, _), (n2, _)| n1.cmp(n2));
+
+        for (dir_name, dir) in section_dirs {
+            // separate "man" prefix from section indicator,
+            // while validating the particular sub directory
+            let parsed_man_dir = dir_name.to_str()
+                .filter(|d| d.len() > 3)
+                .map(|d| d.split_at(3));
+
+            match parsed_man_dir {
+                Some(("man", s)) => {
+                    // we have a valid man dir, check if it contains our page
+                    let dir_content = read_dir(dir).map_err(NmanError::IO)?;
+
+                    for entry in dir_content {
+                        let file = entry.map_err(NmanError::IO)?;
+                        let mmatch =
+                            file.file_name().to_str()
+                                .map(|f| match_man_page_file(f, s, page));
+
+                        if mmatch.unwrap_or(false) {
+                            return Ok(Some(file.path()))
+                        }
+                    }
+                },
+                _ => continue,
+            }
         }
+
+        Ok(None)
     }
 
-    Ok(None)
 }
 
-
 /// Match if a file name is a man file matching the given
 /// section and page. It is checked that the filename is
 /// of the form `<page>.<section>` or
@@ -423,6 +430,7 @@ fn match_man_page_file(name: &str, section: &str, page: &str) -> bool {
     }
 }
 
+
 /// Check if a string describes a man section,
 /// i. e. is a number or "3p" (Perl Developer's
 /// manual). Used to distinguish between man pages
@@ -437,7 +445,6 @@ fn parse_man_section(section: &str) -> Result<&str, &str> {
     }
 }
 
-
 fn debug_log_command(cmd: &mut Command) -> Result<&mut Command, std::io::Error> {
 
     let mut formatted = vec![b'$', b' '];