xtask/extendrtests/
with_absolute_path.rs
1use std::error::Error;
2use std::path::Path;
3
4use toml_edit::{DocumentMut, InlineTable, Value};
5use xshell::Shell;
6
7use crate::extendrtests::path_helper::RCompatiblePath;
8
9pub(crate) const R_FOLDER_PATH: &str = "tests/extendrtests";
10
11const RUST_FOLDER_PATH: &str = "tests/extendrtests/src/rust";
12const CARGO_TOML: &str = "Cargo.toml";
13
14#[derive(Debug)]
15pub(crate) struct DocumentMutHandle<'a> {
16 document: Vec<u8>,
17 shell: &'a Shell,
18}
19
20impl Drop for DocumentMutHandle<'_> {
21 fn drop(&mut self) {
22 let _rust_folder = self.shell.push_dir(RUST_FOLDER_PATH);
23 self.shell
24 .write_file(CARGO_TOML, &self.document)
25 .expect("Failed to restore Cargo.toml");
26 }
27}
28
29pub(crate) fn swap_extendr_api_path(shell: &Shell) -> Result<DocumentMutHandle, Box<dyn Error>> {
30 let current_path = shell.current_dir();
31 let _rust_folder = shell.push_dir(RUST_FOLDER_PATH);
32
33 let original_cargo_toml_bytes = read_file_with_line_ending(shell, CARGO_TOML)?;
34
35 let original_cargo_toml: DocumentMut =
36 std::str::from_utf8(&original_cargo_toml_bytes)?.parse()?;
37
38 let mut cargo_toml = original_cargo_toml.clone();
39
40 let extendr_api_entry =
41 get_extendr_api_entry(&mut cargo_toml).ok_or("`extendr-api` not found in Cargo.toml")?;
42
43 let mut replacement = InlineTable::new();
44
45 let item = Value::from(get_replacement_path_extendr_api(¤t_path));
46 replacement.entry("path").or_insert(item);
47 *extendr_api_entry = Value::InlineTable(replacement);
48
49 shell.write_file(CARGO_TOML, cargo_toml.to_string())?;
51 Ok(DocumentMutHandle {
52 document: original_cargo_toml_bytes,
53 shell,
54 })
55}
56
57fn get_replacement_path_extendr_api(path: &Path) -> String {
58 let path = path.adjust_for_r();
59
60 format!("{path}/extendr-api")
61}
62
63fn get_extendr_api_entry(document: &mut DocumentMut) -> Option<&mut Value> {
64 document
65 .get_mut("patch")?
66 .get_mut("crates-io")?
67 .get_mut("extendr-api")?
68 .as_value_mut()
69}
70
71fn read_file_with_line_ending<P: AsRef<Path>>(
72 shell: &Shell,
73 path: P,
74) -> Result<Vec<u8>, Box<dyn Error>> {
75 let file_contents = shell.read_binary_file(path)?;
76 Ok(file_contents)
77}