lanzatool: keep unrelated files when running gc
This commit is contained in:
parent
8cd7452194
commit
b6eb6c1e52
|
@ -35,10 +35,30 @@ impl Roots {
|
|||
}
|
||||
|
||||
pub fn collect_garbage(&self, directory: impl AsRef<Path>) -> Result<()> {
|
||||
self.collect_garbage_with_filter(directory, |_| true)
|
||||
}
|
||||
|
||||
/// Collect garbage with an additional filter.
|
||||
///
|
||||
/// The filter function takes a &Path and returns a bool. The paths for which the filter
|
||||
/// function returns true are considered for garbage collection. This means that _only_ files
|
||||
/// that are unused AND for which the filter function returns true are deleted.
|
||||
pub fn collect_garbage_with_filter<P>(
|
||||
&self,
|
||||
directory: impl AsRef<Path>,
|
||||
mut predicate: P,
|
||||
) -> Result<()>
|
||||
where
|
||||
P: FnMut(&Path) -> bool,
|
||||
{
|
||||
// Find all the paths not used anymore.
|
||||
let entries_not_in_use = WalkDir::new(directory.as_ref())
|
||||
.into_iter()
|
||||
.filter(|e| !self.in_use(e.as_ref().ok()));
|
||||
.filter(|e| !self.in_use(e.as_ref().ok()))
|
||||
.filter(|e| match e.as_ref().ok() {
|
||||
Some(e) => predicate(e.path()),
|
||||
None => false,
|
||||
});
|
||||
|
||||
// Remove all entries not in use.
|
||||
for e in entries_not_in_use {
|
||||
|
@ -148,6 +168,27 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_delete_filtered_unused_files() -> Result<()> {
|
||||
let tmpdir = tempfile::tempdir()?;
|
||||
let rootdir = create_dir(tmpdir.path().join("root"))?;
|
||||
|
||||
let unused_file = create_file(rootdir.join("unused_file"))?;
|
||||
let unused_file_with_prefix = create_file(rootdir.join("prefix_unused_file"))?;
|
||||
|
||||
let mut roots = Roots::new();
|
||||
roots.extend(vec![&rootdir]);
|
||||
roots.collect_garbage_with_filter(&rootdir, |p| {
|
||||
p.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.map_or(false, |n| n.starts_with("prefix_"))
|
||||
})?;
|
||||
|
||||
assert!(unused_file.exists());
|
||||
assert!(!unused_file_with_prefix.exists());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_file(path: PathBuf) -> Result<PathBuf> {
|
||||
fs::File::create(&path)?;
|
||||
Ok(path)
|
||||
|
|
|
@ -61,7 +61,20 @@ impl Installer {
|
|||
};
|
||||
self.install_links(links)?;
|
||||
|
||||
self.gc_roots.collect_garbage(&self.esp)?;
|
||||
// Only collect garbage in these two directories. This way, no files that do not belong to
|
||||
// the NixOS installation are deleted. Lanzatool takes full control over the esp/EFI/nixos
|
||||
// directory and deletes ALL files that it doesn't know about. Dual- or multiboot setups
|
||||
// that need files in this directory will NOT work.
|
||||
self.gc_roots.collect_garbage(self.esp.join("EFI/nixos"))?;
|
||||
// The esp/EFI/Linux directory is assumed to be potentially shared with other distros.
|
||||
// Thus, only files that start with "nixos-" are garbage collected (i.e. potentially
|
||||
// deleted).
|
||||
self.gc_roots
|
||||
.collect_garbage_with_filter(self.esp.join("EFI/Linux"), |p| {
|
||||
p.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.map_or(false, |n| n.starts_with("nixos-"))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -44,6 +44,41 @@ fn keep_only_configured_number_of_generations() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keep_unrelated_files_on_esp() -> Result<()> {
|
||||
let esp_mountpoint = tempdir()?;
|
||||
let tmpdir = tempdir()?;
|
||||
let profiles = tempdir()?;
|
||||
let generation_links: Vec<PathBuf> = [1, 2, 3]
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
common::setup_generation_link(tmpdir.path(), profiles.path(), v)
|
||||
.expect("Failed to setup generation link")
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Install all 3 generations.
|
||||
let output0 = common::lanzaboote_install(0, esp_mountpoint.path(), generation_links.clone())?;
|
||||
assert!(output0.status.success());
|
||||
|
||||
let unrelated_uki = esp_mountpoint.path().join("EFI/Linux/ubuntu.efi");
|
||||
let unrelated_os = esp_mountpoint.path().join("EFI/windows");
|
||||
let unrelated_firmware = esp_mountpoint.path().join("dell");
|
||||
fs::File::create(&unrelated_uki)?;
|
||||
fs::create_dir(&unrelated_os)?;
|
||||
fs::create_dir(&unrelated_firmware)?;
|
||||
|
||||
// Call `lanzatool install` again with a config limit of 2.
|
||||
let output1 = common::lanzaboote_install(2, esp_mountpoint.path(), generation_links)?;
|
||||
assert!(output1.status.success());
|
||||
|
||||
assert!(unrelated_uki.exists());
|
||||
assert!(unrelated_os.exists());
|
||||
assert!(unrelated_firmware.exists());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn count_files(path: &Path) -> Result<usize> {
|
||||
Ok(fs::read_dir(path)?.count())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue