feat: set rust-version in Cargo.toml, closes #77
Update zigbuild docker run command to download latest rust version
This commit is contained in:
@@ -47,11 +47,19 @@ jobs:
|
|||||||
- name: install cross
|
- name: install cross
|
||||||
run: cargo install cross --git https://github.com/cross-rs/cross
|
run: cargo install cross --git https://github.com/cross-rs/cross
|
||||||
|
|
||||||
# Build binary for arm MacOS using Docker Zigbuild
|
|
||||||
- name: build
|
- name: build
|
||||||
if: matrix.target == 'aarch64-apple-darwin'
|
if: matrix.target == 'aarch64-apple-darwin'
|
||||||
run: |
|
run: |
|
||||||
docker run --rm -v $(pwd):/io -w /io ghcr.io/rust-cross/cargo-zigbuild cargo zigbuild --release --target aarch64-apple-darwin
|
docker run --rm \
|
||||||
|
-v "$(pwd):/io" \
|
||||||
|
-w /io \
|
||||||
|
ghcr.io/rust-cross/cargo-zigbuild \
|
||||||
|
bash -ec '
|
||||||
|
rustup update stable
|
||||||
|
rustup default stable
|
||||||
|
rustup target add aarch64-apple-darwin
|
||||||
|
cargo zigbuild --release --target aarch64-apple-darwin
|
||||||
|
'
|
||||||
|
|
||||||
# Build all other targets using Cross
|
# Build all other targets using Cross
|
||||||
- name: build
|
- name: build
|
||||||
|
|||||||
+1
-2
@@ -7,8 +7,7 @@ description = "A simple tui to view & control docker containers"
|
|||||||
repository = "https://github.com/mrjackwills/oxker"
|
repository = "https://github.com/mrjackwills/oxker"
|
||||||
homepage = "https://github.com/mrjackwills/oxker"
|
homepage = "https://github.com/mrjackwills/oxker"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
# This is stuck to whatever version cargo-zigbuild is using - https://github.com/rust-cross/cargo-zigbuild/blob/main/Dockerfile
|
rust-version = "1.90.0"
|
||||||
rust-version = "1.87.0"
|
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["docker", "tui", "tokio", "terminal", "podman"]
|
keywords = ["docker", "tui", "tokio", "terminal", "podman"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
|
|||||||
+6
-2
@@ -232,8 +232,12 @@ cross_build_x86_windows() {
|
|||||||
# Build, using zig-build, for Apple silicon
|
# Build, using zig-build, for Apple silicon
|
||||||
zig_build_aarch64_apple() {
|
zig_build_aarch64_apple() {
|
||||||
# mkdir /workspace/oxker/target
|
# mkdir /workspace/oxker/target
|
||||||
echo -e "${YELLOW}docker run --rm -v $(pwd):/io -w /io ghcr.io/rust-cross/cargo-zigbuild cargo zigbuild --release --target aarch64-apple-darwin${RESET}"
|
echo -e "${YELLOW}docker run --rm -v $(pwd):/io -w /io ghcr.io/rust-cross/cargo-zigbuild bash -e -c 'rustup update stable && rustup default stable && rustup target add aarch64-apple-darwin && cargo zigbuild --release --target aarch64-apple-darwin${RESET}"
|
||||||
docker run --rm -v "$(pwd):/io" -w /io ghcr.io/rust-cross/cargo-zigbuild cargo zigbuild --release --target aarch64-apple-darwin
|
|
||||||
|
docker run --rm -v "$(pwd):/io" -w /io \
|
||||||
|
ghcr.io/rust-cross/cargo-zigbuild \
|
||||||
|
bash -ec 'rustup update stable && rustup default stable && rustup target add aarch64-apple-darwin && cargo zigbuild --release --target aarch64-apple-darwin'
|
||||||
|
|
||||||
if ask_yn "sudo chown $(pwd)/target"; then
|
if ask_yn "sudo chown $(pwd)/target"; then
|
||||||
echo -e "${YELLOW}sudo chown -R vscode:vscode $(pwd)/target${RESET}"
|
echo -e "${YELLOW}sudo chown -R vscode:vscode $(pwd)/target${RESET}"
|
||||||
sudo chown -R vscode:vscode "$(pwd)/target"
|
sudo chown -R vscode:vscode "$(pwd)/target"
|
||||||
|
|||||||
@@ -689,12 +689,11 @@ impl Logs {
|
|||||||
if let Some(new_index) = match sd {
|
if let Some(new_index) = match sd {
|
||||||
ScrollDirection::Next => current_position.checked_add(1),
|
ScrollDirection::Next => current_position.checked_add(1),
|
||||||
ScrollDirection::Previous => current_position.checked_sub(1),
|
ScrollDirection::Previous => current_position.checked_sub(1),
|
||||||
} {
|
}
|
||||||
if let Some(f) = self.search_results.get(new_index) {
|
&& let Some(f) = self.search_results.get(new_index) {
|
||||||
self.lines.state.select(Some(*f));
|
self.lines.state.select(Some(*f));
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let range = match sd {
|
let range = match sd {
|
||||||
ScrollDirection::Previous => (0..=current_selected).rev().collect::<Vec<_>>(),
|
ScrollDirection::Previous => (0..=current_selected).rev().collect::<Vec<_>>(),
|
||||||
@@ -922,11 +921,10 @@ impl Logs {
|
|||||||
/// Add a padding so one char will always be visilbe?
|
/// Add a padding so one char will always be visilbe?
|
||||||
pub fn forward(&mut self, width: u16) {
|
pub fn forward(&mut self, width: u16) {
|
||||||
let offset = usize::from(self.offset);
|
let offset = usize::from(self.offset);
|
||||||
if self.horizontal_scroll_able(width) {
|
if self.horizontal_scroll_able(width)
|
||||||
if self.adjusted_max_width > 0 && offset < self.adjusted_max_width {
|
&& self.adjusted_max_width > 0 && offset < self.adjusted_max_width {
|
||||||
self.offset = self.offset.saturating_add(1);
|
self.offset = self.offset.saturating_add(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reduce the char offset
|
/// Reduce the char offset
|
||||||
|
|||||||
+4
-6
@@ -172,11 +172,10 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_search_scroll(&mut self, np: &ScrollDirection) {
|
pub fn log_search_scroll(&mut self, np: &ScrollDirection) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container()
|
||||||
if i.logs.search_scroll(np).is_some() {
|
&& i.logs.search_scroll(np).is_some() {
|
||||||
self.rerender.update_draw();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_log_search(&self) -> Option<LogSearch> {
|
pub fn gen_log_search(&self) -> Option<LogSearch> {
|
||||||
@@ -340,14 +339,13 @@ impl AppData {
|
|||||||
/// Sort containers based on a given header, if headings match, and already ascending, remove sorting
|
/// Sort containers based on a given header, if headings match, and already ascending, remove sorting
|
||||||
pub fn set_sort_by_header(&mut self, selected_header: Header) {
|
pub fn set_sort_by_header(&mut self, selected_header: Header) {
|
||||||
let mut output = Some((selected_header, SortedOrder::Asc));
|
let mut output = Some((selected_header, SortedOrder::Asc));
|
||||||
if let Some((current_header, order)) = self.get_sorted() {
|
if let Some((current_header, order)) = self.get_sorted()
|
||||||
if current_header == selected_header {
|
&& current_header == selected_header {
|
||||||
match order {
|
match order {
|
||||||
SortedOrder::Desc => output = None,
|
SortedOrder::Desc => output = None,
|
||||||
SortedOrder::Asc => output = Some((selected_header, SortedOrder::Desc)),
|
SortedOrder::Asc => output = Some((selected_header, SortedOrder::Desc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.set_sorted(output);
|
self.set_sorted(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,8 +158,8 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
|vec_str: Option<Vec<String>>,
|
|vec_str: Option<Vec<String>>,
|
||||||
keymap_field: &mut (KeyCode, Option<KeyCode>),
|
keymap_field: &mut (KeyCode, Option<KeyCode>),
|
||||||
keymap_clash: &mut HashSet<KeyCode>| {
|
keymap_clash: &mut HashSet<KeyCode>| {
|
||||||
if let Some(vec_str) = vec_str {
|
if let Some(vec_str) = vec_str
|
||||||
if let Some(vec_keycode) = Self::try_parse_keycode(&vec_str) {
|
&& let Some(vec_keycode) = Self::try_parse_keycode(&vec_str) {
|
||||||
if let Some(first) = vec_keycode.first() {
|
if let Some(first) = vec_keycode.first() {
|
||||||
keymap_clash.insert(*first);
|
keymap_clash.insert(*first);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
@@ -173,7 +173,6 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
keymap_field.1 = None;
|
keymap_field.1 = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ck) = value {
|
if let Some(ck) = value {
|
||||||
@@ -276,8 +275,8 @@ impl Keymap {
|
|||||||
|
|
||||||
for key in input.iter().take(2) {
|
for key in input.iter().take(2) {
|
||||||
if key.chars().count() == 1 {
|
if key.chars().count() == 1 {
|
||||||
if let Some(first_char) = key.chars().next() {
|
if let Some(first_char) = key.chars().next()
|
||||||
if let Some(first_char) = match first_char {
|
&& let Some(first_char) = match first_char {
|
||||||
x if x.is_ascii_alphabetic() || x.is_ascii_digit() => Some(first_char),
|
x if x.is_ascii_alphabetic() || x.is_ascii_digit() => Some(first_char),
|
||||||
'/' | '\\' | ',' | '.' | '#' | '\'' | '[' | ']' | ';' | '=' | '-' => {
|
'/' | '\\' | ',' | '.' | '#' | '\'' | '[' | ']' | ';' | '=' | '-' => {
|
||||||
Some(first_char)
|
Some(first_char)
|
||||||
@@ -286,7 +285,6 @@ impl Keymap {
|
|||||||
} {
|
} {
|
||||||
output.push(KeyCode::Char(first_char));
|
output.push(KeyCode::Char(first_char));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let keycode = match key.to_lowercase().as_str() {
|
let keycode = match key.to_lowercase().as_str() {
|
||||||
"f1" => Some(KeyCode::F(1)),
|
"f1" => Some(KeyCode::F(1)),
|
||||||
|
|||||||
+2
-3
@@ -211,13 +211,12 @@ impl Config {
|
|||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let config_from_cli = Self::from(&args);
|
let config_from_cli = Self::from(&args);
|
||||||
|
|
||||||
if let Some(config_file) = &args.config_file {
|
if let Some(config_file) = &args.config_file
|
||||||
if let Some(config_file) =
|
&& let Some(config_file) =
|
||||||
parse_config_file::ConfigFile::try_parse_from_file(config_file)
|
parse_config_file::ConfigFile::try_parse_from_file(config_file)
|
||||||
{
|
{
|
||||||
return Self::from(config_file).merge_args(config_from_cli);
|
return Self::from(config_file).merge_args(config_from_cli);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(config_file) = parse_config_file::ConfigFile::try_parse(in_container) {
|
if let Some(config_file) = parse_config_file::ConfigFile::try_parse(in_container) {
|
||||||
return Self::from(config_file).merge_args(config_from_cli);
|
return Self::from(config_file).merge_args(config_from_cli);
|
||||||
|
|||||||
+9
-19
@@ -161,15 +161,15 @@ impl ExecMode {
|
|||||||
let use_cli = app_data.lock().config.use_cli;
|
let use_cli = app_data.lock().config.use_cli;
|
||||||
let container = app_data.lock().get_selected_container_id_state_name();
|
let container = app_data.lock().get_selected_container_id_state_name();
|
||||||
|
|
||||||
if let Some((id, state, _)) = container {
|
if let Some((id, state, _)) = container
|
||||||
if [
|
&& [
|
||||||
State::Running(RunningState::Healthy),
|
State::Running(RunningState::Healthy),
|
||||||
State::Running(RunningState::Unhealthy),
|
State::Running(RunningState::Unhealthy),
|
||||||
]
|
]
|
||||||
.contains(&state)
|
.contains(&state)
|
||||||
{
|
{
|
||||||
if tty_readable() && !use_cli {
|
if tty_readable() && !use_cli
|
||||||
if let Ok(exec) = docker
|
&& let Ok(exec) = docker
|
||||||
.create_exec(
|
.create_exec(
|
||||||
id.get(),
|
id.get(),
|
||||||
CreateExecOptions {
|
CreateExecOptions {
|
||||||
@@ -180,34 +180,24 @@ impl ExecMode {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
&& let Ok(StartExecResults::Attached { mut output, .. }) =
|
||||||
if let Ok(StartExecResults::Attached { mut output, .. }) =
|
|
||||||
docker.start_exec(&exec.id, None).await
|
docker.start_exec(&exec.id, None).await
|
||||||
{
|
&& let Some(Ok(msg)) = output.next().await
|
||||||
if let Some(Ok(msg)) = output.next().await {
|
&& !msg.to_string().starts_with(OCI_ERROR) {
|
||||||
if !msg.to_string().starts_with(OCI_ERROR) {
|
|
||||||
return Some(Self::Internal((
|
return Some(Self::Internal((
|
||||||
Arc::new(id),
|
Arc::new(id),
|
||||||
Arc::clone(docker),
|
Arc::clone(docker),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(output) = std::process::Command::new(command::DOCKER)
|
if let Ok(output) = std::process::Command::new(command::DOCKER)
|
||||||
.args([command::EXEC, id.get(), command::PWD])
|
.args([command::EXEC, id.get(), command::PWD])
|
||||||
.output()
|
.output()
|
||||||
{
|
&& let Ok(output) = String::from_utf8(output.stdout)
|
||||||
if let Ok(output) = String::from_utf8(output.stdout) {
|
&& !output.starts_with(OCI_ERROR) {
|
||||||
if !output.starts_with(OCI_ERROR) {
|
|
||||||
return Some(Self::External(Arc::new(id)));
|
return Some(Self::External(Arc::new(id)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,8 +178,8 @@ impl InputHandler {
|
|||||||
async fn save_logs(&self) -> Result<(), Box<dyn std::error::Error>> {
|
async fn save_logs(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let args = self.app_data.lock().config.clone();
|
let args = self.app_data.lock().config.clone();
|
||||||
let container = self.app_data.lock().get_selected_container_id_state_name();
|
let container = self.app_data.lock().get_selected_container_id_state_name();
|
||||||
if let Some((id, _, name)) = container {
|
if let Some((id, _, name)) = container
|
||||||
if let Some(log_path) = args.save_dir {
|
&& let Some(log_path) = args.save_dir {
|
||||||
let (sx, rx) = tokio::sync::oneshot::channel();
|
let (sx, rx) = tokio::sync::oneshot::channel();
|
||||||
self.docker_tx.send(DockerMessage::Exec(sx)).await?;
|
self.docker_tx.send(DockerMessage::Exec(sx)).await?;
|
||||||
|
|
||||||
@@ -230,7 +230,6 @@ impl InputHandler {
|
|||||||
.set_info_box(&format!("saved to {}", path.display()));
|
.set_info_box(&format!("saved to {}", path.display()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -1,4 +1,3 @@
|
|||||||
#![allow(clippy::collapsible_if)]
|
|
||||||
// #![allow(unused)]
|
// #![allow(unused)]
|
||||||
// Zigbuild is stuck on 1.87.0, which means Mac builds won't work when using collapsible ifs
|
// Zigbuild is stuck on 1.87.0, which means Mac builds won't work when using collapsible ifs
|
||||||
|
|
||||||
@@ -64,8 +63,8 @@ async fn docker_init(
|
|||||||
Docker::connect_with_socket(&host, 120, API_DEFAULT_VERSION)
|
Docker::connect_with_socket(&host, 120, API_DEFAULT_VERSION)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(docker) = connection {
|
if let Ok(docker) = connection
|
||||||
if docker.ping().await.is_ok() {
|
&& docker.ping().await.is_ok() {
|
||||||
tokio::spawn(DockerData::start(
|
tokio::spawn(DockerData::start(
|
||||||
Arc::clone(app_data),
|
Arc::clone(app_data),
|
||||||
docker,
|
docker,
|
||||||
@@ -75,7 +74,6 @@ async fn docker_init(
|
|||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerConnect, gui_state, Status::DockerConnect);
|
.set_error(AppError::DockerConnect, gui_state, Status::DockerConnect);
|
||||||
|
|||||||
@@ -39,15 +39,14 @@ fn gen_header<'a>(
|
|||||||
fn gen_header_block<'a>(colors: AppColors, fd: &FrameData, header: Header) -> (Color, &'a str) {
|
fn gen_header_block<'a>(colors: AppColors, fd: &FrameData, header: Header) -> (Color, &'a str) {
|
||||||
let mut color = colors.headers_bar.text;
|
let mut color = colors.headers_bar.text;
|
||||||
let mut suffix = "";
|
let mut suffix = "";
|
||||||
if let Some((a, b)) = &fd.sorted_by {
|
if let Some((a, b)) = &fd.sorted_by
|
||||||
if &header == a {
|
&& &header == a {
|
||||||
match b {
|
match b {
|
||||||
SortedOrder::Asc => suffix = " ▲",
|
SortedOrder::Asc => suffix = " ▲",
|
||||||
SortedOrder::Desc => suffix = " ▼",
|
SortedOrder::Desc => suffix = " ▼",
|
||||||
}
|
}
|
||||||
color = colors.headers_bar.text_selected;
|
color = colors.headers_bar.text_selected;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(color, suffix)
|
(color, suffix)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,13 +103,12 @@ fn generate_block<'a>(
|
|||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.title(ratatui::text::Line::from(title).left_aligned());
|
.title(ratatui::text::Line::from(title).left_aligned());
|
||||||
|
|
||||||
if panel == SelectablePanel::Logs {
|
if panel == SelectablePanel::Logs
|
||||||
if let Some(x) = fd.scroll_title.as_ref() {
|
&& let Some(x) = fd.scroll_title.as_ref() {
|
||||||
block = block
|
block = block
|
||||||
.title_bottom(x.to_owned())
|
.title_bottom(x.to_owned())
|
||||||
.title_alignment(ratatui::layout::Alignment::Right);
|
.title_alignment(ratatui::layout::Alignment::Right);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if !fd.status.contains(&Status::Filter) {
|
if !fd.status.contains(&Status::Filter) {
|
||||||
if fd.selected_panel == panel {
|
if fd.selected_panel == panel {
|
||||||
block = block.border_style(Style::default().fg(colors.borders.selected));
|
block = block.border_style(Style::default().fg(colors.borders.selected));
|
||||||
|
|||||||
+2
-3
@@ -237,8 +237,8 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if crossterm::event::poll(POLL_RATE).unwrap_or(false) {
|
if crossterm::event::poll(POLL_RATE).unwrap_or(false)
|
||||||
if let Ok(event) = event::read() {
|
&& let Ok(event) = event::read() {
|
||||||
if let Event::Key(key) = event {
|
if let Event::Key(key) = event {
|
||||||
if key.kind == event::KeyEventKind::Press {
|
if key.kind == event::KeyEventKind::Press {
|
||||||
self.input_tx
|
self.input_tx
|
||||||
@@ -264,7 +264,6 @@ impl Ui {
|
|||||||
self.gui_state.lock().set_screen_width(width);
|
self.gui_state.lock().set_screen_width(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.check_clear();
|
self.check_clear();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user