Skip to content

Commit

Permalink
feat: initial optional exec command
Browse files Browse the repository at this point in the history
  • Loading branch information
robertpsoane committed Jul 8, 2024
1 parent db3bda3 commit 1cc6086
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/components/text_input_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl TextInputWrapper {
Ok(MessageResponse::Consumed)
}

pub fn get_value(&mut self) -> String {
pub fn get_value(&self) -> String {

Check warning on line 39 in src/components/text_input_wrapper.rs

View check run for this annotation

Codecov / codecov/patch

src/components/text_input_wrapper.rs#L39

Added line #L39 was not covered by tests
self.state.get_value().clone()
}

Expand Down
24 changes: 16 additions & 8 deletions src/docker/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,24 @@ impl DockerContainer {
pub async fn attach(&self, cmd: &str) -> Result<()> {
Command::new("clear").spawn()?.wait().await?;

Command::new("docker")
.arg("exec")
.arg("-it")
.arg(&self.names)
.arg(cmd)
.spawn()?
.wait()
.await?;
let parts: Vec<String> = cmd.split_whitespace().map(String::from).collect();

let mut command = Command::new("docker");

let mut arged_commands = command.arg("exec").arg("-it").arg(&self.names);

Check warning on line 148 in src/docker/container.rs

View check run for this annotation

Codecov / codecov/patch

src/docker/container.rs#L144-L148

Added lines #L144 - L148 were not covered by tests

for part in parts {
arged_commands = arged_commands.arg(part);
}

Check warning on line 152 in src/docker/container.rs

View check run for this annotation

Codecov / codecov/patch

src/docker/container.rs#L150-L152

Added lines #L150 - L152 were not covered by tests

let exit_status = arged_commands.spawn()?.wait().await?;

Check warning on line 154 in src/docker/container.rs

View check run for this annotation

Codecov / codecov/patch

src/docker/container.rs#L154

Added line #L154 was not covered by tests

Command::new("clear").spawn()?.wait().await?;

if !exit_status.success() {
bail!("error in connecting to or interacting with container")
}

Check warning on line 161 in src/docker/container.rs

View check run for this annotation

Codecov / codecov/patch

src/docker/container.rs#L158-L161

Added lines #L158 - L161 were not covered by tests
Ok(())
}
}
Expand Down
132 changes: 110 additions & 22 deletions src/pages/attach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ use std::sync::{Arc, Mutex};

use crossterm::terminal::disable_raw_mode;

use color_eyre::eyre::{bail, Ok, Result};
use color_eyre::eyre::{bail, Result};
use ratatui::layout::{Constraint, Layout};
use ratatui::{layout::Rect, Frame};
use tokio::sync::mpsc::Sender;

use crate::components::alert_modal::{AlertModal, ModalState};
use crate::components::text_input_wrapper::TextInputWrapper;
use crate::config::Config;
use crate::context::AppContext;
use crate::traits::Close;
use crate::docker::traits::Describe;
use crate::traits::{Close, ModalComponent};
use crate::{
components::help::{PageHelp, PageHelpBuilder},
docker::container::DockerContainer,
Expand All @@ -17,70 +21,132 @@ use crate::{
};

const NAME: &str = "Attach";
const PROMPT: &str = "exec: ";

const ESC_KEY: Key = Key::Esc;
const ENTER: Key = Key::Enter;

#[derive(Debug)]
enum ModalType {
AlertModal,
}

#[derive(Debug)]
pub struct Attach {
config: Box<Config>,
container: Option<DockerContainer>,
next: Option<Transition>,
tx: Sender<Message<Key, Transition>>,
page_help: Arc<Mutex<PageHelp>>,
attach_input: TextInputWrapper,
alert_modal: AlertModal<ModalType>,
}

impl Attach {
pub fn new(tx: Sender<Message<Key, Transition>>, config: Box<Config>) -> Self {
let page_help = PageHelpBuilder::new(NAME.into(), config.clone())
.add_input(format!("{ESC_KEY}"), "back".into())
.build();

let page_help = Self::build_page_help(config.clone(), None);

Check warning on line 47 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L47

Added line #L47 was not covered by tests
Self {
config,
container: None,
next: None,

Check warning on line 51 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L51

Added line #L51 was not covered by tests
tx,
page_help: Arc::new(Mutex::new(page_help)),
attach_input: TextInputWrapper::new(PROMPT.into(), None),
alert_modal: AlertModal::new("Error".into(), ModalType::AlertModal),

Check warning on line 55 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L54-L55

Added lines #L54 - L55 were not covered by tests
}
}

async fn attach(&self, container: DockerContainer, exec: &str, cx: AppContext) -> Result<()> {
disable_raw_mode()?;
container.attach(exec).await?;
pub fn build_page_help(config: Box<Config>, name: Option<String>) -> PageHelp {
PageHelpBuilder::new(
match name {
Some(n) => n,
None => NAME.into(),

Check warning on line 63 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L59-L63

Added lines #L59 - L63 were not covered by tests
},
config.clone(),
)
.add_input(format!("{ESC_KEY}"), "back".into())
.add_input(format!("{ENTER}"), "exec".into())
.build()
}

Check warning on line 70 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L65-L70

Added lines #L65 - L70 were not covered by tests

let transition = if let Some(t) = cx.next() {
t
async fn to_containers(&self) -> Result<()> {
let transition = if let Some(t) = &self.next {
t.clone()

Check warning on line 74 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L72-L74

Added lines #L72 - L74 were not covered by tests
} else {
Transition::ToContainerPage(AppContext {
docker_container: Some(container),
..Default::default()
})
Transition::ToContainerPage(AppContext::default())

Check warning on line 76 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L76

Added line #L76 was not covered by tests
};

self.tx.send(Message::Transition(transition)).await?;
self.tx
.send(Message::Transition(Transition::ToNewTerminal))
.await?;

Ok(())
}

Check warning on line 85 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L84-L85

Added lines #L84 - L85 were not covered by tests

async fn attach(&self, exec: &str) -> Result<()> {
if self.container.is_none() {
bail!("could not attach to a container when no container is set");
};

let container = self.container.clone().unwrap();

disable_raw_mode()?;
let res = container.attach(exec).await;
self.tx
.send(Message::Transition(Transition::ToNewTerminal))
.await?;

Check warning on line 98 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L87-L98

Added lines #L87 - L98 were not covered by tests

if res.is_err() {
bail!("failed to attach to container");
}

Check warning on line 102 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L100-L102

Added lines #L100 - L102 were not covered by tests
Ok(())
}
}

#[async_trait::async_trait]
impl Page for Attach {
async fn update(&mut self, _message: Key) -> Result<MessageResponse> {
let res = MessageResponse::Consumed;
async fn update(&mut self, message: Key) -> Result<MessageResponse> {
if let ModalState::Open(_) = self.alert_modal.state.clone() {
return self.alert_modal.update(message).await;
}

Check warning on line 112 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L109-L112

Added lines #L109 - L112 were not covered by tests

let res = match message {
Key::Enter => {
let exec = self.attach_input.get_value();
match self.attach(&exec).await {
Ok(()) => self.to_containers().await?,
Err(_) => {
let msg = format!("Error in exec with command\n`{exec}`");
self.alert_modal.initialise(msg)
}
}

MessageResponse::Consumed
}
Key::Esc => {
self.to_containers().await?;
MessageResponse::Consumed
}
_ => self.attach_input.update(message)?,
};

Check warning on line 132 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L114-L132

Added lines #L114 - L132 were not covered by tests
Ok(res)
}

async fn initialise(&mut self, cx: AppContext) -> Result<()> {
if let Some(container) = cx.clone().docker_container {
let page_name = format!("{NAME} ({})", container.get_name());
self.page_help = Arc::new(Mutex::new(Self::build_page_help(
self.config.clone(),
Some(page_name),
)));

Check warning on line 142 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L138-L142

Added lines #L138 - L142 were not covered by tests
self.container = Some(container)
} else {
bail!("no docker container")
}
if let Some(container) = self.container.clone() {
self.attach(container, &self.config.default_exec, cx)
.await?;
}
self.attach_input
.set_input(self.config.default_exec.clone());
self.next = cx.next();

Check warning on line 149 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L147-L149

Added lines #L147 - L149 were not covered by tests
Ok(())
}

Expand All @@ -93,5 +159,27 @@ impl Page for Attach {
impl Close for Attach {}

impl Component for Attach {
fn draw(&mut self, _f: &mut Frame<'_>, _area: Rect) {}
fn draw(&mut self, f: &mut Frame<'_>, area: Rect) {
let height = area.height;

let [_, text_area, _] = Layout::vertical([
Constraint::Length((height - 3) / 2),
Constraint::Length(3),
Constraint::Min(0),
])
.areas(area);

let [_, text_area, _] = Layout::horizontal([
Constraint::Percentage(5),
Constraint::Percentage(90),
Constraint::Percentage(5),
])
.areas(text_area);

self.attach_input.draw(f, text_area);

if let ModalState::Open(_) = self.alert_modal.state.clone() {
self.alert_modal.draw(f, area)
}
}

Check warning on line 184 in src/pages/attach.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/attach.rs#L162-L184

Added lines #L162 - L184 were not covered by tests
}
2 changes: 1 addition & 1 deletion src/pages/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl Page for DescribeContainer {
}
};
self.thing_summary = Some(thing.describe()?);
let page_name = format!("Describe ({})", thing.get_name());
let page_name = format!("{NAME} ({})", thing.get_name());

Check warning on line 135 in src/pages/describe.rs

View check run for this annotation

Codecov / codecov/patch

src/pages/describe.rs#L135

Added line #L135 was not covered by tests
self.page_help = Arc::new(Mutex::new(Self::build_page_help(
self.config.clone(),
Some(page_name),
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/text_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl TextInputState {
self.update_autocomplete();
}

pub fn get_value(&mut self) -> String {
pub fn get_value(&self) -> String {

Check warning on line 87 in src/widgets/text_input.rs

View check run for this annotation

Codecov / codecov/patch

src/widgets/text_input.rs#L87

Added line #L87 was not covered by tests
self.value.clone()
}

Expand Down

0 comments on commit 1cc6086

Please sign in to comment.