pkgs/runner/
unload.rs

1use std::path::PathBuf;
2
3use super::{Runner, RunnerError, UnloadError};
4use crate::logger::LoggerOutput;
5use crate::trace::PkgTrace;
6
7impl<O: LoggerOutput> Runner<O> {
8    pub fn unload_module(&mut self, name: &str, trace: &PkgTrace) -> Result<(), RunnerError> {
9        self.logger.unload_module(name);
10        self.unload_module_inner(trace)
11            .map_err(|e| RunnerError::UnloadModuleError {
12                source: e,
13                module: name.to_string(),
14            })
15    }
16
17    fn unload_module_inner(&mut self, trace: &PkgTrace) -> Result<(), UnloadError> {
18        let pkg_dir = self.cwd.join(&trace.directory);
19
20        for (src, dst) in &trace.maps {
21            let dst_path = PathBuf::from(dst);
22            if !dst_path.exists() {
23                return Err(UnloadError::DstNotFound {
24                    src: src.clone(),
25                    dst: dst_path,
26                });
27            }
28            if !dst_path.is_symlink() {
29                return Err(UnloadError::DstNotSymlink {
30                    src: src.clone(),
31                    dst: dst_path,
32                });
33            }
34
35            let src_path = pkg_dir.join(src);
36            self.remove_symlink(src_path, dst_path)?;
37        }
38
39        Ok(())
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use std::fs;
46
47    use super::*;
48    use crate::test_utils::prelude::*;
49
50    fn setup() -> Result<(TempDir, PkgTrace, Runner<NullOutput>)> {
51        let (td, pkg, mut runner) = common_local_pkg()?;
52        let trace = runner.load_module(&pkg, None)?;
53        let runner = common_runner(td.path());
54        Ok((td, trace, runner))
55    }
56
57    #[gtest]
58    fn it_works() -> Result<()> {
59        let (td, trace, mut runner) = setup()?;
60        runner.unload_module("test_package", &trace)?;
61
62        expect_pred!(!td.join(DST_FILE_PATH).exists());
63        expect_pred!(!td.join(DST_DIR_PATH).exists());
64
65        let messages = runner.messages();
66        expect_eq!(messages.len(), 3);
67        expect_that!(messages[0], pat!(LogMessage::UnloadModule("test_package")));
68        expect_that!(
69            messages,
70            contains(pat!(LogMessage::RemoveSymlink {
71                src: &td.join(SRC_DIR_PATH),
72                dst: &td.join(DST_DIR_PATH),
73            }))
74        );
75        expect_that!(
76            messages,
77            contains(pat!(LogMessage::RemoveSymlink {
78                src: &td.join(SRC_FILE_PATH),
79                dst: &td.join(DST_FILE_PATH),
80            }))
81        );
82
83        Ok(())
84    }
85
86    #[gtest]
87    fn dst_not_exists() -> Result<()> {
88        let (td, trace, mut runner) = setup()?;
89        fs::remove_file(td.join(DST_FILE_PATH))?;
90
91        let err = runner
92            .unload_module("test_package", &trace)
93            .unwrap_err()
94            .unwrap_unload();
95        expect_that!(
96            err,
97            pat!(UnloadError::DstNotFound {
98                src: "src_file",
99                dst: &td.join(DST_FILE_PATH)
100            })
101        );
102
103        Ok(())
104    }
105
106    #[gtest]
107    fn dst_is_not_symlink() -> Result<()> {
108        let (td, trace, mut runner) = setup()?;
109        fs::remove_file(td.join(DST_FILE_PATH))?;
110        fs::write(td.join(DST_FILE_PATH), "not_a_symlink")?;
111
112        let err = runner
113            .unload_module("test_package", &trace)
114            .unwrap_err()
115            .unwrap_unload();
116        expect_that!(
117            err,
118            pat!(UnloadError::DstNotSymlink {
119                src: "src_file",
120                dst: &td.join(DST_FILE_PATH)
121            })
122        );
123
124        Ok(())
125    }
126}