From 3b1106c648c7d63d5ca39c68c1cf29fabd2a48d7 Mon Sep 17 00:00:00 2001
From: Iago Bonnici <iago.bonnici@umontpellier.fr>
Date: Wed, 24 Jul 2024 13:29:29 +0200
Subject: [PATCH] Resolve file paths relatively to the config file.

---
 src/bin/aphid/main.rs |  1 -
 src/config.rs         |  1 +
 src/config/check.rs   | 29 +++++++++++++++++++++++++----
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/bin/aphid/main.rs b/src/bin/aphid/main.rs
index 5603aef..aca3e73 100644
--- a/src/bin/aphid/main.rs
+++ b/src/bin/aphid/main.rs
@@ -29,7 +29,6 @@ use crate::display_tree_analysis::display_geometrical_tree_analysis;
 #[command(author, version, about, long_about = None)]
 struct Args {
     /// Path to the config file.
-    #[arg(short, long)]
     config: PathBuf,
 }
 
diff --git a/src/config.rs b/src/config.rs
index 5caa52d..88f1932 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -22,6 +22,7 @@ mod deserialize;
 // The final value handed out to user.
 pub struct Config {
     // Path to the gene trees data file.
+    // If relative: relative to the config file.
     pub trees: PathBuf,
 
     // Names of the species of interest.
diff --git a/src/config/check.rs b/src/config/check.rs
index 14e1abc..d97ae99 100644
--- a/src/config/check.rs
+++ b/src/config/check.rs
@@ -60,11 +60,32 @@ impl Config {
             );
         }
 
+        let search = (&raw).try_into()?;
+        let taxa = raw.taxa._try_into(interner)?;
+
+        // Resolve relative paths relatively to the config file.
+        let mut trees = raw.taxa.trees;
+        if !trees.is_absolute() {
+            let mut path = path
+                .parent()
+                .unwrap_or_else(|| {
+                    panic!(
+                        "Config file has been read but its path has no parent: {}",
+                        path.to_string_lossy()
+                    )
+                })
+                .to_owned();
+            path.push(trees);
+            trees = path
+                .canonicalize()
+                .with_context(|_| CanonicalizeErr { path })?;
+        }
+
         // Most checks implemented within `TryFrom` trait.
         Ok(Config {
-            search: (&raw).try_into()?,
-            taxa: raw.taxa._try_into(interner)?,
-            trees: raw.taxa.trees,
+            search,
+            taxa,
+            trees,
             unresolved_length: raw.unresolved_length,
             filters: if let Some(ref raw) = raw.filters {
                 raw.try_into()?
@@ -640,7 +661,7 @@ pub enum Error {
     Config { mess: String },
     #[snafu(transparent)]
     Optim { source: optim::Error },
-    #[snafu(display("Could not canonicalize path: {:?}.", path.to_string_lossy()))]
+    #[snafu(display("Could not canonicalize path: {:?}:\n{source}", path.to_string_lossy()))]
     Canonicalize {
         source: std::io::Error,
         path: PathBuf,
-- 
GitLab