#![feature(oneshot_channel)] use std::fs; use std::fs::OpenOptions; use std::io::BufReader; use std::io::Read; use std::io::Write; use std::sync::oneshot; use std::thread; use std::time::Duration; use chrono::TimeDelta; use clap::ArgAction; use marts::generated::spacetime::RemoteProcedures; use marts::generated::spacetime::export_timetrack; use chrono::Local; use marts::generated::spacetime::first_timetrack_date; use marts::timetrack; use marts::generated::spacetime::add_thought; use tracing::info; use ciborium::Value; use clap::Arg; use clap::ArgMatches; use clap::Command; use cmd_lib::run_cmd as sh; use cmd_lib::run_fun as shc; use dioxus::html::g::format; use indoc::concatdoc as str; use marts::CliPart; use marts::ClientAuth; use mize::Mize; use mize::MizeError; use mize::MizePart; use mize::MizePartCreate; use mize::MizeResult; use mize::data; use mize::item::{IntoItemData, ItemData}; use mize::mize_err; use mize::mize_part; use mize::prelude::*; use mize::proto::MessageCmd; use mize::proto::MizeMessage; static MIZE_SRC: &str = "/home/me/work/config/mize"; static SRC: &str = "/home/me/work/config"; static RSYNC_EXCLUDES: &str = "--exclude=node_modules --exclude=target --exclude=mize_config.toml --exclude=rust_dist --exclude=deno_dist --exclude=dist --exclude=result --exclude=pkg"; pub fn lush_os_main() -> MizeResult<()> { println!("main on lush..."); let mut config = ItemData::from_cbor(data! { //spacetime.url = "" }); config.set_path("store", "/home/me/host/mize")?; config.set_path("data_dir", "/home/me/host/mize/misc")?; config.set_path("log.level", "debug")?; config.set_path("log.stderr.enable", true)?; config.set_path("cli.daemonMode", true)?; config.set_path("c2vi.dash.enable", true)?; config.set_path("auth.client.refresh_thread", true)?; let mut mize = mize::Mize::with_config(config)?; marts::cli(&mut mize)?; marts::part_client_auth(&mut mize)?; marts::spacetime(&mut mize)?; marts::timetrack::timetrack(&mut mize)?; marts::c2vi(&mut mize)?; mize.run() } pub fn remote_deploy(matches: &ArgMatches, _: Mize, hostname: &str) -> MizeResult<()> { unsafe { /* std::env::set_var( "PATH", "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", ); */ std::env::set_var("SRC", SRC); std::env::set_var("HOSTNAME", hostname); } let mut do_mize_restart = false; let bin = match matches.get_one::("bin") { Some(val) => val.to_owned(), None => { do_mize_restart = true; format!("{}-os", hostname) } }; let remote_src_dir = match hostname { "lush" => "/home/me/here/config", "mac" => "/data/external/config", "files" => "/home/files/here/config", "nico" => "/root/work/config-c2vi", "ppc-hosting" => "/root/host/c2vi-config", _ => "main-idk", }; let mize_store_dir = match hostname { "lush" => "/home/me/host/mize", "mac" => "/home/me/host/mize", "files" => "/home/files/storage/files/mize", "nico" => "/root/work/app-data/mize", "ppc-hosting" => "/root/host/mize", _ => "/tmp/idk", }; let rclone_flag = match hostname { "nico" => "--chown=root:root", _ => "", }; sh!(rsync -r -u -v -a --delete --perms $rclone_flag --include=".git/" --include=".git/**" --exclude="target" --mkpath $RSYNC_EXCLUDES $SRC/ $hostname:$remote_src_dir)?; let ssh_cmd = format!( r#" if ! tmux has-session -t mize-deploy 2>/dev/null; then echo "Created new tmux session...." tmux new-session -d -s mize-deploy "nix develop git+file://{remote_src_dir}/mize#buildShell --max-jobs 1" else echo "using existing session..." fi tmux send-keys -t mize-deploy "DO_MIZE_RESTART={do_mize_restart}" Enter tmux send-keys -t mize-deploy "cargo build --manifest-path {remote_src_dir}/Cargo.toml --bin {bin}" Enter tmux send-keys -t mize-deploy 'BUILD_SUCCESS=$?' Enter tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > {mize_store_dir}/daemon.env' Enter tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && echo "MIZE_CONFIG_FILES={mize_store_dir}/config.toml" >> {mize_store_dir}/daemon.env' Enter tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && [[ "$HOSTNAME" == "nico" ]] && echo "PATH=/root/work/path-extra:$PATH" >> {mize_store_dir}/daemon.env' Enter tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && [[ "$DO_MIZE_RESTART" == "true" ]] && systemctl --user restart mize' Enter "# ); sh!(ssh $hostname $ssh_cmd)?; Ok(()) } #[mize_part] #[derive(Default)] struct MizeDev { mize: Mize, } impl MizePart for MizeDev {} impl MizePartCreate for MizeDev {} pub fn md(mize: &mut Mize) -> MizeResult<()> { let mut cli = mize.get_part_native::("cli")?; cli.set_command("md"); let bin_arg = Arg::new("bin").short('b'); cli.subcommand( Command::new("deploy-lush").alias("dlu").arg(&bin_arg), Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "lush")), )?; cli.subcommand( Command::new("deploy-mac").alias("dmc").arg(&bin_arg), Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "mac")), )?; cli.subcommand( Command::new("deploy-files").alias("dfi").arg(&bin_arg), Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "files")), )?; cli.subcommand( Command::new("deploy-ppc").alias("dpp").arg(&bin_arg), Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "ppc-hosting")), )?; cli.subcommand( Command::new("deploy-nico").alias("dni").arg(&bin_arg), Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "nico")), )?; cli.subcommand( Command::new("deploy-main").alias("dma").arg(&bin_arg), Box::new(main_deploy), )?; cli.subcommand( Command::new("deploy-obsidian").alias("do").arg(&bin_arg), Box::new(obsidian_deploy), )?; cli.subcommand( Command::new("deploy-spacetime").alias("dsp").arg(&bin_arg), Box::new(deploy_spacetime), )?; cli.subcommand( Command::new("generate").alias("gen").arg(&bin_arg), Box::new(md_generate), )?; mize.register_part(Box::new(MizeDev { mize: mize.clone() })) } pub fn gen_file(path: &str, content: &str) -> MizeResult<()> { sh!(touch $SRC/generated/$path)?; std::fs::write(format!("{}/generated/{}", SRC, path), content)?; Ok(()) } pub fn gen_file_absolute(path: &str, content: &str) -> MizeResult<()> { sh!(touch $path)?; std::fs::write(path, content)?; Ok(()) } pub fn gen_main_rs(name: &str) -> MizeResult<()> { let fn_name = name.replace("-", "_"); let fn_name = format!("{}_main", fn_name); gen_file(format!("{}.rs", name).as_str(), format!(r#" fn main() {{ if let Err(err) = c2vi_part::{fn_name}() {{ err.log(); }} }} "#).as_str())?; OpenOptions::new().append(true).open(format!("{}/generated/Cargo.toml", SRC))?.write(format!(r#" [[bin]] name = "{name}" path = "{name}.rs" "#).as_bytes())?; Ok(()) } pub fn md_generate(_: &ArgMatches, mize: Mize) -> MizeResult<()> { sh!(touch $SRC/generated/Cargo.toml)?; sh!(mkdir -p $SRC/generated/src)?; fs::write(format!("{}/generated/Cargo.toml", SRC), format!(r#" [package] name = "generated-c2vi-dev-part" version = "0.1.0" edition = "2024" [dependencies] c2vi-dev-part.path = "../dev-part" "#).as_bytes())?; gen_main_rs("lush-os")?; gen_main_rs("main-os")?; gen_main_rs("mac-os")?; gen_main_rs("nico-os")?; gen_main_rs("mppc")?; gen_main_rs("timetrack-waybar")?; gen_main_rs("md")?; gen_main_rs("dev")?; gen_file_absolute(format!("{SRC}/mize/marts/generated/Cargo.toml").as_str(), str!(r#" [package] name = "generated" version = "0.1.0" edition = "2021" [lib] name = "generated" path = "src/lib.rs" [dependencies] spacetimedb-sdk = "2.6.0" [features] target-js = [ "spacetimedb-sdk/browser" ] "#))?; gen_file_absolute(format!("{SRC}/mize/marts/generated/src/lib.rs").as_str(), str!(r#" pub mod spacetime; "#))?; sh!(RUST_LOG=error RUST_BACKTRACE=0 spacetime generate --build-options="--lint-dir=" -p $SRC/mize/marts/spacetime -o $SRC/mize/marts/generated/src/spacetime --lang rust)?; Ok(()) } pub fn deploy_spacetime(_: &ArgMatches, _: Mize) -> MizeResult<()> { unsafe { /* std::env::set_var( "PATH", "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", ); */ std::env::set_var("SRC", SRC); } let cmd = format!( r#" if ! tmux has-session -t mize-deploy 2>/dev/null; then echo "Created new tmux session...." systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize --impure" else echo "using existing session..." tmux send-keys -t mize-deploy "echo hoooooooooooooo" Enter fi tmux send-keys -t mize-deploy "spacetime publish -p $SRC/mize/packages/spacetime/ --yes mize" Enter "# ); sh!(/bin/sh -c "$cmd")?; Ok(()) } pub fn obsidian_deploy(_: &ArgMatches, _: Mize) -> MizeResult<()> { unsafe { std::env::set_var( "PATH", "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", ); std::env::set_var("SRC", SRC); } let cmd = format!( r#" if ! tmux has-session -t mize-deploy 2>/dev/null; then echo "Created new tmux session...." systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize --impure" else echo "using existing session..." fi tmux send-keys -t mize-deploy "deno run --config {SRC}/mize/packages/ppc/platform/obsidian/deno.json build" Enter tmux send-keys -t mize-deploy "cp -r {SRC}/mize/packages/ppc/platform/obsidian/dist/* ~/work/things/.obsidian/plugins/mize/" Enter "# ); sh!(/bin/sh -c "$cmd")?; Ok(()) } pub fn main_deploy(_: &ArgMatches, _: Mize) -> MizeResult<()> { unsafe { std::env::set_var( "PATH", "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", ); std::env::set_var("SRC", SRC); } let cmd = str!( r#" if ! tmux has-session -t mize-deploy 2>/dev/null; then systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize#buildShell" tmux send-keys -t mize-deploy "set -e" Enter tmux send-keys -t mize-deploy "cargo build --manifest-path $SRC/parts/Cargo.toml --bin main-os" Enter tmux send-keys -t mize-deploy 'echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /home/me/work/app-data/mize/daemon.env' Enter tmux send-keys -t mize-deploy "systemctl --user restart mize" Enter else echo "using existing session..." tmux send-keys -t mize-deploy "cargo build --manifest-path $SRC/parts/Cargo.toml --bin main-os" Enter tmux send-keys -t mize-deploy 'echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /home/me/work/app-data/mize/daemon.env' Enter tmux send-keys -t mize-deploy "systemctl --user restart mize" Enter fi "# ); sh!(/bin/sh -c "$cmd")?; Ok(()) } pub fn main_os_main() -> MizeResult<()> { println!("os daemon on main..."); let mut config = ItemData::new(); config.set_path("store", "/home/me/work/app-data/mize")?; config.set_path("log.level", "debug")?; config.set_path("log.stderr.enable", true)?; config.set_path("cli.daemonMode", true)?; config.set_path("c2vi.dash.enable", false)?; config.set_path("auth.client.refresh_thread", true)?; unsafe { std::env::set_var("RUST_BACKTRACE", "1"); } let mut mize = mize::Mize::with_config(config)?; marts::cli(&mut mize)?; marts::part_client_auth(&mut mize)?; let mut auth = mize.get_part_native::("client_auth")?; if auth.secrets().is_none() { auth.login()?; } drop(auth); md(&mut mize)?; marts::spacetime(&mut mize)?; marts::timetrack::timetrack(&mut mize)?; part_add_thought(&mut mize)?; marts::c2vi(&mut mize)?; //ppc::daemon(&mut mize)?; // testing(&mut mize)?; mize.run()?; mize.wait(); Ok(()) } pub fn testing(mize: &mut mize::Mize) -> MizeResult<()> { let test = str! {r#" a = "hello" # a comment b = true "#}; //let a = mizelang::parse(test)?; //println!("data: {}", a); Ok(()) } pub fn mize_thin_cli_client(bin_name: Option<&str>) -> MizeResult<()> { use std::io::Write; use std::os::unix::net::UnixStream; let store_path = std::env::var("MIZE_STORE").map_err(|_| mize_err!("MIZE_STORE not set in environment"))?; let sock_path = store_path + "/sock"; println!("sock_path: {}", sock_path); let mut cmd_line = std::env::args().collect::>(); if let Some(bin_name) = bin_name { cmd_line[0] = bin_name.to_owned(); } let msg = MizeMessage::new_custom("cli", cmd_line, 0); let mut stream = UnixStream::connect(sock_path)?; stream.write_all(&msg.bytes())?; // Optional: Ensure all buffered data is pushed to the socket stream.flush()?; let mut reader = BufReader::new(stream.try_clone()?); loop { let msg: Value = ciborium::from_reader(&mut reader)?; let mut msg = MizeMessage::new(msg, 0); match msg.cmd()? { MessageCmd::Custom(kind) => { if kind == "cli.done".into_item_data() { break; } if kind == "cli.stdout".into_item_data() { println!("{}", msg.data()?.value_string()?); } if kind == "cli.stderr".into_item_data() { eprintln!("{}", msg.data()?.value_string()?); } if kind == "cli.spawn".into_item_data() { let cmd = msg.data()?.value_string()?; std::process::Command::new("/bin/sh") .arg("-c") .arg(&cmd) .status()?; let done_msg = MizeMessage::new_custom("cli.spawn_done", ItemData::new(), 0); stream.write_all(&done_msg.bytes())?; } } _ => { continue; } } } Ok(()) } pub fn dma_local() -> MizeResult<()> { println!("running dma_local..."); unsafe { std::env::set_var( "PATH", "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", ); std::env::set_var("SRC", SRC); } let cmd = str!( r#" if ! tmux has-session -t mize-deploy 2>/dev/null; then echo "Created new tmux session...." systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "NIXPKGS_ALLOW_UNFREE=1 nix develop git+file://$SRC/mize --impure" else echo "using existing session..." fi tmux send-keys -t mize-deploy "cargo build --manifest-path $SRC/Cargo.toml --bin main-os" Enter tmux send-keys -t mize-deploy 'echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /home/me/work/app-data/mize/daemon.env' Enter tmux send-keys -t mize-deploy 'echo "PATH=$PATH" >> /home/me/work/app-data/mize/daemon.env' Enter tmux send-keys -t mize-deploy "systemctl --user restart mize" Enter "# ); sh!(/bin/sh -c "$cmd")?; Ok(()) } pub fn md_main() -> MizeResult<()> { // run md dma locally let args: Vec = std::env::args().collect(); if args.get(1).map(|s| s.as_str()) == Some("dma") { dma_local()?; return Ok(()); } if args.get(1).map(|s| s.as_str()) == Some("dev") { sh!(dx serve --hot-reload true --bin dev)?; return Ok(()); } mize_thin_cli_client(None) } pub fn mppc_main() -> MizeResult<()> { mize_thin_cli_client(Some("ppc")) } pub fn dev_main() -> MizeResult<()> { use dioxus::desktop::{Config, WindowBuilder, muda::Menu}; use dioxus::prelude::*; let mize = Mize::new(); let mize_clone = mize.clone(); LaunchBuilder::new() .with_context_provider(move || Box::new(mize_clone.clone())) .with_cfg(desktop! { Config::new().with_window(WindowBuilder::new().with_decorations(false).with_title("PPC")) }) .launch(marts::ppc::main_page); Ok(()) } pub fn timetrack_waybar_main() -> MizeResult<()> { use std::io::Write; use std::os::unix::net::UnixStream; let store_path = std::env::var("MIZE_STORE").map_err(|_| mize_err!("MIZE_STORE not set in environment"))?; let sock_path = store_path + "/sock"; let out_msg = MizeMessage::new_custom("timetrack.sub_current", ItemData::new(), 0); let mut stream = UnixStream::connect(&sock_path)?; stream.write_all(&out_msg.bytes())?; // Optional: Ensure all buffered data is pushed to the socket stream.flush()?; let mut reader = BufReader::new(stream.try_clone()?); loop { let msg: Value = match ciborium::from_reader(&mut reader) { Ok(val) => val, Err(_) => { fn read_msg(out_msg: &MizeMessage, sock_path: &String) -> MizeResult { thread::sleep(Duration::from_secs(12)); let mut stream = UnixStream::connect(sock_path)?; stream.write_all(&out_msg.bytes())?; stream.flush()?; let mut reader = BufReader::new(stream.try_clone()?); let val: Value = ciborium::from_reader(&mut reader)?; Ok(val) }; match read_msg(&out_msg, &sock_path) { Ok(val) => val, Err(_) => { continue; } } } }; let mut msg = MizeMessage::new(msg, 0); match msg.cmd()? { MessageCmd::Custom(kind) => { if kind == "timetrack.current".into_item_data() { //println!("----> {} <----", msg.data()?.value_string()?); println!("{}", msg.data()?.value_string()?); } } _ => { continue; } } } Ok(()) } pub fn mac_os_main() -> MizeResult<()> { println!("os daemon on mac..."); let mut config = ItemData::new(); config.set_path("store", "/home/me/host/mize")?; config.set_path("data_dir", "/home/me/host/mize/misc")?; config.set_path("log.level", "debug")?; config.set_path("log.stderr.enable", true)?; config.set_path("cli.daemonMode", true)?; config.set_path("c2vi.dash.enable", false)?; config.set_path("auth.client.refresh_thread", true)?; //unsafe { std::env::set_var("RUST_BACKTRACE", "1"); } let mut mize = mize::Mize::with_config(config)?; marts::cli(&mut mize)?; marts::part_client_auth(&mut mize)?; let mut auth = mize.get_part_native::("client_auth")?; if auth.secrets().is_none() { tracing::info!("main: auth.secrets is none"); auth.login()?; } drop(auth); md(&mut mize)?; marts::spacetime(&mut mize)?; marts::timetrack::timetrack(&mut mize)?; part_add_thought(&mut mize)?; marts::c2vi(&mut mize)?; mize.run()?; mize.wait(); Ok(()) } pub fn nico_os_main() -> MizeResult<()> { println!("os daemon on nico..."); let mut config = ItemData::new(); config.set_path("store", "/root/work/app-data/mize")?; config.set_path("data_dir", "/root/work/app-data/mize/misc")?; config.set_path("log.level", "debug")?; config.set_path("log.stderr.enable", true)?; config.set_path("cli.daemonMode", true)?; config.set_path("c2vi.dash.enable", false)?; config.set_path("auth.client.refresh_thread", true)?; config.set_path("sc2.userNotesDir", "/root/work/nico/notes/c2vi")?; let mut mize = mize::Mize::with_config(config)?; marts::cli(&mut mize)?; marts::part_client_auth(&mut mize)?; let mut auth = mize.get_part_native::("client_auth")?; if auth.secrets().is_none() { tracing::info!("main: auth.secrets is none"); auth.login()?; } drop(auth); marts::spacetime(&mut mize)?; part_timetrack_export(&mut mize)?; // notes sync let mize_clone = mize.clone(); mize.spawn_background("nico_notes_sync", || nico_notes_sync_thread(mize_clone))?; marts::c2vi(&mut mize)?; mize.run()?; mize.wait(); Ok(()) } pub fn part_add_thought(mize: &mut Mize) -> MizeResult<()> { use marts::generated::spacetime::add_thought; let mut cli = mize.get_part_native::("cli")?; cli.set_command("ppc"); cli.subcommand(Command::new("inputThought").alias("ti"), |matches, mut mize| { let tmp_file = std::env::temp_dir().join(format!( "sc2-input-thought-{}.txt", chrono::Utc::now().timestamp() )); marts::cli_spawn(format!("nvim {}", tmp_file.display()))?; let new_file_content = std::fs::read_to_string(&tmp_file) .map_err(|e| mize_err!("Failed to read temp file: {}", e))?; let _ = std::fs::remove_file(&tmp_file); let spacetime = mize.get_part_native::("spacetime")?; spacetime.con().reducers.add_thought(new_file_content)?; Ok(()) })?; Ok(()) } pub fn part_timetrack_export(mize: &mut Mize) -> MizeResult<()> { use std::path::Path; let mut cli = mize.get_part_native::("cli")?; cli.set_command("ppc"); cli.subcommand(Command::new("exportTimetrack").alias("et").arg(Arg::new("date").short('d')).arg(Arg::new("all").short('a').action(ArgAction::SetTrue)), |matches , mut mize| { let spacetime = mize.get_part_native::("spacetime")?; let notes_dir = mize.get_config("sc2.userNotesDir").unwrap_or_default().value_string()?; let today = Local::now().format("%Y-%m-%d").to_string(); let mut date = matches.get_one::("date").unwrap_or(&today); std::fs::create_dir_all(Path::new(¬es_dir).join("timetrack_exports"))?; let all = matches.get_flag("all"); if all { let (tx, rx) = oneshot::channel(); spacetime.con().procedures.first_timetrack_date_then("c2vi".to_string(), |_, res| {tx.send(res);}); let res = rx.recv()???; let dates = dates_until_today(&res)?; for date in dates { out!("date: {}", date); let (tx, rx) = oneshot::channel(); spacetime.con().procedures.export_timetrack_then("c2vi".to_string(), date.to_owned(), |_, res| {tx.send(res);}); let res = rx.recv()???; let mut file = OpenOptions::new().create(true).write(true).open(Path::new(¬es_dir).join("timetrack_exports").join(format!("timetrack_export_{}.md", date)))?; file.write_all(res.as_bytes())?; } return Ok(()); } out!("date: {}", date); let (tx, rx) = oneshot::channel(); spacetime.con().procedures.export_timetrack_then("c2vi".to_string(), date.to_owned(), |_, res| {tx.send(res);}); let res = rx.recv()???; let mut file = OpenOptions::new().create(true).write(true).open(Path::new(¬es_dir).join("timetrack_exports").join(format!("timetrack_export_{}.md", date)))?; file.write_all(res.as_bytes())?; Ok(()) })?; Ok(()) } fn dates_until_today(start: &str) -> Result, chrono::ParseError> { use chrono::NaiveDate; let mut current = NaiveDate::parse_from_str(start, "%Y-%m-%d")?; let today = Local::now().date_naive(); let mut dates = Vec::new(); while current <= today { dates.push(current.format("%Y-%m-%d").to_string()); current += TimeDelta::days(1); } Ok(dates) } pub fn nico_notes_sync_thread(mize: Mize) -> MizeResult<()> { tracing::info!("starting nico_notes_sync_thread"); loop { let res = sh!(/bin/bash -c r#" cd /root/work/nico/notes/c2vi git add . git commit -m "nico notes sync" git pull --rebase git push cd /root/work/nico/notes/nexus git add . git commit -m "nico nexus notes sync" git pull --rebase git push cd /root/work/nico/notes/ppc-wiki git add . git commit -m "nico ppc-wiki notes sync" git pull --rebase git push "#); if let Err(e) = res { tracing::error!("error in nico_notes_sync_thread: {}", e); }; std::thread::sleep(std::time::Duration::from_mins(2)); } }