Garbage collect old releases
This commit is contained in:
parent
9e3c130ac9
commit
ea4f516f84
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue