2020-06-10 11:51:52 +03:00
|
|
|
use crate::execution_context::ExecutionContext;
|
|
|
|
|
use crate::executor::CommandExt;
|
|
|
|
|
use crate::terminal::print_separator;
|
2020-06-16 21:02:50 +03:00
|
|
|
use crate::{error::SkipStep, utils};
|
2020-06-10 11:51:52 +03:00
|
|
|
use anyhow::Result;
|
2020-06-25 08:37:29 +03:00
|
|
|
use log::{debug, error};
|
2020-06-10 11:51:52 +03:00
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
use std::process::Command;
|
2020-06-16 21:02:50 +03:00
|
|
|
use std::{fmt::Display, rc::Rc, str::FromStr};
|
2020-06-10 11:51:52 +03:00
|
|
|
use strum::EnumString;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, EnumString)]
|
|
|
|
|
#[strum(serialize_all = "lowercase")]
|
|
|
|
|
enum BoxStatus {
|
|
|
|
|
PowerOff,
|
|
|
|
|
Running,
|
2020-06-12 15:35:39 +03:00
|
|
|
Saved,
|
2020-06-13 07:40:03 +03:00
|
|
|
Aborted,
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl BoxStatus {
|
|
|
|
|
fn powered_on(self) -> bool {
|
2020-10-24 14:46:38 -05:00
|
|
|
matches!(self, BoxStatus::Running)
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-06-16 21:02:50 +03:00
|
|
|
pub struct VagrantBox {
|
2020-12-01 08:59:59 +02:00
|
|
|
path: Rc<Path>,
|
2020-06-10 11:51:52 +03:00
|
|
|
name: String,
|
2020-06-16 21:02:50 +03:00
|
|
|
initial_status: BoxStatus,
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
|
|
|
|
|
2020-06-16 21:02:50 +03:00
|
|
|
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 {
|
2020-06-10 11:51:52 +03:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2020-06-16 21:02:50 +03:00
|
|
|
write!(f, "{} @ {}", self.name, self.path.display())
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Vagrant {
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Vagrant {
|
2021-01-07 10:03:20 +02:00
|
|
|
fn get_boxes(&self, directory: &str) -> Result<Vec<VagrantBox>> {
|
2020-12-01 08:59:59 +02:00
|
|
|
let path: Rc<Path> = Path::new(directory).into();
|
2020-06-16 21:02:50 +03:00
|
|
|
|
2020-06-10 11:51:52 +03:00
|
|
|
let output = Command::new(&self.path)
|
|
|
|
|
.arg("status")
|
|
|
|
|
.current_dir(directory)
|
|
|
|
|
.check_output()?;
|
|
|
|
|
debug!("Vagrant output in {}: {}", directory, output);
|
|
|
|
|
|
|
|
|
|
let boxes = output
|
|
|
|
|
.split('\n')
|
|
|
|
|
.skip(2)
|
|
|
|
|
.take_while(|line| !(line.is_empty() || line.starts_with('\r')))
|
|
|
|
|
.map(|line| {
|
|
|
|
|
debug!("Vagrant line: {:?}", line);
|
|
|
|
|
let mut elements = line.split_whitespace();
|
2020-06-16 21:02:50 +03:00
|
|
|
|
|
|
|
|
let name = elements.next().unwrap().to_string();
|
|
|
|
|
let initial_status = BoxStatus::from_str(elements.next().unwrap()).unwrap();
|
|
|
|
|
|
2020-06-10 11:51:52 +03:00
|
|
|
let vagrant_box = VagrantBox {
|
2020-06-16 21:02:50 +03:00
|
|
|
name,
|
|
|
|
|
path: path.clone(),
|
|
|
|
|
initial_status,
|
2020-06-10 11:51:52 +03:00
|
|
|
};
|
2020-06-16 21:02:50 +03:00
|
|
|
debug!("{:?}", vagrant_box);
|
|
|
|
|
vagrant_box
|
2020-06-10 11:51:52 +03:00
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
Ok(boxes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn temporary_power_on<'a>(
|
|
|
|
|
&'a self,
|
|
|
|
|
vagrant_box: &'a VagrantBox,
|
|
|
|
|
ctx: &'a ExecutionContext,
|
|
|
|
|
) -> Result<TemporaryPowerOn<'a>> {
|
2020-06-16 21:02:50 +03:00
|
|
|
TemporaryPowerOn::create(&self.path, vagrant_box, ctx)
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct TemporaryPowerOn<'a> {
|
|
|
|
|
vagrant: &'a Path,
|
2020-06-16 21:02:50 +03:00
|
|
|
vagrant_box: &'a VagrantBox,
|
2020-06-10 11:51:52 +03:00
|
|
|
ctx: &'a ExecutionContext<'a>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> TemporaryPowerOn<'a> {
|
2020-06-16 21:02:50 +03:00
|
|
|
fn create(vagrant: &'a Path, vagrant_box: &'a VagrantBox, ctx: &'a ExecutionContext<'a>) -> Result<Self> {
|
|
|
|
|
let subcommand = match vagrant_box.initial_status {
|
2020-06-13 07:40:03 +03:00
|
|
|
BoxStatus::PowerOff | BoxStatus::Aborted => "up",
|
2020-06-12 15:35:39 +03:00
|
|
|
BoxStatus::Saved => "resume",
|
2020-06-13 07:40:03 +03:00
|
|
|
BoxStatus::Running => unreachable!(),
|
2020-06-12 15:35:39 +03:00
|
|
|
};
|
|
|
|
|
|
2020-06-10 11:51:52 +03:00
|
|
|
ctx.run_type()
|
|
|
|
|
.execute(vagrant)
|
2021-10-28 22:05:35 +03:00
|
|
|
.args(&[subcommand, &vagrant_box.name])
|
2020-12-01 08:59:59 +02:00
|
|
|
.current_dir(vagrant_box.path.clone())
|
2020-06-10 11:51:52 +03:00
|
|
|
.check_run()?;
|
|
|
|
|
Ok(TemporaryPowerOn {
|
|
|
|
|
vagrant,
|
|
|
|
|
vagrant_box,
|
|
|
|
|
ctx,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Drop for TemporaryPowerOn<'a> {
|
|
|
|
|
fn drop(&mut self) {
|
2020-06-13 07:44:53 +03:00
|
|
|
let subcommand = if self.ctx.config().vagrant_always_suspend().unwrap_or(false) {
|
|
|
|
|
"suspend"
|
|
|
|
|
} else {
|
2020-06-16 21:02:50 +03:00
|
|
|
match self.vagrant_box.initial_status {
|
2020-06-13 07:44:53 +03:00
|
|
|
BoxStatus::PowerOff | BoxStatus::Aborted => "halt",
|
|
|
|
|
BoxStatus::Saved => "suspend",
|
|
|
|
|
BoxStatus::Running => unreachable!(),
|
|
|
|
|
}
|
2020-06-12 15:35:39 +03:00
|
|
|
};
|
|
|
|
|
|
2020-06-17 09:33:45 +03:00
|
|
|
println!();
|
2020-06-10 11:51:52 +03:00
|
|
|
self.ctx
|
|
|
|
|
.run_type()
|
|
|
|
|
.execute(self.vagrant)
|
2021-10-28 22:05:35 +03:00
|
|
|
.args(&[subcommand, &self.vagrant_box.name])
|
2020-12-01 08:59:59 +02:00
|
|
|
.current_dir(self.vagrant_box.path.clone())
|
2020-06-10 11:51:52 +03:00
|
|
|
.check_run()
|
|
|
|
|
.ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 21:02:50 +03:00
|
|
|
pub fn collect_boxes(ctx: &ExecutionContext) -> Result<Vec<VagrantBox>> {
|
2020-08-21 23:04:36 +03:00
|
|
|
let directories = utils::require_option(
|
|
|
|
|
ctx.config().vagrant_directories(),
|
|
|
|
|
String::from("No Vagrant directories were specified in the configuration file"),
|
|
|
|
|
)?;
|
2020-06-10 11:51:52 +03:00
|
|
|
let vagrant = Vagrant {
|
|
|
|
|
path: utils::require("vagrant")?,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
print_separator("Vagrant");
|
2020-06-16 21:02:50 +03:00
|
|
|
println!("Collecting Vagrant boxes");
|
|
|
|
|
|
|
|
|
|
let mut result = Vec::new();
|
2020-06-10 11:51:52 +03:00
|
|
|
|
|
|
|
|
for directory in directories {
|
2020-06-25 08:37:29 +03:00
|
|
|
match vagrant.get_boxes(directory) {
|
|
|
|
|
Ok(mut boxes) => {
|
|
|
|
|
result.append(&mut boxes);
|
|
|
|
|
}
|
|
|
|
|
Err(e) => error!("Error collecting vagrant boxes from {}: {}", directory, e),
|
|
|
|
|
};
|
2020-06-16 21:02:50 +03:00
|
|
|
}
|
2020-06-10 11:51:52 +03:00
|
|
|
|
2020-06-16 21:02:50 +03:00
|
|
|
Ok(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) -> Result<()> {
|
|
|
|
|
let vagrant = Vagrant {
|
|
|
|
|
path: utils::require("vagrant")?,
|
|
|
|
|
};
|
2020-06-10 11:51:52 +03:00
|
|
|
|
2020-06-16 21:02:50 +03:00
|
|
|
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)) {
|
2020-08-21 23:04:36 +03:00
|
|
|
return Err(SkipStep(format!("Skipping powered off box {}", vagrant_box)).into());
|
2020-06-16 21:02:50 +03:00
|
|
|
} else {
|
|
|
|
|
print_separator(seperator);
|
2021-09-02 07:27:09 +03:00
|
|
|
_poweron = Some(vagrant.temporary_power_on(vagrant_box, ctx)?);
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
2020-06-16 21:02:50 +03:00
|
|
|
} else {
|
|
|
|
|
print_separator(seperator);
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|
2020-06-16 21:02:50 +03:00
|
|
|
let mut command = format!("env TOPGRADE_PREFIX={} topgrade", vagrant_box.smart_name());
|
|
|
|
|
if ctx.config().yes() {
|
2020-07-01 20:54:31 +03:00
|
|
|
command.push_str(" -y");
|
2020-06-16 21:02:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.run_type()
|
|
|
|
|
.execute(&vagrant.path)
|
2020-12-01 08:59:59 +02:00
|
|
|
.current_dir(&vagrant_box.path)
|
2021-10-28 22:05:35 +03:00
|
|
|
.args(&["ssh", "-c", &command])
|
2020-06-16 21:02:50 +03:00
|
|
|
.check_run()
|
2020-06-10 11:51:52 +03:00
|
|
|
}
|