Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion helix-cli/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::metrics_sender::MetricsSender;
use crate::project::{ProjectContext, get_helix_repo_cache};
use crate::utils::{
copy_dir_recursive_excluding, diagnostic_source, helixc_utils::collect_hx_files, print_status,
print_success,
print_success, Spinner,
};
use eyre::Result;
use std::time::Instant;
Expand Down Expand Up @@ -90,7 +90,10 @@ pub async fn run(instance_name: String, metrics_sender: &MetricsSender) -> Resul
DockerManager::check_runtime_available(runtime)?;
let docker = DockerManager::new(&project);

let mut spinner = Spinner::new("DOCKER", "Building Docker image...");
spinner.start();
docker.build_image(&instance_name, instance_config.docker_build_target())?;
spinner.stop();
}

print_success(&format!("Instance '{instance_name}' built successfully"));
Expand Down
14 changes: 12 additions & 2 deletions helix-cli/src/commands/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::config::{CloudConfig, InstanceInfo};
use crate::docker::DockerManager;
use crate::metrics_sender::MetricsSender;
use crate::project::ProjectContext;
use crate::utils::{print_status, print_success};
use crate::utils::{print_status, print_success, Spinner};
use eyre::Result;
use std::time::Instant;

Expand Down Expand Up @@ -136,7 +136,11 @@ async fn push_cloud_instance(

let metrics_data = if instance_config.should_build_docker_image() {
// Build happens, get metrics data from build
crate::commands::build::run(instance_name.to_string(), metrics_sender).await?
let mut spinner = Spinner::new("BUILD", "Building instance...");
spinner.start();
let result = crate::commands::build::run(instance_name.to_string(), metrics_sender).await;
spinner.stop();
result?
} else {
// No build, use lightweight parsing
parse_queries_for_metrics(project)?
Expand All @@ -149,8 +153,11 @@ async fn push_cloud_instance(
// 3. Triggering deployment on the cloud

let config = project.config.cloud.get(instance_name).unwrap();
let mut deploy_spinner = Spinner::new("DEPLOY", "Deploying instance...");
deploy_spinner.start();
match config {
CloudConfig::FlyIo(config) => {
deploy_spinner.update("Deploying to Fly.io...");
let fly = FlyManager::new(project, config.auth_type.clone()).await?;
let docker = DockerManager::new(project);
// Get the correct image name from docker compose project name
Expand All @@ -160,6 +167,7 @@ async fn push_cloud_instance(
.await?;
}
CloudConfig::Ecr(config) => {
deploy_spinner.update("Deploying to ECR...");
let ecr = EcrManager::new(project, config.auth_type.clone()).await?;
let docker = DockerManager::new(project);
// Get the correct image name from docker compose project name
Expand All @@ -169,10 +177,12 @@ async fn push_cloud_instance(
.await?;
}
CloudConfig::Helix(_config) => {
deploy_spinner.update("Deploying to Helix...");
let helix = HelixManager::new(project);
helix.deploy(None, instance_name.to_string()).await?;
}
}
deploy_spinner.stop();

print_status("UPLOAD", &format!("Uploading to cluster: {cluster_id}"));

Expand Down
3 changes: 1 addition & 2 deletions helix-cli/src/docker.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these print statements removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry i forget to revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -547,15 +547,14 @@ networks:
self.runtime.label(),
&format!("Building image for instance '{instance_name}'..."),
);

let output = self.run_compose_command(instance_name, vec!["build"])?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(eyre!("{} build failed:\n{stderr}", self.runtime.binary()));
}

print_status(self.runtime.label(), "Image built successfully");

Ok(())
}

Expand Down
75 changes: 75 additions & 0 deletions helix-cli/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use color_eyre::owo_colors::OwoColorize;
use eyre::{Result, eyre};
use helix_db::helixc::parser::types::HxFile;
use std::{borrow::Cow, fs, path::Path};
use tokio::sync::oneshot;
use tokio::time::Duration;
use std::io::IsTerminal;


const IGNORES: [&str; 3] = ["target", ".git", ".helix"];

Expand Down Expand Up @@ -360,3 +364,74 @@ pub mod helixc_utils {
Ok(())
}
}

pub struct Spinner {
message: std::sync::Arc<std::sync::Mutex<String>>,
prefix: String,
stop_tx: Option<oneshot::Sender<()>>,
handle: Option<tokio::task::JoinHandle<()>>,
}

impl Spinner {
pub fn new(prefix: &str, message: &str) -> Self {
Self {
message: std::sync::Arc::new(std::sync::Mutex::new(message.to_string())),
prefix: prefix.to_string(),
stop_tx: None,
handle: None,
}
}
// function that starts the spinner
pub fn start(&mut self) {
if !std::io::stdout().is_terminal() {
return; // skip animation for non-interactive terminals
}
let message = self.message.clone();
let prefix = self.prefix.clone();
let (tx, mut rx) = oneshot::channel::<()>();

let handle = tokio::spawn(async move {
let frames = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
let mut frame_idx = 0;
loop {
if rx.try_recv().is_ok() {
break;
}
let frame = frames[frame_idx % frames.len()];
let msg = message.lock().unwrap().clone();
print!(
"\r{} {frame} {msg}",
format!("[{prefix}]").blue().bold()
);
std::io::Write::flush(&mut std::io::stdout()).unwrap();
frame_idx += 1;
tokio::time::sleep(Duration::from_millis(100)).await;
}
});
self.handle = Some(handle);
self.stop_tx = Some(tx);
}
// function that Stops the spinner
pub fn stop(&mut self) {
if let Some(tx) = self.stop_tx.take() {
let _ = tx.send(());
}
if let Some(handle) = self.handle.take() {
handle.abort();
}
print!("\r");
std::io::Write::flush(&mut std::io::stdout()).unwrap();
}
/// function that updates the message
pub fn update(&mut self, message: &str) {
if let Ok(mut msg) = self.message.lock() {
*msg = message.to_string();
}
}
}

impl Drop for Spinner {
fn drop(&mut self) {
self.stop();
}
}
Loading