Skip to main content

nemo_fabric_cli/
assets.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Embedded assets used by installation-safe CLI experiments.
5
6use std::fs;
7use std::path::{Path, PathBuf};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10/// One embedded file and its path relative to a staged asset root.
11#[derive(Debug, Clone, Copy)]
12pub struct EmbeddedFile {
13    /// Relative path written under the staged root.
14    pub path: &'static str,
15    /// UTF-8 file contents.
16    pub contents: &'static str,
17}
18
19/// Temporary asset root retained for the lifetime of a selected experiment.
20#[derive(Debug)]
21pub struct StagedAssets {
22    path: PathBuf,
23}
24
25impl StagedAssets {
26    /// Stage embedded files and return their temporary base directory.
27    pub fn create(files: &[EmbeddedFile]) -> std::io::Result<Self> {
28        let nonce = SystemTime::now()
29            .duration_since(UNIX_EPOCH)
30            .unwrap_or_default()
31            .as_nanos();
32        let path = std::env::temp_dir().join(format!("nemo-fabric-{}-{nonce}", std::process::id()));
33        fs::create_dir(&path)?;
34        for file in files {
35            let destination = path.join(file.path);
36            if let Some(parent) = destination.parent() {
37                fs::create_dir_all(parent)?;
38            }
39            fs::write(destination, file.contents)?;
40        }
41        Ok(Self { path })
42    }
43
44    /// Return the staged base directory.
45    pub fn path(&self) -> &Path {
46        &self.path
47    }
48}
49
50impl Drop for StagedAssets {
51    fn drop(&mut self) {
52        let _ = fs::remove_dir_all(&self.path);
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn stages_and_removes_embedded_files() {
62        let root_path;
63        {
64            let root = StagedAssets::create(&[EmbeddedFile {
65                path: "nested/value.txt",
66                contents: "value",
67            }])
68            .expect("stage assets");
69            root_path = root.path().to_path_buf();
70            assert_eq!(
71                fs::read_to_string(root.path().join("nested/value.txt")).expect("read asset"),
72                "value"
73            );
74        }
75        assert!(!root_path.exists());
76    }
77}