conjure_oxide/
find_conjure.rs

1use anyhow::{anyhow, bail, Result};
2use versions::Versioning;
3
4const CONJURE_MIN_VERSION: &str = "2.5.1";
5const CORRECT_FIRST_LINE: &str = "Conjure: The Automated Constraint Modelling Tool";
6
7/// Checks if the conjure executable is present in PATH and if it is the correct version.
8/// Returns () on success and an error on failure.
9pub fn conjure_executable() -> Result<()> {
10    let mut cmd = std::process::Command::new("conjure");
11    let output = cmd.arg("--version").output()?;
12    let stdout = String::from_utf8(output.stdout)?;
13    let stderr = String::from_utf8(output.stderr)?;
14
15    if !stderr.is_empty() {
16        bail!("'conjure' results in error: ".to_string() + &stderr);
17    }
18    let first = stdout
19        .lines()
20        .next()
21        .ok_or(anyhow!("Could not read stdout"))?;
22    if first != CORRECT_FIRST_LINE {
23        let path = std::env::var("PATH")?;
24        let paths = std::env::split_paths(&path);
25        let num_conjures = paths.filter(|path| path.join("conjure").exists()).count();
26        if num_conjures > 1 {
27            bail!(
28                "Conjure may be present in PATH after a conflicting name. \
29            Make sure to prepend the correct path to Conjure to PATH."
30            )
31        } else {
32            bail!("The correct Conjure executable is not present in PATH.")
33        }
34    }
35    let version_line = stdout
36        .lines()
37        .nth(1)
38        .ok_or(anyhow!("Could not read Conjure's stdout"))?;
39
40    let version = match version_line.strip_prefix("Release version ") {
41        Some(v) => Ok(v),
42        None => match version_line.strip_prefix("Conjure v") {
43            // New format: Conjure v2.5.1 (Repository version ...)
44            Some(v) => v.split_whitespace().next().ok_or(anyhow!(
45                "Could not read Conjure's version from: {}",
46                version_line
47            )),
48            None => Err(anyhow!(
49                "Could not read Conjure's version from: {}",
50                version_line
51            )),
52        },
53    }?;
54
55    if Versioning::new(version) < Versioning::new(CONJURE_MIN_VERSION) {
56        bail!(
57            "Conjure version is too old (< {}): {}",
58            CONJURE_MIN_VERSION,
59            version
60        );
61    }
62    Ok(())
63}