artifactize_core/platform/
interaction.rs1use std::{io, path::Path, sync::OnceLock};
3
4pub(crate) fn paths_equal(left: &Path, right: &Path) -> bool {
7 let identity = |path: &Path| {
8 super::open_directory(path)
9 .or_else(|_| super::open_regular(path))
10 .and_then(|file| super::file_identity(&file))
11 };
12 match (identity(left), identity(right)) {
13 (Ok(left), Ok(right)) => left == right,
14 _ => left == right,
15 }
16}
17
18pub(crate) fn is_within(path: &Path, root: &Path) -> bool {
20 path.ancestors().any(|ancestor| paths_equal(ancestor, root))
21}
22
23pub(crate) fn label() -> &'static str {
25 static LABEL: OnceLock<String> = OnceLock::new();
26 LABEL.get_or_init(|| format!("{} {}", std::env::consts::OS, std::env::consts::ARCH))
27}
28
29pub fn selected_editor() -> String {
30 ["VISUAL", "EDITOR"]
31 .into_iter()
32 .find_map(|name| {
33 super::environment::var_text(name).filter(|value| !value.trim().is_empty())
34 })
35 .unwrap_or_else(|| super::DEFAULT_EDITOR.into())
36}
37
38pub fn private_temp_file(prefix: &str) -> io::Result<PrivateTempFile> {
40 let root = super::canonicalize(&std::env::temp_dir())?;
42 let directory = super::private_tempdir_in(prefix, &root)?;
43 let file = tempfile::Builder::new()
44 .prefix(prefix)
45 .suffix(".json")
46 .tempfile_in(directory.path())?;
47 super::restrict_file(file.as_file())?;
48 Ok(PrivateTempFile {
49 file,
50 _directory: directory,
51 })
52}
53
54pub(crate) fn private_anonymous_file() -> io::Result<std::fs::File> {
57 let file = tempfile::tempfile()?;
58 super::restrict_file(&file)?;
59 Ok(file)
60}
61
62pub async fn run_editor(command: &str, file: &Path) -> io::Result<()> {
64 let status = super::editor(command, file).status().await?;
65 if status.success() {
66 Ok(())
67 } else {
68 Err(io::Error::other(format!(
69 "The editor exited unsuccessfully ({status}); nothing was submitted."
70 )))
71 }
72}
73
74pub struct PrivateTempFile {
76 file: tempfile::NamedTempFile,
77 _directory: super::PrivateTempDir,
78}
79impl PrivateTempFile {
80 pub fn path(&self) -> &Path {
81 self.file.path()
82 }
83}