Garbage collect old releases

This commit is contained in:
Michael Vines 2021-01-29 15:38:54 -08:00 committed by mergify[bot]
parent 9e3c130ac9
commit ea4f516f84
3 changed files with 71 additions and 1 deletions

View File

@ -39,6 +39,7 @@ static BULLET: Emoji = Emoji("• ", "* ");
static SPARKLE: Emoji = Emoji("", ""); static SPARKLE: Emoji = Emoji("", "");
static PACKAGE: Emoji = Emoji("📦 ", ""); static PACKAGE: Emoji = Emoji("📦 ", "");
static INFORMATION: Emoji = Emoji(" ", ""); static INFORMATION: Emoji = Emoji(" ", "");
static RECYCLING: Emoji = Emoji("♻️ ", "");
/// Creates a new process bar for processing that will take an unknown amount of time /// Creates a new process bar for processing that will take an unknown amount of time
fn new_spinner_progress_bar() -> ProgressBar { fn new_spinner_progress_bar() -> ProgressBar {
@ -786,6 +787,61 @@ fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> std::io::Resul
std::os::unix::fs::symlink(src, dst) std::os::unix::fs::symlink(src, dst)
} }
pub fn gc(config_file: &str) -> Result<(), String> {
let config = Config::load(config_file)?;
let entries = fs::read_dir(&config.releases_dir)
.map_err(|err| format!("Unable to read {}: {}", config.releases_dir.display(), err))?;
let mut releases = entries
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
entry
.metadata()
.ok()
.map(|metadata| (entry.path(), metadata))
})
.filter_map(|(release_path, metadata)| {
if metadata.is_dir() {
Some((release_path, metadata))
} else {
None
}
})
.filter_map(|(release_path, metadata)| {
metadata
.modified()
.ok()
.map(|modified_time| (release_path, modified_time))
})
.collect::<Vec<_>>();
releases.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); // order by newest releases
let old_releases = releases.split_off(5); // Delete all but the 5 newest releases
if !old_releases.is_empty() {
let progress_bar = new_spinner_progress_bar();
progress_bar.set_length(old_releases.len() as u64);
progress_bar.set_style(
ProgressStyle::default_bar()
.template(&format!(
"{}{}{}",
"{spinner:.green} ",
RECYCLING,
"Removing old releases [{bar:40.cyan/blue}] {pos}/{len} ({eta})"
))
.progress_chars("=> "),
);
for (release, _modified_type) in old_releases {
progress_bar.inc(1);
let _ = fs::remove_dir_all(&release);
}
progress_bar.finish_and_clear();
}
Ok(())
}
pub fn update(config_file: &str) -> Result<bool, String> { pub fn update(config_file: &str) -> Result<bool, String> {
let mut config = Config::load(config_file)?; let mut config = Config::load(config_file)?;
let update_manifest = info(config_file, false, false)?; let update_manifest = info(config_file, false, false)?;
@ -917,6 +973,13 @@ pub fn update(config_file: &str) -> Result<bool, String> {
return Err(format!("Incompatible update target: {}", release_target)); return Err(format!("Incompatible update target: {}", release_target));
} }
// Trigger an update to the modification time for `release_dir`
{
let path = &release_dir.join(".touch");
let _ = fs::OpenOptions::new().create(true).write(true).open(path);
let _ = fs::remove_file(path);
}
let _ = fs::remove_dir_all(config.active_release_dir()); let _ = fs::remove_dir_all(config.active_release_dir());
symlink_dir( symlink_dir(
release_dir.join("solana-release"), release_dir.join("solana-release"),
@ -932,6 +995,7 @@ pub fn update(config_file: &str) -> Result<bool, String> {
})?; })?;
config.save(config_file)?; config.save(config_file)?;
gc(config_file)?;
println!(" {}{}", SPARKLE, style("Update successful").bold()); println!(" {}{}", SPARKLE, style("Update successful").bold());
Ok(true) Ok(true)

View File

@ -18,7 +18,7 @@ pub struct Config {
pub current_update_manifest: Option<UpdateManifest>, pub current_update_manifest: Option<UpdateManifest>,
pub update_poll_secs: u64, pub update_poll_secs: u64,
pub explicit_release: Option<ExplicitRelease>, pub explicit_release: Option<ExplicitRelease>,
releases_dir: PathBuf, pub releases_dir: PathBuf,
active_release_dir: PathBuf, active_release_dir: PathBuf,
} }

View File

@ -208,6 +208,11 @@ pub fn main() -> Result<(), String> {
.help("Keypair file for the update manifest (/path/to/keypair.json)"), .help("Keypair file for the update manifest (/path/to/keypair.json)"),
), ),
) )
.subcommand(
SubCommand::with_name("gc")
.about("Delete older releases from the install cache to reclaim disk space")
.setting(AppSettings::DisableVersion),
)
.subcommand( .subcommand(
SubCommand::with_name("update") SubCommand::with_name("update")
.about("Checks for an update, and if available downloads and applies it") .about("Checks for an update, and if available downloads and applies it")
@ -255,6 +260,7 @@ pub fn main() -> Result<(), String> {
update_manifest_keypair_file, update_manifest_keypair_file,
) )
} }
("gc", Some(_matches)) => command::gc(config_file),
("update", Some(_matches)) => command::update(config_file).map(|_| ()), ("update", Some(_matches)) => command::update(config_file).map(|_| ()),
("run", Some(matches)) => { ("run", Some(matches)) => {
let program_name = matches.value_of("program_name").unwrap(); let program_name = matches.value_of("program_name").unwrap();