2021-09-07 13:22:46 +02:00
|
|
|
use std::fmt;
|
2021-08-31 01:40:29 +02:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::BufRead;
|
|
|
|
use std::io::BufReader;
|
|
|
|
use std::io::Write;
|
2021-08-30 00:28:12 +02:00
|
|
|
|
|
|
|
use tui::style::{Color, Style};
|
|
|
|
use tui::widgets::{Block, Borders, List, ListState};
|
|
|
|
|
2021-09-13 15:54:37 +02:00
|
|
|
use crate::repo;
|
2021-08-30 00:28:12 +02:00
|
|
|
use crate::ui::State;
|
|
|
|
|
2021-09-07 15:29:20 +02:00
|
|
|
#[derive(Debug)]
|
2021-08-30 00:28:12 +02:00
|
|
|
pub enum Error {
|
|
|
|
NoneSelected,
|
|
|
|
Parsing(String),
|
|
|
|
}
|
|
|
|
|
2021-09-07 13:22:46 +02:00
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Error::NoneSelected => write!(f, "None selected"),
|
|
|
|
Error::Parsing(s) => write!(f, "Parsing error: {}", s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 00:28:12 +02:00
|
|
|
pub struct ServiceSwitcher {
|
|
|
|
list: Vec<String>,
|
|
|
|
state: ListState,
|
2021-09-01 18:28:17 +02:00
|
|
|
changed: bool,
|
2021-08-30 00:28:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ServiceSwitcher {
|
|
|
|
pub fn new() -> Self {
|
2021-08-31 01:40:29 +02:00
|
|
|
let list = match File::open("docker-compose.yml") {
|
2021-09-01 20:03:49 +02:00
|
|
|
Err(e) => vec![format!("No docker-compose.yml found: {}", e)],
|
2021-08-31 01:40:29 +02:00
|
|
|
Ok(file) => {
|
|
|
|
let buf = BufReader::new(file);
|
|
|
|
buf.lines()
|
|
|
|
.map(|l| l.expect("Could not parse line"))
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-30 00:28:12 +02:00
|
|
|
Self {
|
|
|
|
list,
|
|
|
|
state: ListState::default(),
|
2021-09-01 18:28:17 +02:00
|
|
|
changed: false,
|
2021-08-30 00:28:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn render(&mut self, state: &State) -> (List, &mut ListState) {
|
|
|
|
let border_style = if state == &State::SelectService {
|
|
|
|
Style::default().fg(Color::Green)
|
|
|
|
} else {
|
|
|
|
Style::default().fg(Color::Gray)
|
|
|
|
};
|
|
|
|
|
2021-09-01 18:28:17 +02:00
|
|
|
let title = match &self.changed {
|
2021-09-01 20:03:49 +02:00
|
|
|
true => "File: *docker-compose.yml*",
|
|
|
|
false => "File: docker-compose.yml",
|
2021-09-01 18:28:17 +02:00
|
|
|
};
|
|
|
|
|
2021-08-30 00:28:12 +02:00
|
|
|
let items: Vec<tui::widgets::ListItem> = self
|
|
|
|
.list
|
|
|
|
.iter()
|
|
|
|
.map(|l| {
|
|
|
|
tui::widgets::ListItem::new(l.as_ref())
|
|
|
|
.style(Style::default().fg(Color::White).bg(Color::Black))
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
// Create a List from all list items and highlight the currently selected one
|
|
|
|
let items = List::new(items)
|
|
|
|
.block(
|
|
|
|
Block::default()
|
2021-09-01 18:28:17 +02:00
|
|
|
.title(title)
|
2021-08-30 00:28:12 +02:00
|
|
|
.borders(Borders::ALL)
|
|
|
|
.border_style(border_style),
|
|
|
|
)
|
|
|
|
.style(Style::default().fg(Color::White).bg(Color::Black))
|
|
|
|
.highlight_style(Style::default().bg(Color::Black))
|
|
|
|
.highlight_symbol(">>");
|
|
|
|
|
|
|
|
(items, &mut self.state)
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:20 +02:00
|
|
|
/// finds the next image tag in given file
|
2021-08-30 00:28:12 +02:00
|
|
|
pub fn find_next_match(&mut self) -> bool {
|
|
|
|
let current_line: usize = match self.state.selected() {
|
|
|
|
None => 0,
|
|
|
|
Some(i) => i,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut i = (current_line + 1) % self.list.len();
|
|
|
|
loop {
|
|
|
|
if i == current_line {
|
|
|
|
//looped through the list
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//check if line matches
|
2021-09-13 15:54:37 +02:00
|
|
|
if repo::match_yaml_image(&self.list[i]).is_some() {
|
2021-08-30 00:28:12 +02:00
|
|
|
self.state.select(Some(i));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = (i + 1) % self.list.len(); //iterate
|
|
|
|
}
|
|
|
|
|
|
|
|
//nothing found
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:20 +02:00
|
|
|
/// finds the previous image tag in given file
|
2021-08-30 00:28:12 +02:00
|
|
|
pub fn find_previous_match(&mut self) -> bool {
|
|
|
|
let current_line: usize = match self.state.selected() {
|
|
|
|
None => 0,
|
|
|
|
Some(i) => i,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut i: usize = if current_line == 0 {
|
|
|
|
self.list.len() - 1
|
|
|
|
} else {
|
|
|
|
current_line - 1
|
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if i == current_line {
|
|
|
|
//looped through the list
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//check if line matches
|
2021-09-13 15:54:37 +02:00
|
|
|
if repo::match_yaml_image(&self.list[i]).is_some() {
|
2021-08-30 00:28:12 +02:00
|
|
|
self.state.select(Some(i));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//iterate
|
|
|
|
i = if i == 0 { self.list.len() - 1 } else { i - 1 }
|
|
|
|
}
|
|
|
|
|
|
|
|
//nothing found
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:20 +02:00
|
|
|
/// return the repository from currently selected row
|
2021-08-30 00:28:12 +02:00
|
|
|
pub fn extract_repo(&self) -> Result<String, Error> {
|
|
|
|
match self.state.selected() {
|
|
|
|
None => return Err(Error::NoneSelected),
|
2021-09-13 15:54:37 +02:00
|
|
|
Some(i) => match repo::match_yaml_image(&self.list[i]) {
|
|
|
|
None => return Err(Error::Parsing(String::from("Nothing found"))),
|
|
|
|
Some((_, repo)) => return Ok(repo.to_string()),
|
|
|
|
},
|
2021-08-30 00:28:12 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-31 01:40:29 +02:00
|
|
|
|
2021-09-07 16:07:20 +02:00
|
|
|
/// replace currently selected line with repo and tag
|
2021-08-31 01:40:29 +02:00
|
|
|
pub fn change_current_line(&mut self, repo_with_tag: String) {
|
|
|
|
match self.state.selected() {
|
|
|
|
None => (),
|
2021-09-13 15:54:37 +02:00
|
|
|
Some(i) => match repo::match_yaml_image(&self.list[i]) {
|
|
|
|
None => return,
|
|
|
|
Some((front, _)) => self.list[i] = format!("{}{}", front, repo_with_tag),
|
|
|
|
},
|
2021-08-31 01:40:29 +02:00
|
|
|
}
|
2021-09-01 18:28:17 +02:00
|
|
|
self.changed = true;
|
2021-08-31 01:40:29 +02:00
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:20 +02:00
|
|
|
/// save the currently opened file
|
2021-09-01 18:28:17 +02:00
|
|
|
pub fn save(&mut self) -> Result<(), std::io::Error> {
|
2021-09-01 23:04:07 +02:00
|
|
|
let name = "docker-compose.yml";
|
2021-08-31 16:37:04 +02:00
|
|
|
let mut file = File::create(name)?;
|
2021-08-31 01:40:29 +02:00
|
|
|
for line in &self.list {
|
2021-08-31 16:37:04 +02:00
|
|
|
file.write_all(line.as_bytes())?;
|
|
|
|
file.write_all("\n".as_bytes())?;
|
2021-08-31 01:40:29 +02:00
|
|
|
}
|
2021-09-01 18:28:17 +02:00
|
|
|
|
|
|
|
self.changed = false;
|
2021-08-31 16:37:04 +02:00
|
|
|
Ok(())
|
2021-08-31 01:40:29 +02:00
|
|
|
}
|
2021-08-30 00:28:12 +02:00
|
|
|
}
|