on main help sign in
refactor: now make cli more consistent
2ef4011robcholz
docs/tasks.md+2−1
@@ -48,7 +48,8 @@
48 3. [x] add an actual config file.
48 3. [x] add an actual config file.
49 4. [x] set up the cli.
49 4. [x] set up the cli.
509. [ ] fix ui overlap, and consistency issue.
509. [ ] fix ui overlap, and consistency issue.
51+10. [ ] `clean_cache` to cleanup the cache.
51−10. [ ] intensive integration test.
52+11. [ ] intensive integration test.
52
53
53## Publish
54## Publish
54
55
src/bin/vibebox-cli.rs+57−11
@@ -11,7 +11,8 @@ use color_eyre::Result;
11use dialoguer::Confirm;
11use dialoguer::Confirm;
12use time::OffsetDateTime;
12use time::OffsetDateTime;
13use time::format_description::well_known::Rfc3339;
13use time::format_description::well_known::Rfc3339;
14−use tracing_subscriber::EnvFilter;
14+use tracing_subscriber::filter::LevelFilter;
15+use tracing_subscriber::{EnvFilter, fmt, prelude::*};
15
16
16use vibebox::tui::{AppState, VmInfo};
17use vibebox::tui::{AppState, VmInfo};
17use vibebox::{
18use vibebox::{
@@ -39,11 +40,11 @@ enum Command {
39}
40}
40
41
41fn main() -> Result<()> {
42fn main() -> Result<()> {
42− init_tracing();
43 color_eyre::install()?;
43 color_eyre::install()?;
44+ let cwd = env::current_dir().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?;
45+ init_tracing(&cwd);
44
46
45 let cli = Cli::parse();
47 let cli = Cli::parse();
46− let cwd = env::current_dir().map_err(|err| color_eyre::eyre::eyre!(err.to_string()))?;
47 tracing::info!(cwd = %cwd.display(), "starting vibebox cli");
48 tracing::info!(cwd = %cwd.display(), "starting vibebox cli");
48 if let Some(command) = cli.command {
49 if let Some(command) = cli.command {
49 return handle_command(command, &cwd, cli.config.as_deref());
50 return handle_command(command, &cwd, cli.config.as_deref());
@@ -249,13 +250,58 @@ fn format_last_active(value: Option<&str>) -> String {
249 format!("{} day{} ago", days, if days == 1 { "" } else { "s" })
250 format!("{} day{} ago", days, if days == 1 { "" } else { "s" })
250}
251}
251
252
252−fn init_tracing() {
253+fn init_tracing(cwd: &Path) {
253 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
254 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
255+ let stderr_is_tty = std::io::stderr().is_terminal();
254− let ansi = std::io::stderr().is_terminal() && env::var("VIBEBOX_LOG_NO_COLOR").is_err();
256+ let ansi = stderr_is_tty && env::var("VIBEBOX_LOG_NO_COLOR").is_err();
255− let _ = tracing_subscriber::fmt()
257+ let file = instance::ensure_instance_dir(cwd)
256− .with_env_filter(filter)
258+ .ok()
259+ .and_then(|instance_dir| {
260+ let log_path = instance_dir.join("cli.log");
261+ std::fs::OpenOptions::new()
262+ .create(true)
263+ .write(true)
264+ .truncate(true)
265+ .open(log_path)
266+ .ok()
267+ });
268+
269+ if stderr_is_tty {
270+ let stderr_layer = fmt::layer()
271+ .with_target(false)
272+ .with_ansi(ansi)
273+ .without_time()
274+ .with_writer(std::io::stderr)
275+ .with_filter(LevelFilter::INFO);
276+ let subscriber = tracing_subscriber::registry()
277+ .with(filter)
278+ .with(stderr_layer);
279+ if let Some(file) = file {
280+ let file_layer = fmt::layer()
257− .with_target(false)
281+ .with_target(false)
282+ .with_ansi(false)
283+ .with_writer(file);
284+ let _ = subscriber.with(file_layer).try_init();
285+ } else {
286+ let _ = subscriber.try_init();
287+ }
288+ } else {
289+ let stderr_layer = fmt::layer()
290+ .with_target(false)
258− .with_ansi(ansi)
291+ .with_ansi(ansi)
259− .with_writer(std::io::stderr)
292+ .with_writer(std::io::stderr)
293+ .with_filter(LevelFilter::INFO);
294+ let subscriber = tracing_subscriber::registry()
295+ .with(filter)
296+ .with(stderr_layer);
297+ if let Some(file) = file {
298+ let file_layer = fmt::layer()
299+ .with_target(false)
300+ .with_ansi(false)
301+ .with_writer(file);
302+ let _ = subscriber.with(file_layer).try_init();
303+ } else {
260− .try_init();
304+ let _ = subscriber.try_init();
305+ }
306+ }
261}
307}
src/bin/vibebox-supervisor.rs+21−7
@@ -5,6 +5,9 @@ use std::{
5
5
6use color_eyre::Result;
6use color_eyre::Result;
7use tracing_subscriber::EnvFilter;
7use tracing_subscriber::EnvFilter;
8+use tracing_subscriber::filter::LevelFilter;
9+use tracing_subscriber::fmt;
10+use tracing_subscriber::prelude::*;
8
11
9use vibebox::{config, instance, vm, vm_manager};
12use vibebox::{config, instance, vm, vm_manager};
10
13
@@ -40,11 +43,22 @@ fn main() -> Result<()> {
40
43
41fn init_tracing() {
44fn init_tracing() {
42 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
45 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
46+ let stderr_is_tty = std::io::stderr().is_terminal();
43− let ansi = std::io::stderr().is_terminal() && env::var("VIBEBOX_LOG_NO_COLOR").is_err();
47+ let ansi = stderr_is_tty && env::var("VIBEBOX_LOG_NO_COLOR").is_err();
48+ if stderr_is_tty {
49+ let stderr_layer = fmt::layer()
50+ .with_target(false)
51+ .with_ansi(ansi)
52+ .without_time()
53+ .with_writer(io::stderr)
54+ .with_filter(LevelFilter::INFO);
44− let _ = tracing_subscriber::fmt()
55+ let _ = tracing_subscriber::registry().with(stderr_layer).try_init();
45− .with_env_filter(filter)
56+ } else {
46− .with_target(false)
57+ let stderr_layer = fmt::layer()
47− .with_ansi(ansi)
58+ .with_target(false)
48− .with_writer(io::stderr)
59+ .with_ansi(ansi)
49− .try_init();
60+ .with_writer(io::stderr)
61+ .with_filter(filter);
62+ let _ = tracing_subscriber::registry().with(stderr_layer).try_init();
63+ }
50}
64}
src/instance.rs+9−3
@@ -72,7 +72,6 @@ pub fn run_with_ssh(manager_conn: UnixStream) -> Result<(), Box<dyn std::error::
72 tracing::debug!(ssh_user = %ssh_user, "loaded instance config");
72 tracing::debug!(ssh_user = %ssh_user, "loaded instance config");
73
73
74 let _manager_conn = manager_conn;
74 let _manager_conn = manager_conn;
75− tracing::debug!("waiting for vm ipv4");
76 wait_for_vm_ipv4(&instance_dir, Duration::from_secs(120))?;
75 wait_for_vm_ipv4(&instance_dir, Duration::from_secs(120))?;
77
76
78 let ip = load_or_create_instance_config(&instance_dir)?
77 let ip = load_or_create_instance_config(&instance_dir)?
@@ -247,7 +246,8 @@ fn wait_for_vm_ipv4(
247) -> Result<(), Box<dyn std::error::Error>> {
246) -> Result<(), Box<dyn std::error::Error>> {
248 let start = Instant::now();
247 let start = Instant::now();
249 let mut next_log_at = start + Duration::from_secs(10);
248 let mut next_log_at = start + Duration::from_secs(10);
250− tracing::debug!("waiting for vm ipv4");
249+ tracing::info!("waiting for vm ipv4");
250+ let mut once_hint = false;
251 loop {
251 loop {
252 let config = load_or_create_instance_config(instance_dir)?;
252 let config = load_or_create_instance_config(instance_dir)?;
253 if config.vm_ipv4.is_some() {
253 if config.vm_ipv4.is_some() {
@@ -258,7 +258,13 @@ fn wait_for_vm_ipv4(
258 }
258 }
259 if Instant::now() >= next_log_at {
259 if Instant::now() >= next_log_at {
260 let waited = start.elapsed();
260 let waited = start.elapsed();
261+ if waited.as_secs() > 15 && !once_hint {
262+ tracing::info!(
263+ "if vibebox is just initialized in this directory, it might take up to 1 minutes depending on your machine, and then you can enjoy the speed vibecoding! go pack!"
264+ );
265+ once_hint = true;
266+ }
261− tracing::debug!("still waiting for vm ipv4, {}s elapsed", waited.as_secs(),);
267+ tracing::info!("still waiting for vm ipv4, {}s elapsed", waited.as_secs(),);
262 next_log_at += Duration::from_secs(10);
268 next_log_at += Duration::from_secs(10);
263 }
269 }
264 thread::sleep(Duration::from_millis(200));
270 thread::sleep(Duration::from_millis(200));