Make Vagrant boxes into seperated steps

This commit is contained in:
Roey Darwish Dror
2020-06-16 21:02:50 +03:00
parent 4d8dc69e7f
commit f0fcb0f4cd
2 changed files with 81 additions and 64 deletions

View File

@@ -390,7 +390,13 @@ fn run() -> Result<()> {
} }
if config.should_run(Step::Vagrant) { if config.should_run(Step::Vagrant) {
runner.execute("Vagrant", || vagrant::topgrade_vagrant_boxes(&ctx))?; if let Ok(boxes) = vagrant::collect_boxes(&ctx) {
for vagrant_box in boxes {
runner.execute(format!("Vagrant ({})", vagrant_box.smart_name()), || {
vagrant::topgrade_vagrant_box(&ctx, &vagrant_box)
})?;
}
}
} }
if !runner.report().data().is_empty() { if !runner.report().data().is_empty() {

View File

@@ -1,12 +1,12 @@
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::executor::CommandExt; use crate::executor::CommandExt;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils; use crate::{error::SkipStep, utils};
use anyhow::Result; use anyhow::Result;
use log::debug; use log::debug;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, rc::Rc, str::FromStr};
use strum::EnumString; use strum::EnumString;
#[derive(Debug, Copy, Clone, EnumString)] #[derive(Debug, Copy, Clone, EnumString)]
@@ -28,14 +28,25 @@ impl BoxStatus {
} }
#[derive(Debug)] #[derive(Debug)]
struct VagrantBox<'a> { pub struct VagrantBox {
path: &'a str, path: Rc<PathBuf>,
name: String, name: String,
initial_status: BoxStatus,
} }
impl<'a> Display for VagrantBox<'a> { impl VagrantBox {
pub fn smart_name(&self) -> &str {
if self.name == "default" {
self.path.file_name().unwrap().to_str().unwrap()
} else {
&self.name
}
}
}
impl Display for VagrantBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} @ {}", self.name, self.path) write!(f, "{} @ {}", self.name, self.path.display())
} }
} }
@@ -44,7 +55,9 @@ struct Vagrant {
} }
impl Vagrant { impl Vagrant {
fn get_boxes<'a>(&self, directory: &'a str) -> Result<Vec<(VagrantBox<'a>, BoxStatus)>> { fn get_boxes<'a>(&self, directory: &'a str) -> Result<Vec<VagrantBox>> {
let path = Rc::new(PathBuf::from(directory));
let output = Command::new(&self.path) let output = Command::new(&self.path)
.arg("status") .arg("status")
.current_dir(directory) .current_dir(directory)
@@ -58,13 +71,17 @@ impl Vagrant {
.map(|line| { .map(|line| {
debug!("Vagrant line: {:?}", line); debug!("Vagrant line: {:?}", line);
let mut elements = line.split_whitespace(); let mut elements = line.split_whitespace();
let name = elements.next().unwrap().to_string();
let initial_status = BoxStatus::from_str(elements.next().unwrap()).unwrap();
let vagrant_box = VagrantBox { let vagrant_box = VagrantBox {
name: elements.next().unwrap().to_string(), name,
path: directory, path: path.clone(),
initial_status,
}; };
let box_status = BoxStatus::from_str(elements.next().unwrap()).unwrap(); debug!("{:?}", vagrant_box);
debug!("{:?}: {:?}", vagrant_box, box_status); vagrant_box
(vagrant_box, box_status)
}) })
.collect(); .collect();
@@ -74,43 +91,34 @@ impl Vagrant {
fn temporary_power_on<'a>( fn temporary_power_on<'a>(
&'a self, &'a self,
vagrant_box: &'a VagrantBox, vagrant_box: &'a VagrantBox,
status: BoxStatus,
ctx: &'a ExecutionContext, ctx: &'a ExecutionContext,
) -> Result<TemporaryPowerOn<'a>> { ) -> Result<TemporaryPowerOn<'a>> {
TemporaryPowerOn::create(&self.path, vagrant_box, status, ctx) TemporaryPowerOn::create(&self.path, vagrant_box, ctx)
} }
} }
struct TemporaryPowerOn<'a> { struct TemporaryPowerOn<'a> {
vagrant: &'a Path, vagrant: &'a Path,
vagrant_box: &'a VagrantBox<'a>, vagrant_box: &'a VagrantBox,
status: BoxStatus,
ctx: &'a ExecutionContext<'a>, ctx: &'a ExecutionContext<'a>,
} }
impl<'a> TemporaryPowerOn<'a> { impl<'a> TemporaryPowerOn<'a> {
fn create( fn create(vagrant: &'a Path, vagrant_box: &'a VagrantBox, ctx: &'a ExecutionContext<'a>) -> Result<Self> {
vagrant: &'a Path, let subcommand = match vagrant_box.initial_status {
vagrant_box: &'a VagrantBox<'a>,
status: BoxStatus,
ctx: &'a ExecutionContext<'a>,
) -> Result<Self> {
let subcommand = match status {
BoxStatus::PowerOff | BoxStatus::Aborted => "up", BoxStatus::PowerOff | BoxStatus::Aborted => "up",
BoxStatus::Saved => "resume", BoxStatus::Saved => "resume",
BoxStatus::Running => unreachable!(), BoxStatus::Running => unreachable!(),
}; };
println!("Powering on {}", vagrant_box);
ctx.run_type() ctx.run_type()
.execute(vagrant) .execute(vagrant)
.args(&[subcommand, &vagrant_box.name]) .args(&[subcommand, &vagrant_box.name])
.current_dir(vagrant_box.path) .current_dir(vagrant_box.path.as_path())
.check_run()?; .check_run()?;
Ok(TemporaryPowerOn { Ok(TemporaryPowerOn {
vagrant, vagrant,
vagrant_box, vagrant_box,
status,
ctx, ctx,
}) })
} }
@@ -121,65 +129,68 @@ impl<'a> Drop for TemporaryPowerOn<'a> {
let subcommand = if self.ctx.config().vagrant_always_suspend().unwrap_or(false) { let subcommand = if self.ctx.config().vagrant_always_suspend().unwrap_or(false) {
"suspend" "suspend"
} else { } else {
match self.status { match self.vagrant_box.initial_status {
BoxStatus::PowerOff | BoxStatus::Aborted => "halt", BoxStatus::PowerOff | BoxStatus::Aborted => "halt",
BoxStatus::Saved => "suspend", BoxStatus::Saved => "suspend",
BoxStatus::Running => unreachable!(), BoxStatus::Running => unreachable!(),
} }
}; };
println!("Powering off {}", self.vagrant_box);
self.ctx self.ctx
.run_type() .run_type()
.execute(self.vagrant) .execute(self.vagrant)
.args(&[subcommand, &self.vagrant_box.name]) .args(&[subcommand, &self.vagrant_box.name])
.current_dir(self.vagrant_box.path) .current_dir(self.vagrant_box.path.as_path())
.check_run() .check_run()
.ok(); .ok();
} }
} }
pub fn topgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> { pub fn collect_boxes(ctx: &ExecutionContext) -> Result<Vec<VagrantBox>> {
let directories = utils::require_option(ctx.config().vagrant_directories())?; let directories = utils::require_option(ctx.config().vagrant_directories())?;
let vagrant = Vagrant { let vagrant = Vagrant {
path: utils::require("vagrant")?, path: utils::require("vagrant")?,
}; };
print_separator("Vagrant"); print_separator("Vagrant");
println!("Collecting Vagrant boxes");
let mut result = Vec::new();
for directory in directories { for directory in directories {
let boxes = vagrant.get_boxes(directory)?; let mut boxes = vagrant.get_boxes(directory)?;
debug!("{:?}", boxes); result.append(&mut boxes);
for (vagrant_box, status) in boxes {
let mut _poweron = None;
if !status.powered_on() {
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
debug!("Skipping powered off box {}", vagrant_box);
continue;
} else {
_poweron = Some(vagrant.temporary_power_on(&vagrant_box, status, ctx)?);
}
}
println!("Running Topgrade in {}", vagrant_box);
let pathbuf = PathBuf::from(directory);
let prefix = if vagrant_box.name == "default" {
pathbuf.file_name().unwrap().to_str().unwrap()
} else {
&vagrant_box.name
};
let mut command = format!("env TOPGRADE_PREFIX={} topgrade", prefix);
if ctx.config().yes() {
command.push_str(" -y");
}
ctx.run_type()
.execute(&vagrant.path)
.current_dir(directory)
.args(&["ssh", "-c", &command])
.check_run()?;
}
} }
Ok(())
Ok(result)
}
pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) -> Result<()> {
let vagrant = Vagrant {
path: utils::require("vagrant")?,
};
let seperator = format!("Vagrant ({})", vagrant_box.smart_name());
let mut _poweron = None;
if !vagrant_box.initial_status.powered_on() {
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
debug!("Skipping powered off box {}", vagrant_box);
return Err(SkipStep.into());
} else {
print_separator(seperator);
_poweron = Some(vagrant.temporary_power_on(&vagrant_box, ctx)?);
}
} else {
print_separator(seperator);
}
let mut command = format!("env TOPGRADE_PREFIX={} topgrade", vagrant_box.smart_name());
if ctx.config().yes() {
command.push_str(" -y");
}
ctx.run_type()
.execute(&vagrant.path)
.current_dir(&vagrant_box.path.as_path())
.args(&["ssh", "-c", &command])
.check_run()
} }