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<()> {
|
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.
|
// Find all the paths not used anymore.
|
||||||
let entries_not_in_use = WalkDir::new(directory.as_ref())
|
let entries_not_in_use = WalkDir::new(directory.as_ref())
|
||||||
.into_iter()
|
.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.
|
// Remove all entries not in use.
|
||||||
for e in entries_not_in_use {
|
for e in entries_not_in_use {
|
||||||
|
@ -148,6 +168,27 @@ mod tests {
|
||||||
Ok(())
|
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> {
|
fn create_file(path: PathBuf) -> Result<PathBuf> {
|
||||||
fs::File::create(&path)?;
|
fs::File::create(&path)?;
|
||||||
Ok(path)
|
Ok(path)
|
||||||
|
|
|
@ -61,7 +61,20 @@ impl Installer {
|
||||||
};
|
};
|
||||||
self.install_links(links)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,41 @@ fn keep_only_configured_number_of_generations() -> Result<()> {
|
||||||
Ok(())
|
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> {
|
fn count_files(path: &Path) -> Result<usize> {
|
||||||
Ok(fs::read_dir(path)?.count())
|
Ok(fs::read_dir(path)?.count())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue