added distrobox logic, and protomotion logic
This commit is contained in:
+14
-2
@@ -35,6 +35,11 @@ pub fn run_tui(
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
let (event_tx, event_rx) = channel::<AppEvent>();
|
||||
let input_tx = event_tx.clone();
|
||||
let mut project_list_state = ListState::default();
|
||||
if !state.projects.is_empty() {
|
||||
project_list_state.select(Some(0));
|
||||
state.selected_project = 0;
|
||||
}
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
if event::poll(Duration::from_millis(100)).unwrap_or(false) {
|
||||
@@ -169,6 +174,9 @@ pub fn run_tui(
|
||||
state.output.push("Error: USAGE -> np <org> <name>".into());
|
||||
}
|
||||
}
|
||||
"current_project" | "cp" => {
|
||||
let _ = state.execute_command(command, None);
|
||||
}
|
||||
command_name => {
|
||||
if state.module_loader.commands.contains_key(command_name) {
|
||||
state.output.push(format!(
|
||||
@@ -221,7 +229,9 @@ pub fn run_tui(
|
||||
{
|
||||
if let Some(selected) = project_list_state.selected() {
|
||||
if selected > 0 {
|
||||
project_list_state.select(Some(selected - 1));
|
||||
let new_index = selected - 1;
|
||||
project_list_state.select(Some(new_index));
|
||||
state.selected_project = new_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +242,9 @@ pub fn run_tui(
|
||||
{
|
||||
if let Some(selected) = project_list_state.selected() {
|
||||
if selected + 1 < state.projects.len() {
|
||||
project_list_state.select(Some(selected + 1));
|
||||
let new_index = selected + 1;
|
||||
project_list_state.select(Some(new_index));
|
||||
state.selected_project = new_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+132
-21
@@ -1,10 +1,12 @@
|
||||
use fs_extra::dir::{CopyOptions, copy};
|
||||
use ratatui::crossterm::event;
|
||||
use rhai::{AST, Dynamic, Engine, Scope};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fs::{File, create_dir_all, read_dir, read_to_string};
|
||||
use std::fs::{File, create_dir_all, read_dir, read_to_string, remove_dir_all};
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::sync::{Arc, mpsc::Sender, mpsc::channel};
|
||||
|
||||
@@ -22,7 +24,7 @@ pub struct AppState {
|
||||
pub log: Vec<String>,
|
||||
pub output: Vec<String>,
|
||||
pub selected_server: Option<Server>,
|
||||
pub selected_project: Option<Project>,
|
||||
pub selected_project: usize,
|
||||
pub curent_intput: String,
|
||||
pub module_loader: ModuleLoader,
|
||||
pub output_scroll: u16,
|
||||
@@ -47,7 +49,7 @@ impl AppState {
|
||||
log: Vec::new(),
|
||||
output: Vec::new(),
|
||||
selected_server: None,
|
||||
selected_project: None,
|
||||
selected_project: 0,
|
||||
curent_intput: String::new(),
|
||||
module_loader: ModuleLoader::new(),
|
||||
output_scroll: 0,
|
||||
@@ -145,6 +147,48 @@ impl AppState {
|
||||
)))?;
|
||||
}
|
||||
}
|
||||
"current_project" | "cp" => {
|
||||
let mut out_vec = Vec::new();
|
||||
out_vec.push(format!(
|
||||
"org: {}",
|
||||
&self.projects[self.selected_project].org_name
|
||||
));
|
||||
out_vec.push(format!(
|
||||
"name: {}",
|
||||
&self.projects[self.selected_project].name
|
||||
));
|
||||
out_vec.push(format!(
|
||||
"files: {}",
|
||||
&self.projects[self.selected_project].files.display()
|
||||
));
|
||||
out_vec.push(format!(
|
||||
"notes: {}",
|
||||
&self.projects[self.selected_project].notes.display()
|
||||
));
|
||||
if let Some(db) = self.projects[self.selected_project].db.clone() {
|
||||
out_vec.push(format!("distrobox: {}", db.name));
|
||||
}
|
||||
if self.projects[self.selected_project].current {
|
||||
out_vec.push(format!("status: current"));
|
||||
} else {
|
||||
out_vec.push(format!("status: upcoming"));
|
||||
}
|
||||
for line in out_vec {
|
||||
let _ = self.main_tx.send(ToolMessage::Output(line));
|
||||
}
|
||||
}
|
||||
"promote_project" | "pp" => {
|
||||
match self.promote_project() {
|
||||
Ok(out) => {
|
||||
let _ = self.main_tx.send(ToolMessage::Output(out));
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = self
|
||||
.main_tx
|
||||
.send(ToolMessage::Output(format!("error promoting project! {e}")));
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
let ast = self
|
||||
.module_loader
|
||||
@@ -164,9 +208,7 @@ impl AppState {
|
||||
for arg_requirement in &cmd_meta.args {
|
||||
match arg_requirement.as_str() {
|
||||
"project" => {
|
||||
if let Some(ref proj) = self.selected_project {
|
||||
scope.push("project", proj.clone());
|
||||
}
|
||||
scope.push("project", self.projects[self.selected_project].clone());
|
||||
}
|
||||
"projects" => {
|
||||
let mut arr = rhai::Array::new();
|
||||
@@ -176,16 +218,10 @@ impl AppState {
|
||||
scope.push("projects", arr);
|
||||
}
|
||||
"host" => {
|
||||
if let Some(host) =
|
||||
self.selected_project.as_ref().and_then(|p| p.hosts.first())
|
||||
{
|
||||
scope.push("host", host.clone());
|
||||
}
|
||||
scope.push("host", "todo");
|
||||
}
|
||||
"hosts" => {
|
||||
if let Some(ref proj) = self.selected_project {
|
||||
scope.push("hosts", proj.hosts.clone());
|
||||
}
|
||||
scope.push("hosts", self.projects[self.selected_project].clone());
|
||||
}
|
||||
"config" => {
|
||||
let mut map = rhai::Map::new();
|
||||
@@ -248,19 +284,30 @@ impl AppState {
|
||||
|
||||
pub fn new_project(&mut self, org: String, name: String) -> Result<(), Box<dyn Error>> {
|
||||
let template_box = self.config.get("template_box").unwrap();
|
||||
let tools_dir = self.config.get("tools").unwrap();
|
||||
let project_files = PathBuf::from(self.config.get("upcoming_files").unwrap())
|
||||
.join(format!("{}/{}", org, name));
|
||||
let project_notes = PathBuf::from(self.config.get("upcoming_notes").unwrap())
|
||||
.join(format!("{}/{}", org, name));
|
||||
create_dir_all(&project_files)?;
|
||||
create_dir_all(&project_notes)?;
|
||||
let db = DistroBox {
|
||||
name: format!("{}-{}-{}", template_box, org, name),
|
||||
volumes: vec![
|
||||
project_files.display().to_string(),
|
||||
project_notes.display().to_string(),
|
||||
tools_dir.clone(),
|
||||
],
|
||||
created: false,
|
||||
template: template_box.clone(),
|
||||
};
|
||||
let mut new_project = Project::new();
|
||||
let mut project_conf_folder = self.config_file.clone();
|
||||
project_conf_folder.pop();
|
||||
project_conf_folder.push(format!("projects/{}-{}", org, name));
|
||||
new_project.config_folder(project_conf_folder);
|
||||
new_project.box_name(format!("{}-{}-{}", template_box, org, name));
|
||||
new_project.name = name;
|
||||
new_project.db = Some(db);
|
||||
new_project.org_name(org);
|
||||
new_project.files(project_files);
|
||||
new_project.notes(project_notes);
|
||||
@@ -268,6 +315,44 @@ impl AppState {
|
||||
self.projects.push(new_project);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn promote_project(&mut self) -> Result<String, Box<dyn Error>> {
|
||||
let mut return_string = String::from("Project promoted successfully!");
|
||||
let mut new_project = self.projects[self.selected_project].clone();
|
||||
let new_files_path = PathBuf::from(self.config.get("current_files").unwrap())
|
||||
.join(format!("{}/{}", new_project.org_name, new_project.name));
|
||||
let new_notes_path = PathBuf::from(self.config.get("current_notes").unwrap())
|
||||
.join(format!("{}/{}", new_project.org_name, new_project.name));
|
||||
let mut options = CopyOptions::new();
|
||||
options.overwrite = true;
|
||||
copy(new_project.files.clone(), new_files_path.clone(), &options)?;
|
||||
copy(new_project.notes.clone(), new_notes_path.clone(), &options)?;
|
||||
let cleanup_res = Command::new("rm")
|
||||
.arg("-rf")
|
||||
.arg(new_project.files.display().to_string())
|
||||
.arg(new_project.notes.display().to_string())
|
||||
.status();
|
||||
if cleanup_res.is_err() {
|
||||
return_string = format!(
|
||||
"Error deleting {} and {}, please clean up manually. Otherwise Project promotion succeeded!",
|
||||
new_files_path.display(),
|
||||
new_notes_path.display()
|
||||
);
|
||||
}
|
||||
new_project.files(new_files_path.clone());
|
||||
new_project.notes(new_notes_path.clone());
|
||||
if let Some(mut db) = new_project.db {
|
||||
db.volumes = vec![
|
||||
new_files_path.display().to_string(),
|
||||
new_notes_path.display().to_string(),
|
||||
self.config.get("tools").unwrap().to_string(),
|
||||
];
|
||||
db.create()?;
|
||||
new_project.db = Some(db);
|
||||
}
|
||||
self.projects[self.selected_project] = new_project;
|
||||
return Ok(return_string);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -285,7 +370,7 @@ pub struct Project {
|
||||
pub files: PathBuf,
|
||||
pub hosts: Vec<Host>,
|
||||
pub current: bool,
|
||||
pub boxname: String,
|
||||
pub db: Option<DistroBox>,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
@@ -298,7 +383,7 @@ impl Project {
|
||||
files: PathBuf::new(),
|
||||
hosts: Vec::new(),
|
||||
current: false,
|
||||
boxname: String::new(),
|
||||
db: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,10 +411,6 @@ impl Project {
|
||||
self.config_folder = path;
|
||||
}
|
||||
|
||||
pub fn box_name(&mut self, boxname: String) {
|
||||
self.boxname = boxname;
|
||||
}
|
||||
|
||||
pub fn load_config(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
let config_contents = read_to_string(&self.config_folder)?;
|
||||
for line in config_contents.lines() {
|
||||
@@ -656,3 +737,33 @@ enum AppEvent {
|
||||
Worker(ToolMessage),
|
||||
Mouse(event::MouseEvent),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DistroBox {
|
||||
pub name: String,
|
||||
pub volumes: Vec<String>,
|
||||
pub created: bool,
|
||||
pub template: String,
|
||||
}
|
||||
|
||||
impl DistroBox {
|
||||
pub fn create(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
let mut create_command = Command::new("distrobox");
|
||||
create_command
|
||||
.arg("create")
|
||||
.arg("--root")
|
||||
.arg("--clone")
|
||||
.arg(self.template.clone())
|
||||
.arg("--name")
|
||||
.arg(self.name.clone());
|
||||
for volume in &self.volumes {
|
||||
let folder_name = volume.split("/").last().unwrap();
|
||||
create_command
|
||||
.arg("--volume")
|
||||
.arg(format!("{}:/{}:rw", volume, folder_name));
|
||||
}
|
||||
create_command.status()?;
|
||||
self.created = true;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user