From 0ee763d594223c717e7873611ed373cebef870ef Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Tue, 1 Nov 2022 17:45:58 +0100 Subject: [PATCH 01/22] introduce bundle command --- src/plugin.rs | 13 ++++++++++--- src/plugin/action.rs | 20 ++++++++++++++++++++ src/plugin/action/build.rs | 17 +++++++++++++++++ src/plugin/action/bundle.rs | 9 +++++++++ src/plugin/action/tool.rs | 7 +++++++ src/plugin/async_action.rs | 2 +- src/plugin/cli.rs | 35 ++--------------------------------- src/plugin/handler.rs | 2 +- src/plugin/tool.rs | 2 +- 9 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 src/plugin/action.rs create mode 100644 src/plugin/action/build.rs create mode 100644 src/plugin/action/bundle.rs create mode 100644 src/plugin/action/tool.rs diff --git a/src/plugin.rs b/src/plugin.rs index f77f849..cd3afad 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,9 +1,16 @@ +mod action; mod async_action; mod cli; mod handler; mod tool; -use crate::plugin::{async_action::*, cli::*, handler::*, tool::*}; +use crate::plugin::{ + action::ActionPlugin, + async_action::{AsyncAction, AsyncActionPlugin}, + cli::CliPlugin, + handler::HandlerPlugin, + tool::ToolPlugin, +}; use dip::bevy::app::{App, Plugin}; pub struct DipCliPlugin; @@ -13,7 +20,7 @@ impl Plugin for DipCliPlugin { app.add_plugin(CliPlugin::::application()) .add_plugin(ActionPlugin) .add_plugin(AsyncActionPlugin) - .add_plugin(ToolPlugin) - .add_plugin(HandlerPlugin); + .add_plugin(HandlerPlugin) + .add_plugin(ToolPlugin); } } diff --git a/src/plugin/action.rs b/src/plugin/action.rs new file mode 100644 index 0000000..40618b8 --- /dev/null +++ b/src/plugin/action.rs @@ -0,0 +1,20 @@ +use dip::cli::SubcommandPlugin; + +mod build; +mod bundle; +mod tool; + +pub use build::*; +pub use bundle::*; +pub use tool::*; + +#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] +pub enum Action { + Build(BuildArgs), + + #[clap(subcommand)] + Bundle(BundleAction), + + #[clap(subcommand)] + Tool(ToolAction), +} diff --git a/src/plugin/action/build.rs b/src/plugin/action/build.rs new file mode 100644 index 0000000..ddfe2b2 --- /dev/null +++ b/src/plugin/action/build.rs @@ -0,0 +1,17 @@ +#[derive(clap::Args, Clone, Debug)] +pub struct BuildArgs { + #[clap(short, long, default_value_t = String::from("."))] + pub path: String, + + #[clap(short, long, default_value_t = String::from("tailwind.config.js"))] + pub config: String, + + #[clap(short, long, default_value_t = String::from("styles/style.css"))] + pub input: String, + + #[clap(short, long, default_value_t = String::from("static/style.css"))] + pub output: String, + + #[clap(short, long)] + pub watch: bool, +} diff --git a/src/plugin/action/bundle.rs b/src/plugin/action/bundle.rs new file mode 100644 index 0000000..729e5b1 --- /dev/null +++ b/src/plugin/action/bundle.rs @@ -0,0 +1,9 @@ +use dip::cli::SubcommandPlugin; + +#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] +pub enum BundleAction { + Apply { + #[clap(short, long, required = false)] + verbose: bool, + }, +} diff --git a/src/plugin/action/tool.rs b/src/plugin/action/tool.rs new file mode 100644 index 0000000..d5903ef --- /dev/null +++ b/src/plugin/action/tool.rs @@ -0,0 +1,7 @@ +use dip::cli::SubcommandPlugin; + +#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] +pub enum ToolAction { + List, + Add { name: String }, +} diff --git a/src/plugin/async_action.rs b/src/plugin/async_action.rs index 70ab215..b61236d 100644 --- a/src/plugin/async_action.rs +++ b/src/plugin/async_action.rs @@ -1,5 +1,5 @@ use crate::{ - plugin::BuildAction, + plugin::action::BuildAction, resource::tool::{Tool, ToolResult}, }; use dip::{bevy::ecs::event::EventReader, core::task::async_action}; diff --git a/src/plugin/cli.rs b/src/plugin/cli.rs index 9489719..c4f3857 100644 --- a/src/plugin/cli.rs +++ b/src/plugin/cli.rs @@ -1,4 +1,5 @@ -use dip::cli::{CliPlugin, SubcommandPlugin}; +use crate::plugin::action::{handle_action, Action}; +use dip::cli::CliPlugin; #[derive(CliPlugin, clap::Parser)] #[clap(version)] @@ -6,35 +7,3 @@ struct Cli { #[clap(subcommand)] action: Action, } - -#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] -pub enum Action { - Build(BuildArgs), - - #[clap(subcommand)] - Tool(ToolAction), -} - -#[derive(clap::Args, Clone, Debug)] -pub struct BuildArgs { - #[clap(short, long, default_value_t = String::from("."))] - pub path: String, - - #[clap(short, long, default_value_t = String::from("tailwind.config.js"))] - pub config: String, - - #[clap(short, long, default_value_t = String::from("styles/style.css"))] - pub input: String, - - #[clap(short, long, default_value_t = String::from("static/style.css"))] - pub output: String, - - #[clap(short, long)] - pub watch: bool, -} - -#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] -pub enum ToolAction { - List, - Add { name: String }, -} diff --git a/src/plugin/handler.rs b/src/plugin/handler.rs index b9e45bc..e3c5e25 100644 --- a/src/plugin/handler.rs +++ b/src/plugin/handler.rs @@ -1,5 +1,5 @@ use crate::{ - plugin::{AsyncAction, BuildAction}, + plugin::{action::BuildAction, AsyncAction}, resource::tool::Tool, }; use dip::{ diff --git a/src/plugin/tool.rs b/src/plugin/tool.rs index c961806..44297ee 100644 --- a/src/plugin/tool.rs +++ b/src/plugin/tool.rs @@ -1,5 +1,5 @@ use crate::{ - plugin::{async_action::*, cli::*}, + plugin::{action::*, async_action::*}, resource::tool::{Tool, ToolResult}, }; use dip::{ From a4fe3e9b97a76057699cbafaab4aeac92f31f9ef Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Tue, 1 Nov 2022 18:19:23 +0100 Subject: [PATCH 02/22] remove handler plugin --- src/plugin.rs | 3 - src/plugin/action.rs | 13 +++- src/plugin/action/build.rs | 128 ++++++++++++++++++++++++++++++++++++ src/plugin/handler.rs | 131 ------------------------------------- 4 files changed, 140 insertions(+), 135 deletions(-) delete mode 100644 src/plugin/handler.rs diff --git a/src/plugin.rs b/src/plugin.rs index cd3afad..70b5569 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,14 +1,12 @@ mod action; mod async_action; mod cli; -mod handler; mod tool; use crate::plugin::{ action::ActionPlugin, async_action::{AsyncAction, AsyncActionPlugin}, cli::CliPlugin, - handler::HandlerPlugin, tool::ToolPlugin, }; use dip::bevy::app::{App, Plugin}; @@ -20,7 +18,6 @@ impl Plugin for DipCliPlugin { app.add_plugin(CliPlugin::::application()) .add_plugin(ActionPlugin) .add_plugin(AsyncActionPlugin) - .add_plugin(HandlerPlugin) .add_plugin(ToolPlugin); } } diff --git a/src/plugin/action.rs b/src/plugin/action.rs index 40618b8..4a75034 100644 --- a/src/plugin/action.rs +++ b/src/plugin/action.rs @@ -1,4 +1,7 @@ -use dip::cli::SubcommandPlugin; +use dip::{ + bevy::app::{App, Plugin}, + cli::SubcommandPlugin, +}; mod build; mod bundle; @@ -8,6 +11,14 @@ pub use build::*; pub use bundle::*; pub use tool::*; +pub struct DipActionPlugin; + +impl Plugin for DipActionPlugin { + fn build(&self, app: &mut App) { + app.add_plugin(ActionPlugin).add_plugin(BuildActionPlugin); + } +} + #[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] pub enum Action { Build(BuildArgs), diff --git a/src/plugin/action/build.rs b/src/plugin/action/build.rs index ddfe2b2..eed19cd 100644 --- a/src/plugin/action/build.rs +++ b/src/plugin/action/build.rs @@ -1,3 +1,29 @@ +use crate::{ + plugin::{action::*, AsyncAction}, + resource::tool::Tool, +}; +use dip::{ + bevy::{ + app::{App, AppExit, Plugin}, + ecs::prelude::*, + log, + }, + core::task::AsyncActionPool, +}; +use std::{fs, path::PathBuf, process::Command}; + +pub struct BuildActionPlugin; + +impl Plugin for BuildActionPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_system(handle_build) + .add_system(compile_css.after(handle_build)) + .add_system(build_app.after(handle_build).after(compile_css)); + } +} + #[derive(clap::Args, Clone, Debug)] pub struct BuildArgs { #[clap(short, long, default_value_t = String::from("."))] @@ -15,3 +41,105 @@ pub struct BuildArgs { #[clap(short, long)] pub watch: bool, } + +fn handle_build( + mut actions: EventReader, + mut build_app: EventWriter, + mut compile_css: EventWriter, + async_action: Res>, +) { + for action in actions.iter() { + let tailwind_config = PathBuf::from(&action.path).join("tailwind.config.js"); + + if tailwind_config.is_file() { + let tailwind = &Tool::Tailwind; + + if tailwind.bin_path().is_file() { + compile_css.send(CompileCss { + action: action.clone(), + tool: tailwind.clone(), + }); + } else { + async_action.send(AsyncAction::install_and_build(tailwind, action.clone())); + } + } else { + build_app.send(BuildApp { + action: action.clone(), + }); + } + } +} + +fn build_app(mut events: EventReader, mut app_exit: EventWriter) { + for BuildApp { action } in events.iter() { + let mut cmd = Command::new("cargo"); + + cmd.current_dir(fs::canonicalize(&action.path).unwrap()) + .args(["build"]); + + let output = cmd.output().expect("Could not execute cargo build"); + log::trace!("{output:?}"); + + if output.status.success() { + println!("Build finished"); + } else { + println!("Failed to build project"); + println!("{}", String::from_utf8(output.stderr).unwrap()); + } + + app_exit.send(AppExit); + } +} + +#[derive(Clone, Debug)] +struct BuildApp { + pub action: BuildAction, +} + +#[derive(Clone, Debug)] +struct CompileCss { + pub action: BuildAction, + pub tool: Tool, +} + +fn compile_css( + mut events: EventReader, + mut build_app: EventWriter, + mut app_exit: EventWriter, +) { + for CompileCss { action, tool } in events.iter() { + let mut cmd = Command::new(&tool.bin_path_str()); + + cmd.current_dir(fs::canonicalize(&action.path).unwrap()); + cmd.args([ + "-c", + &action.config, + "-i", + &action.input, + "-o", + &action.output, + ]); + + if action.watch { + cmd.arg("-w"); + } + + let output = cmd + .output() + .expect("Could not execute compilation for Tailwind CSS"); + log::trace!("{output:?}"); + + if output.status.success() { + println!("CSS compiled"); + + build_app.send(BuildApp { + action: action.clone(), + }) + } else { + println!("Failed to compile Tailwind CSS"); + println!("{}", String::from_utf8(output.stderr).unwrap()); + + app_exit.send(AppExit); + } + } +} diff --git a/src/plugin/handler.rs b/src/plugin/handler.rs deleted file mode 100644 index e3c5e25..0000000 --- a/src/plugin/handler.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::{ - plugin::{action::BuildAction, AsyncAction}, - resource::tool::Tool, -}; -use dip::{ - bevy::{ - app::AppExit, - ecs::{ - event::{EventReader, EventWriter}, - schedule::ParallelSystemDescriptorCoercion, - system::Res, - }, - log, - }, - prelude::{AsyncActionPool, Plugin}, -}; -use std::{fs, path::PathBuf, process::Command}; - -pub struct HandlerPlugin; - -impl Plugin for HandlerPlugin { - fn build(&self, app: &mut dip::prelude::App) { - app.add_event::() - .add_event::() - .add_system(handle_build) - .add_system(compile_css.after(handle_build)) - .add_system(build_app.after(handle_build).after(compile_css)); - } -} - -fn handle_build( - mut actions: EventReader, - mut build_app: EventWriter, - mut compile_css: EventWriter, - async_action: Res>, -) { - for action in actions.iter() { - let tailwind_config = PathBuf::from(&action.path).join("tailwind.config.js"); - - if tailwind_config.is_file() { - let tailwind = &Tool::Tailwind; - - if tailwind.bin_path().is_file() { - compile_css.send(CompileCss { - action: action.clone(), - tool: tailwind.clone(), - }); - } else { - async_action.send(AsyncAction::install_and_build(tailwind, action.clone())); - } - } else { - build_app.send(BuildApp { - action: action.clone(), - }); - } - } -} - -fn compile_css( - mut events: EventReader, - mut build_app: EventWriter, - mut app_exit: EventWriter, -) { - for CompileCss { action, tool } in events.iter() { - let mut cmd = Command::new(&tool.bin_path_str()); - - cmd.current_dir(fs::canonicalize(&action.path).unwrap()); - cmd.args([ - "-c", - &action.config, - "-i", - &action.input, - "-o", - &action.output, - ]); - - if action.watch { - cmd.arg("-w"); - } - - let output = cmd - .output() - .expect("Could not execute compilation for Tailwind CSS"); - log::trace!("{output:?}"); - - if output.status.success() { - println!("CSS compiled"); - - build_app.send(BuildApp { - action: action.clone(), - }) - } else { - println!("Failed to compile Tailwind CSS"); - println!("{}", String::from_utf8(output.stderr).unwrap()); - - app_exit.send(AppExit); - } - } -} - -fn build_app(mut events: EventReader, mut app_exit: EventWriter) { - for BuildApp { action } in events.iter() { - let mut cmd = Command::new("cargo"); - - cmd.current_dir(fs::canonicalize(&action.path).unwrap()) - .args(["build"]); - - let output = cmd.output().expect("Could not execute cargo build"); - log::trace!("{output:?}"); - - if output.status.success() { - println!("Build finished"); - } else { - println!("Failed to build project"); - println!("{}", String::from_utf8(output.stderr).unwrap()); - } - - app_exit.send(AppExit); - } -} - -#[derive(Clone, Debug)] -struct BuildApp { - pub action: BuildAction, -} - -#[derive(Clone, Debug)] -struct CompileCss { - pub action: BuildAction, - pub tool: Tool, -} From c711837f88391faef58531aca77f1bb75460c43b Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Tue, 1 Nov 2022 18:32:04 +0100 Subject: [PATCH 03/22] cleanup --- docs/handbook/Internal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/handbook/Internal b/docs/handbook/Internal index 8a1510f..3f793af 160000 --- a/docs/handbook/Internal +++ b/docs/handbook/Internal @@ -1 +1 @@ -Subproject commit 8a1510f3cab5829051f2c859779909995cf7768a +Subproject commit 3f793af89d53c67b626443be7f16d98efb89b256 From d5e82502bd341eb1ef3385bc9c01e1ceac1b2e4f Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Fri, 4 Nov 2022 09:57:26 +0100 Subject: [PATCH 04/22] fix system ordering between subcommands --- Cargo.lock | 58 +++++++++++ Cargo.toml | 5 + plugins/bundle/Cargo.toml | 17 ++++ plugins/bundle/src/config.rs | 43 +++++++++ plugins/bundle/src/lib.rs | 44 +++++++++ plugins/bundle/src/tool.rs | 70 ++++++++++++++ plugins/bundle/src/tool/homebrew.rs | 145 ++++++++++++++++++++++++++++ plugins/bundle/src/tool/tailwind.rs | 27 ++++++ plugins/macro/src/cli.rs | 1 + plugins/macro/src/subcommand.rs | 48 +++++---- src/cli.rs | 37 +++++++ src/cli/action.rs | 46 +++++++++ src/{plugin => cli}/action/build.rs | 21 +--- src/{plugin => cli}/async_action.rs | 2 +- src/lib.rs | 2 + src/main.rs | 4 +- src/plugin.rs | 23 ----- src/plugin/action.rs | 31 ------ src/plugin/action/bundle.rs | 9 -- src/plugin/action/tool.rs | 7 -- src/plugin/cli.rs | 9 -- src/plugin/tool.rs | 60 ------------ 22 files changed, 529 insertions(+), 180 deletions(-) create mode 100644 plugins/bundle/Cargo.toml create mode 100644 plugins/bundle/src/config.rs create mode 100644 plugins/bundle/src/lib.rs create mode 100644 plugins/bundle/src/tool.rs create mode 100644 plugins/bundle/src/tool/homebrew.rs create mode 100644 plugins/bundle/src/tool/tailwind.rs create mode 100644 src/cli.rs create mode 100644 src/cli/action.rs rename src/{plugin => cli}/action/build.rs (86%) rename src/{plugin => cli}/async_action.rs (93%) delete mode 100644 src/plugin.rs delete mode 100644 src/plugin/action.rs delete mode 100644 src/plugin/action/bundle.rs delete mode 100644 src/plugin/action/tool.rs delete mode 100644 src/plugin/cli.rs delete mode 100644 src/plugin/tool.rs diff --git a/Cargo.lock b/Cargo.lock index a8391ef..211fd4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,6 +852,31 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cmd_lib" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba0f413777386d37f85afa5242f277a7b461905254c1af3c339d4af06800f62" +dependencies = [ + "cmd_lib_macros", + "faccess", + "lazy_static", + "log", + "os_pipe", +] + +[[package]] +name = "cmd_lib_macros" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e66605092ff6c6e37e0246601ae6c3f62dc1880e0599359b5f303497c112dc0" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cocoa" version = "0.24.0" @@ -1261,6 +1286,7 @@ dependencies = [ "clap", "config", "dioxus", + "dip_bundle", "dip_cli", "dip_core", "dip_desktop", @@ -1272,6 +1298,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "dip_bundle" +version = "0.1.0" +dependencies = [ + "bevy", + "cmd_lib", + "dirs", + "reqwest", + "tempfile", +] + [[package]] name = "dip_cli" version = "0.1.0" @@ -1451,6 +1488,17 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "faccess" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" +dependencies = [ + "bitflags", + "libc", + "winapi", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -2826,6 +2874,16 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "os_pipe" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb233f06c2307e1f5ce2ecad9f8121cffbbee2c95428f44ea85222e460d0d213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "os_str_bytes" version = "6.3.0" diff --git a/Cargo.toml b/Cargo.toml index 63c6683..1166004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "plugins/bundle", "plugins/core", "plugins/macro", "plugins/task", @@ -23,9 +24,11 @@ keywords = ["declarative-ui", "ecs", "bevy", "dioxus", "cross-platform"] anyhow = "1.0" bevy = { version = "0.8", default-features = false } bevy_ecs = "0.8" +cmd_lib = "1" config = "0.13" dioxus = { version = "0.2", features = ["fermi"] } dip = { version = "0.1", path = ".", features = ["desktop"] } +dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["full"] } dip_core = { version = "0.1", path = "./plugins/core" } dip_macro = { version = "0.1", path = "./plugins/macro" } dip_task = { version = "0.1", path = "./plugins/task" } @@ -35,6 +38,7 @@ tokio = { version = "1.18", features = ["rt-multi-thread", "sync", "macros", "fs serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_repr = "0.1" +tempfile = "3" [package] name = "dip" @@ -57,6 +61,7 @@ bevy.workspace = true clap = { version = "3.2", features = ["derive"], optional = true } config.workspace = true dioxus.workspace = true +dip_bundle.workspace = true dip_cli = { version = "0.1", path = "./plugins/ui/cli", optional = true } dip_core = { version = "0.1", path = "./plugins/core" } dip_desktop = { version = "0.1", path = "./plugins/ui/desktop", optional = true } diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml new file mode 100644 index 0000000..a5550f9 --- /dev/null +++ b/plugins/bundle/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dip_bundle" +version.workspace = true +edition.workspace = true + +[dependencies] +bevy.workspace = true +dirs.workspace = true +cmd_lib.workspace = true +reqwest.workspace = true +tempfile.workspace = true + +[features] +default = ["full"] +full = ["brew", "tailwind"] +brew = [] +tailwind = [] diff --git a/plugins/bundle/src/config.rs b/plugins/bundle/src/config.rs new file mode 100644 index 0000000..1b364a9 --- /dev/null +++ b/plugins/bundle/src/config.rs @@ -0,0 +1,43 @@ +use bevy::app::{App, Plugin}; +use std::{fs, path::PathBuf}; + +pub struct BundleConfigPlugin; + +impl Plugin for BundleConfigPlugin { + fn build(&self, app: &mut App) { + app.init_resource::(); + } +} + +pub struct BundleConfig { + app_path: PathBuf, +} + +impl Default for BundleConfig { + fn default() -> Self { + Self { + app_path: dirs::home_dir().unwrap().join(".dip"), + } + } +} + +impl BundleConfig { + pub fn app_path(&self) -> PathBuf { + Self::ensure_dir(&self.app_path); + + self.app_path.clone() + } + + pub fn install_path(&self) -> PathBuf { + let p = self.app_path().join("installs"); + Self::ensure_dir(&p); + + p + } + + fn ensure_dir(p: &PathBuf) { + if !&p.is_dir() { + fs::create_dir_all(&p).unwrap(); + } + } +} diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs new file mode 100644 index 0000000..3721d3f --- /dev/null +++ b/plugins/bundle/src/lib.rs @@ -0,0 +1,44 @@ +mod config; +pub mod tool; + +use bevy::{ + app::{App, Plugin}, + ecs::{ + event::{EventReader, EventWriter}, + schedule::ParallelSystemDescriptorCoercion, + }, +}; +pub use config::BundleConfigPlugin; +use tool::{InstallTools, ToolPlugin}; + +pub struct BundlePlugin; + +impl Plugin for BundlePlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_plugin(BundleConfigPlugin) + .add_plugin(ToolPlugin) + .add_system(apply_bundle.after("apply_bundle")); + } +} + +// Events + +pub struct ApplyBundle { + pub verbose: bool, +} + +pub struct BundleApplied; + +fn apply_bundle( + mut events: EventReader, + mut install_tools: EventWriter, +) { + events + .iter() + .map(|e| InstallTools { verbose: e.verbose }) + .for_each(|e| { + install_tools.send(e); + }); +} diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs new file mode 100644 index 0000000..b498ae0 --- /dev/null +++ b/plugins/bundle/src/tool.rs @@ -0,0 +1,70 @@ +mod homebrew; +mod tailwind; + +use crate::BundleApplied; +use bevy::{ + app::{App, Plugin}, + ecs::{component::Component, event::EventWriter, query::With, system::Query}, +}; +pub use homebrew::{HomebrewApplied, HomebrewInstalled, HomebrewPlugin}; +pub use tailwind::{TailwindInstalled, TailwindPlugin}; + +pub struct ToolPlugin; + +impl Plugin for ToolPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_system(check_tools_installed) + .add_system(check_bundle_applied); + + #[cfg(feature = "brew")] + app.add_plugin(HomebrewPlugin); + + #[cfg(feature = "tailwind")] + app.add_plugin(TailwindPlugin); + } +} + +// Events + +pub struct InstallTools { + pub verbose: bool, +} + +pub struct ToolsInstalled; + +// Commponents + +#[derive(Component)] +pub struct Tool; + +#[derive(Component)] +pub struct ToolInstalled; + +#[derive(Component)] +pub struct ToolApplied; + +// Systems + +fn check_tools_installed( + query: Query, With>, + mut installed: EventWriter, +) { + let not_installed = query.iter().find(|installed| installed.is_none()); + + if not_installed.is_none() { + installed.send(ToolsInstalled); + } +} + +fn check_bundle_applied( + query: Query, With>, + mut applied: EventWriter, +) { + let not_applied = query.iter().find(|applied| applied.is_none()); + + if not_applied.is_none() { + applied.send(BundleApplied); + } +} diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs new file mode 100644 index 0000000..333f648 --- /dev/null +++ b/plugins/bundle/src/tool/homebrew.rs @@ -0,0 +1,145 @@ +use crate::ApplyBundle; +use bevy::{ + app::{App, Plugin}, + ecs::{ + event::{EventReader, EventWriter}, + schedule::ParallelSystemDescriptorCoercion, + }, + log, +}; +use cmd_lib::{run_fun, spawn_with_output}; +use std::{ + env, + fs::File, + io::{BufRead, BufReader, Write}, +}; +use tempfile::tempdir; + +use super::InstallTools; + +// Plugin + +pub struct HomebrewPlugin; + +impl Plugin for HomebrewPlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_system(install.after("apply_bundle").before(apply)) + .add_system(apply.after("apply_bundle")); + } +} + +// Events + +pub struct HomebrewInstalled; + +pub struct HomebrewApplied; + +// Systems + +fn install(mut events: EventReader, mut installed: EventWriter) { + events.iter().for_each(|e| { + if run_fun!(which brew).is_ok() { + log::info!("🟡 Skip: Install Homebrew"); + } else { + log::info!("📌 Install Homebrew"); + + let install_sh = reqwest::blocking::get( + "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", + ) + .expect("Failed to fetch Homebrew installation script") + .text() + .expect("Failed to parse Homebrew installation script into text"); + + let dir = tempdir().unwrap(); + let file_path = dir.path().join("brew-install.sh"); + let file_path_str = file_path.clone().into_os_string(); + let mut file = File::create(file_path).unwrap(); + file.write_all(install_sh.as_bytes()) + .expect("Unable to write file"); + + let mut install_brew = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); + + let result = if e.verbose { + install_brew.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| log::info!("{f}")); + }) + } else { + if let Err(e) = install_brew.wait_with_output() { + Err(e) + } else { + Ok(()) + } + }; + + if let Err(e) = result { + log::error!("Failed to run brew install."); + log::error!("{e}"); + log::info!("✅ Install Homebrew"); + } else { + log::info!("✅ Install Homebrew"); + } + } + + installed.send(HomebrewInstalled); + }); +} + +fn apply(mut events: EventReader, mut applied: EventWriter) { + events.iter().for_each(|e| { + log::warn!("TODO: change current_path to somewhere absolute"); + let current_path = env::current_dir().expect("Failed to get current directory."); + let brewfile_path = current_path + .join("bundles") + .join("homebrew") + .join("Brewfile"); + + if brewfile_path.is_file() { + match run_fun!(which brew) { + Ok(_brew_path) => { + log::info!("📌 Apply Homebrew bundle"); + + let brewfile_path_str = &brewfile_path.into_os_string().into_string().unwrap(); + let mut brew_bundle = + spawn_with_output!(brew bundle --file $brewfile_path_str).unwrap(); + + let result = if e.verbose { + brew_bundle.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|line| log::info!("{:?}", line)); + }) + } else { + if let Err(e) = brew_bundle.wait_with_output() { + Err(e) + } else { + Ok(()) + } + }; + + if let Err(e) = result { + log::error!("{e}"); + log::error!("Failed to run brew bundle."); + } else { + log::info!("✅ Apply Homebrew bundle"); + } + } + Err(e) => { + log::error!("{e}"); + log::error!("Could not find homebrew binary."); + } + } + } else { + log::error!( + "Failed to apply Homebrew bundle. Make sure to have bundles/homebrew/Brewfile" + ); + } + + applied.send(HomebrewApplied); + }); +} diff --git a/plugins/bundle/src/tool/tailwind.rs b/plugins/bundle/src/tool/tailwind.rs new file mode 100644 index 0000000..3206487 --- /dev/null +++ b/plugins/bundle/src/tool/tailwind.rs @@ -0,0 +1,27 @@ +use crate::tool::InstallTools; +use bevy::{ + app::{App, Plugin}, + ecs::event::{EventReader, EventWriter}, + log, +}; + +// Plugin +pub struct TailwindPlugin; + +impl Plugin for TailwindPlugin { + fn build(&self, app: &mut App) { + app.add_event::().add_system(install); + } +} + +fn install(mut events: EventReader, mut installed: EventWriter) { + for _e in events.iter() { + log::warn!("TODO: Install Tool"); + + installed.send(TailwindInstalled); + } +} + +// Events + +pub struct TailwindInstalled; diff --git a/plugins/macro/src/cli.rs b/plugins/macro/src/cli.rs index 13b8097..15714d4 100644 --- a/plugins/macro/src/cli.rs +++ b/plugins/macro/src/cli.rs @@ -40,6 +40,7 @@ impl CliParser { &format!("handle_{}", subcommand_name), ) .unwrap(); + token.add_subcommand_handler = quote! { .add_startup_system_to_stage( ::dip::core::schedule::DipStartupStage::Action, diff --git a/plugins/macro/src/subcommand.rs b/plugins/macro/src/subcommand.rs index bba96ca..c23ae3d 100644 --- a/plugins/macro/src/subcommand.rs +++ b/plugins/macro/src/subcommand.rs @@ -43,7 +43,30 @@ impl SubcommandParser { } fn add_system(&self) -> TokenStream2 { - let mut subsubcommand_handler_names = vec![]; + let handler_with_system_order = self.handler_with_system_order(); + + let gen = quote! { + .add_startup_system_to_stage(::dip::core::schedule::DipStartupStage::Action, #handler_with_system_order); + }; + + gen + } + + fn handler_with_system_order(&self) -> TokenStream2 { + let gen_str = self + .child_names() + .iter() + .map(|name| format!("handle_{}", name.to_case(Case::Snake))) + .fold(self.handler_name().to_string(), |acc, name| { + format!("{acc}.before({})", name) + }); + let gen = TokenStream2::from_str(&gen_str).unwrap(); + + gen + } + + fn child_names(&self) -> Vec { + let mut child_names = vec![]; for v in self.commands_enum.variants.iter() { for a in v.attrs.iter() { for t in a.tokens.clone().into_iter() { @@ -54,15 +77,13 @@ impl SubcommandParser { TokenTree::Ident(ident) => { if ident.to_string() == "subcommand" { if let syn::Fields::Unnamed(f) = &v.fields { - let subsubcommand_ty = &f.unnamed[0].ty; - let subsubcommand_ty_quote = - quote! { #subsubcommand_ty }; - let subsubcommand_name = &subsubcommand_ty_quote + let child_ty = &f.unnamed[0].ty; + let child_ty_quote = quote! { #child_ty }; + let child_name = child_ty_quote .to_string() - .to_case(Case::Snake); + .to_case(Case::UpperCamel); - subsubcommand_handler_names - .push(format!("handle_{}", subsubcommand_name)); + child_names.push(child_name); } } } @@ -76,16 +97,7 @@ impl SubcommandParser { } } - let mut handler = self.handler_name().to_string(); - for n in subsubcommand_handler_names { - handler = format!("{}.before({})", handler, n); - } - - let handler_token = TokenStream2::from_str(&handler).unwrap(); - - quote! { - .add_startup_system_to_stage(::dip::core::schedule::DipStartupStage::Action, #handler_token); - } + child_names } fn subcommand_ty_name(&self) -> TokenStream2 { diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..246ba5a --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,37 @@ +mod action; +mod async_action; + +use crate::cli::{ + action::{ActionPlugin, ApplyBundleAction, BundleActionPlugin, CliPlugin}, + async_action::{AsyncAction, AsyncActionPlugin}, +}; +use dip::{ + bevy::{ + app::{App, Plugin}, + ecs::{ + event::{EventReader, EventWriter}, + schedule::ParallelSystemDescriptorCoercion, + }, + }, + bundle::{ApplyBundle, BundlePlugin}, +}; + +pub struct DipCliPlugin; + +impl Plugin for DipCliPlugin { + fn build(&self, app: &mut App) { + app.add_plugin(CliPlugin::::application()) + .add_plugin(ActionPlugin) + .add_plugin(BundleActionPlugin) + .add_plugin(AsyncActionPlugin) + .add_plugin(BundlePlugin) + .add_system(apply_bundle.label("apply_bundle")); + } +} + +fn apply_bundle(mut actions: EventReader, mut apply: EventWriter) { + actions.iter().for_each(|a| { + println!("appyl_bundle"); + apply.send(ApplyBundle { verbose: a.verbose }); + }) +} diff --git a/src/cli/action.rs b/src/cli/action.rs new file mode 100644 index 0000000..6bc7973 --- /dev/null +++ b/src/cli/action.rs @@ -0,0 +1,46 @@ +mod build; + +pub use build::*; + +use dip::cli::{CliPlugin, SubcommandPlugin}; + +#[derive(CliPlugin, clap::Parser)] +#[clap(version)] +struct Cli { + #[clap(subcommand)] + action: Action, +} + +#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] +pub enum Action { + Build(BuildArgs), + + #[clap(subcommand)] + Bundle(BundleAction), +} + +#[derive(clap::Args, Clone, Debug)] +pub struct BuildArgs { + #[clap(short, long, default_value_t = String::from("."))] + pub path: String, + + #[clap(short, long, default_value_t = String::from("tailwind.config.js"))] + pub config: String, + + #[clap(short, long, default_value_t = String::from("styles/style.css"))] + pub input: String, + + #[clap(short, long, default_value_t = String::from("static/style.css"))] + pub output: String, + + #[clap(short, long)] + pub watch: bool, +} + +#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] +pub enum BundleAction { + Apply { + #[clap(short, long, required = false)] + verbose: bool, + }, +} diff --git a/src/plugin/action/build.rs b/src/cli/action/build.rs similarity index 86% rename from src/plugin/action/build.rs rename to src/cli/action/build.rs index eed19cd..ee7adfb 100644 --- a/src/plugin/action/build.rs +++ b/src/cli/action/build.rs @@ -1,5 +1,5 @@ use crate::{ - plugin::{action::*, AsyncAction}, + cli::{action::BuildAction, async_action::AsyncAction}, resource::tool::Tool, }; use dip::{ @@ -23,25 +23,6 @@ impl Plugin for BuildActionPlugin { .add_system(build_app.after(handle_build).after(compile_css)); } } - -#[derive(clap::Args, Clone, Debug)] -pub struct BuildArgs { - #[clap(short, long, default_value_t = String::from("."))] - pub path: String, - - #[clap(short, long, default_value_t = String::from("tailwind.config.js"))] - pub config: String, - - #[clap(short, long, default_value_t = String::from("styles/style.css"))] - pub input: String, - - #[clap(short, long, default_value_t = String::from("static/style.css"))] - pub output: String, - - #[clap(short, long)] - pub watch: bool, -} - fn handle_build( mut actions: EventReader, mut build_app: EventWriter, diff --git a/src/plugin/async_action.rs b/src/cli/async_action.rs similarity index 93% rename from src/plugin/async_action.rs rename to src/cli/async_action.rs index b61236d..9e2a5d7 100644 --- a/src/plugin/async_action.rs +++ b/src/cli/async_action.rs @@ -1,5 +1,5 @@ use crate::{ - plugin::action::BuildAction, + cli::action::BuildAction, resource::tool::{Tool, ToolResult}, }; use dip::{bevy::ecs::event::EventReader, core::task::async_action}; diff --git a/src/lib.rs b/src/lib.rs index c37415a..1b6d5b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,8 @@ pub use dip_cli as cli; #[cfg(feature = "desktop")] pub use dip_desktop as desktop; +pub use dip_bundle as bundle; + pub use bevy; #[cfg(feature = "desktop")] diff --git a/src/main.rs b/src/main.rs index 2be3737..eec3fdc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ -mod plugin; +mod cli; mod resource; -use crate::plugin::DipCliPlugin; +use crate::cli::DipCliPlugin; use dip::bevy::{ app::App, log::{LogPlugin, LogSettings}, diff --git a/src/plugin.rs b/src/plugin.rs deleted file mode 100644 index 70b5569..0000000 --- a/src/plugin.rs +++ /dev/null @@ -1,23 +0,0 @@ -mod action; -mod async_action; -mod cli; -mod tool; - -use crate::plugin::{ - action::ActionPlugin, - async_action::{AsyncAction, AsyncActionPlugin}, - cli::CliPlugin, - tool::ToolPlugin, -}; -use dip::bevy::app::{App, Plugin}; - -pub struct DipCliPlugin; - -impl Plugin for DipCliPlugin { - fn build(&self, app: &mut App) { - app.add_plugin(CliPlugin::::application()) - .add_plugin(ActionPlugin) - .add_plugin(AsyncActionPlugin) - .add_plugin(ToolPlugin); - } -} diff --git a/src/plugin/action.rs b/src/plugin/action.rs deleted file mode 100644 index 4a75034..0000000 --- a/src/plugin/action.rs +++ /dev/null @@ -1,31 +0,0 @@ -use dip::{ - bevy::app::{App, Plugin}, - cli::SubcommandPlugin, -}; - -mod build; -mod bundle; -mod tool; - -pub use build::*; -pub use bundle::*; -pub use tool::*; - -pub struct DipActionPlugin; - -impl Plugin for DipActionPlugin { - fn build(&self, app: &mut App) { - app.add_plugin(ActionPlugin).add_plugin(BuildActionPlugin); - } -} - -#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] -pub enum Action { - Build(BuildArgs), - - #[clap(subcommand)] - Bundle(BundleAction), - - #[clap(subcommand)] - Tool(ToolAction), -} diff --git a/src/plugin/action/bundle.rs b/src/plugin/action/bundle.rs deleted file mode 100644 index 729e5b1..0000000 --- a/src/plugin/action/bundle.rs +++ /dev/null @@ -1,9 +0,0 @@ -use dip::cli::SubcommandPlugin; - -#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] -pub enum BundleAction { - Apply { - #[clap(short, long, required = false)] - verbose: bool, - }, -} diff --git a/src/plugin/action/tool.rs b/src/plugin/action/tool.rs deleted file mode 100644 index d5903ef..0000000 --- a/src/plugin/action/tool.rs +++ /dev/null @@ -1,7 +0,0 @@ -use dip::cli::SubcommandPlugin; - -#[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] -pub enum ToolAction { - List, - Add { name: String }, -} diff --git a/src/plugin/cli.rs b/src/plugin/cli.rs deleted file mode 100644 index c4f3857..0000000 --- a/src/plugin/cli.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::plugin::action::{handle_action, Action}; -use dip::cli::CliPlugin; - -#[derive(CliPlugin, clap::Parser)] -#[clap(version)] -struct Cli { - #[clap(subcommand)] - action: Action, -} diff --git a/src/plugin/tool.rs b/src/plugin/tool.rs deleted file mode 100644 index 44297ee..0000000 --- a/src/plugin/tool.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{ - plugin::{action::*, async_action::*}, - resource::tool::{Tool, ToolResult}, -}; -use dip::{ - bevy::{ - app::{App, AppExit, Plugin}, - ecs::{ - event::{EventReader, EventWriter}, - system::Res, - }, - }, - core::task::AsyncActionPool, -}; - -pub struct ToolPlugin; - -impl Plugin for ToolPlugin { - fn build(&self, app: &mut App) { - app.add_plugin(ToolActionPlugin) - .add_system(list_tool) - .add_system(add_tool) - .add_system(install_result); - } -} - -fn list_tool(mut events: EventReader, mut app_exit: EventWriter) { - for _ in events.iter() { - for t in Tool::list().iter() { - println!("- {t}"); - } - app_exit.send(AppExit); - } -} - -fn add_tool( - mut events: EventReader, - async_action: Res>, -) { - for e in events.iter() { - let name = e.name.as_str(); - let tool = Tool::from_str(name).expect(&format!("Could not find tool: {name}")); - - match tool { - Tool::Tailwind => async_action.send(AsyncAction::install(tool)), - } - } -} - -fn install_result( - mut events: EventReader>, - mut app_exit: EventWriter, -) { - for e in events.iter() { - if let Err(e) = e { - println!("{:?}", e.error); - } - app_exit.send(AppExit); - } -} From 3cfe3c8cc29a4a26faac9b6256dbb491a7d67c96 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sat, 5 Nov 2022 13:31:54 +0100 Subject: [PATCH 05/22] Implement bundle apply for homebrew --- .github/workflows/rust.yml | 2 + Cargo.lock | 1 + .../Product/Framework/CLI/Installation.md | 1 + plugins/bundle/Cargo.toml | 1 + plugins/bundle/src/lib.rs | 37 ++++++++++----- plugins/bundle/src/schedule.rs | 34 ++++++++++++++ plugins/bundle/src/tool.rs | 45 ++++--------------- plugins/bundle/src/tool/homebrew.rs | 40 ++++++++++++----- src/cli.rs | 27 +++++------ src/cli/action.rs | 17 ++++--- src/cli/async_action.rs | 23 ---------- src/main.rs | 5 +-- 12 files changed, 126 insertions(+), 107 deletions(-) create mode 100644 plugins/bundle/src/schedule.rs delete mode 100644 src/cli/async_action.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d28f417..e389254 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -17,6 +17,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Install prerequisites run: | + cargo install cargo-workspaces + sudo apt-get update sudo apt-get install -y \ libudev-dev \ diff --git a/Cargo.lock b/Cargo.lock index 211fd4a..fd6e990 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1304,6 +1304,7 @@ version = "0.1.0" dependencies = [ "bevy", "cmd_lib", + "dip_core", "dirs", "reqwest", "tempfile", diff --git a/docs/handbook/Product/Framework/CLI/Installation.md b/docs/handbook/Product/Framework/CLI/Installation.md index 973e9cd..4c236c6 100644 --- a/docs/handbook/Product/Framework/CLI/Installation.md +++ b/docs/handbook/Product/Framework/CLI/Installation.md @@ -1,3 +1,4 @@ + ## Installation ### From Crates.io diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index a5550f9..1edfd8b 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -5,6 +5,7 @@ edition.workspace = true [dependencies] bevy.workspace = true +dip_core.workspace = true dirs.workspace = true cmd_lib.workspace = true reqwest.workspace = true diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index 3721d3f..fa8dc94 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -1,25 +1,26 @@ mod config; -pub mod tool; +mod schedule; +mod tool; use bevy::{ app::{App, Plugin}, - ecs::{ - event::{EventReader, EventWriter}, - schedule::ParallelSystemDescriptorCoercion, - }, + ecs::event::{EventReader, EventWriter}, }; pub use config::BundleConfigPlugin; -use tool::{InstallTools, ToolPlugin}; +pub use schedule::{BundleSchedulePlugin, BundleStage}; +use std::path::PathBuf; +use tool::{ApplyTools, InstallTools, ToolPlugin}; pub struct BundlePlugin; impl Plugin for BundlePlugin { fn build(&self, app: &mut App) { - app.add_event::() + app.add_plugin(BundleSchedulePlugin) + .add_event::() .add_event::() .add_plugin(BundleConfigPlugin) .add_plugin(ToolPlugin) - .add_system(apply_bundle.after("apply_bundle")); + .add_system_to_stage(BundleStage::Prepare, apply_bundle); } } @@ -27,6 +28,7 @@ impl Plugin for BundlePlugin { pub struct ApplyBundle { pub verbose: bool, + pub path: PathBuf, } pub struct BundleApplied; @@ -34,11 +36,24 @@ pub struct BundleApplied; fn apply_bundle( mut events: EventReader, mut install_tools: EventWriter, + mut apply_tools: EventWriter, ) { events .iter() - .map(|e| InstallTools { verbose: e.verbose }) - .for_each(|e| { - install_tools.send(e); + .map(|e| { + ( + InstallTools { + verbose: e.verbose, + path: e.path.clone(), + }, + ApplyTools { + verbose: e.verbose, + path: e.path.clone(), + }, + ) + }) + .for_each(|(install, apply)| { + install_tools.send(install); + apply_tools.send(apply); }); } diff --git a/plugins/bundle/src/schedule.rs b/plugins/bundle/src/schedule.rs new file mode 100644 index 0000000..7e63fc1 --- /dev/null +++ b/plugins/bundle/src/schedule.rs @@ -0,0 +1,34 @@ +use bevy::{ + app::{App, Plugin}, + ecs::schedule::{StageLabel, SystemStage}, +}; +use dip_core::schedule::DipStage; + +pub struct BundleSchedulePlugin; + +impl Plugin for BundleSchedulePlugin { + fn build(&self, app: &mut App) { + app.add_stage_after( + DipStage::Prepare, + BundleStage::Prepare, + SystemStage::parallel(), + ) + .add_stage_after( + DipStage::Apply, + BundleStage::Install, + SystemStage::parallel(), + ) + .add_stage_after( + BundleStage::Install, + BundleStage::Apply, + SystemStage::parallel(), + ); + } +} + +#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] +pub enum BundleStage { + Prepare, + Install, + Apply, +} diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index b498ae0..a157c47 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -1,22 +1,19 @@ mod homebrew; mod tailwind; -use crate::BundleApplied; use bevy::{ app::{App, Plugin}, - ecs::{component::Component, event::EventWriter, query::With, system::Query}, + ecs::component::Component, }; pub use homebrew::{HomebrewApplied, HomebrewInstalled, HomebrewPlugin}; +use std::path::PathBuf; pub use tailwind::{TailwindInstalled, TailwindPlugin}; pub struct ToolPlugin; impl Plugin for ToolPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_event::() - .add_system(check_tools_installed) - .add_system(check_bundle_applied); + app.add_event::().add_event::(); #[cfg(feature = "brew")] app.add_plugin(HomebrewPlugin); @@ -30,41 +27,15 @@ impl Plugin for ToolPlugin { pub struct InstallTools { pub verbose: bool, + pub path: PathBuf, } -pub struct ToolsInstalled; +pub struct ApplyTools { + pub verbose: bool, + pub path: PathBuf, +} // Commponents #[derive(Component)] pub struct Tool; - -#[derive(Component)] -pub struct ToolInstalled; - -#[derive(Component)] -pub struct ToolApplied; - -// Systems - -fn check_tools_installed( - query: Query, With>, - mut installed: EventWriter, -) { - let not_installed = query.iter().find(|installed| installed.is_none()); - - if not_installed.is_none() { - installed.send(ToolsInstalled); - } -} - -fn check_bundle_applied( - query: Query, With>, - mut applied: EventWriter, -) { - let not_applied = query.iter().find(|applied| applied.is_none()); - - if not_applied.is_none() { - applied.send(BundleApplied); - } -} diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index 333f648..c5e43ac 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -1,10 +1,7 @@ -use crate::ApplyBundle; +use crate::{ApplyBundle, BundleStage}; use bevy::{ app::{App, Plugin}, - ecs::{ - event::{EventReader, EventWriter}, - schedule::ParallelSystemDescriptorCoercion, - }, + ecs::event::{EventReader, EventWriter}, log, }; use cmd_lib::{run_fun, spawn_with_output}; @@ -25,8 +22,8 @@ impl Plugin for HomebrewPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_system(install.after("apply_bundle").before(apply)) - .add_system(apply.after("apply_bundle")); + .add_system_to_stage(BundleStage::Install, install) + .add_system_to_stage(BundleStage::Apply, apply); } } @@ -40,7 +37,21 @@ pub struct HomebrewApplied; fn install(mut events: EventReader, mut installed: EventWriter) { events.iter().for_each(|e| { - if run_fun!(which brew).is_ok() { + let current_path = env::current_dir().expect("Failed to get current directory."); + let brewfile_path = current_path + .join(&e.path) + .join("bundle") + .join("homebrew") + .join("Brewfile"); + + if !brewfile_path.is_file() { + log::info!( + "Brewfile does not exist: {}", + brewfile_path.into_os_string().into_string().unwrap() + ); + log::info!("🟡 Skip: Install Homebrew"); + } else if run_fun!(which brew).is_ok() { + log::info!("brew path already exists"); log::info!("🟡 Skip: Install Homebrew"); } else { log::info!("📌 Install Homebrew"); @@ -91,19 +102,23 @@ fn install(mut events: EventReader, mut installed: EventWriter, mut applied: EventWriter) { events.iter().for_each(|e| { - log::warn!("TODO: change current_path to somewhere absolute"); let current_path = env::current_dir().expect("Failed to get current directory."); let brewfile_path = current_path - .join("bundles") + .join(&e.path) + .join("bundle") .join("homebrew") .join("Brewfile"); + let brewfile_path_str = &brewfile_path + .clone() + .into_os_string() + .into_string() + .unwrap(); if brewfile_path.is_file() { match run_fun!(which brew) { Ok(_brew_path) => { log::info!("📌 Apply Homebrew bundle"); - let brewfile_path_str = &brewfile_path.into_os_string().into_string().unwrap(); let mut brew_bundle = spawn_with_output!(brew bundle --file $brewfile_path_str).unwrap(); @@ -136,7 +151,8 @@ fn apply(mut events: EventReader, mut applied: EventWriter::application()) + app.add_plugin(CliPlugin::::oneshot()) .add_plugin(ActionPlugin) .add_plugin(BundleActionPlugin) - .add_plugin(AsyncActionPlugin) .add_plugin(BundlePlugin) - .add_system(apply_bundle.label("apply_bundle")); + .add_system(apply_bundle); } } fn apply_bundle(mut actions: EventReader, mut apply: EventWriter) { actions.iter().for_each(|a| { - println!("appyl_bundle"); - apply.send(ApplyBundle { verbose: a.verbose }); - }) + apply.send(ApplyBundle { + // verbose: a.verbose, + verbose: true, + path: PathBuf::from(&a.path), + }); + }); } diff --git a/src/cli/action.rs b/src/cli/action.rs index 6bc7973..e476223 100644 --- a/src/cli/action.rs +++ b/src/cli/action.rs @@ -1,6 +1,6 @@ -mod build; +// mod build; -pub use build::*; +// pub use build::*; use dip::cli::{CliPlugin, SubcommandPlugin}; @@ -39,8 +39,13 @@ pub struct BuildArgs { #[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] pub enum BundleAction { - Apply { - #[clap(short, long, required = false)] - verbose: bool, - }, + Apply(ApplyBundleArgs), +} + +#[derive(clap::Args, Clone, Debug)] +pub struct ApplyBundleArgs { + // #[clap(short, long, required = false)] + // pub verbose: bool, + #[clap(short, long, default_value_t = String::from("."))] + pub path: String, } diff --git a/src/cli/async_action.rs b/src/cli/async_action.rs deleted file mode 100644 index 9e2a5d7..0000000 --- a/src/cli/async_action.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{ - cli::action::BuildAction, - resource::tool::{Tool, ToolResult}, -}; -use dip::{bevy::ecs::event::EventReader, core::task::async_action}; - -#[async_action] -impl AsyncActionCreator { - async fn install(tool: Tool) -> ToolResult { - tool.install().await?; - - Ok(Install) - } - - async fn install_and_build(tool: &Tool, action: BuildAction) -> BuildAction { - tool.install().await.unwrap(); - - action - } -} - -#[derive(Clone, Debug)] -pub struct Install; diff --git a/src/main.rs b/src/main.rs index eec3fdc..c016b71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod cli; -mod resource; use crate::cli::DipCliPlugin; use dip::bevy::{ @@ -18,8 +17,8 @@ fn main() { #[cfg(not(debug_assertions))] app.insert_resource(LogSettings { - filter: "warn".into(), - level: bevy::log::Level::WARN, + filter: "".into(), + level: bevy::log::Level::INFO, }); app.add_plugin(DipCliPlugin).add_plugin(LogPlugin).run(); From f2ec17889d679548317af94bbfeb1988ecdbfbad Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sat, 5 Nov 2022 13:53:27 +0100 Subject: [PATCH 06/22] Setup dotfiles plugin --- plugins/bundle/Cargo.toml | 3 ++- plugins/bundle/src/tool.rs | 7 +++++-- plugins/bundle/src/tool/dotfiles.rs | 22 ++++++++++++++++++++++ plugins/bundle/src/tool/homebrew.rs | 18 +++--------------- 4 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 plugins/bundle/src/tool/dotfiles.rs diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index 1edfd8b..fc10e86 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -13,6 +13,7 @@ tempfile.workspace = true [features] default = ["full"] -full = ["brew", "tailwind"] +full = ["brew", "dotfiles", "tailwind"] brew = [] +dotfiles = [] tailwind = [] diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index a157c47..fb03a2c 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -1,13 +1,13 @@ +mod dotfiles; mod homebrew; mod tailwind; +pub use self::{dotfiles::DotfilesPlugin, homebrew::HomebrewPlugin, tailwind::TailwindPlugin}; use bevy::{ app::{App, Plugin}, ecs::component::Component, }; -pub use homebrew::{HomebrewApplied, HomebrewInstalled, HomebrewPlugin}; use std::path::PathBuf; -pub use tailwind::{TailwindInstalled, TailwindPlugin}; pub struct ToolPlugin; @@ -18,6 +18,9 @@ impl Plugin for ToolPlugin { #[cfg(feature = "brew")] app.add_plugin(HomebrewPlugin); + #[cfg(feature = "dotfiles")] + app.add_plugin(DotfilesPlugin); + #[cfg(feature = "tailwind")] app.add_plugin(TailwindPlugin); } diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs new file mode 100644 index 0000000..474dfa1 --- /dev/null +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -0,0 +1,22 @@ +use crate::{ApplyBundle, BundleStage}; +use bevy::{ + app::{App, Plugin}, + ecs::event::EventReader, + log, +}; + +// Plugin + +pub struct DotfilesPlugin; + +impl Plugin for DotfilesPlugin { + fn build(&self, app: &mut App) { + app.add_system_to_stage(BundleStage::Apply, apply); + } +} + +fn apply(mut events: EventReader) { + events.iter().for_each(|_e| { + log::info!("TODO: apply dotfiles"); + }); +} diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index c5e43ac..cb40b90 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -20,22 +20,14 @@ pub struct HomebrewPlugin; impl Plugin for HomebrewPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_event::() - .add_system_to_stage(BundleStage::Install, install) + app.add_system_to_stage(BundleStage::Install, install) .add_system_to_stage(BundleStage::Apply, apply); } } -// Events - -pub struct HomebrewInstalled; - -pub struct HomebrewApplied; - // Systems -fn install(mut events: EventReader, mut installed: EventWriter) { +fn install(mut events: EventReader) { events.iter().for_each(|e| { let current_path = env::current_dir().expect("Failed to get current directory."); let brewfile_path = current_path @@ -95,12 +87,10 @@ fn install(mut events: EventReader, mut installed: EventWriter, mut applied: EventWriter) { +fn apply(mut events: EventReader) { events.iter().for_each(|e| { let current_path = env::current_dir().expect("Failed to get current directory."); let brewfile_path = current_path @@ -155,7 +145,5 @@ fn apply(mut events: EventReader, mut applied: EventWriter Date: Sat, 5 Nov 2022 15:01:52 +0100 Subject: [PATCH 07/22] Retrieve all dotfiles bundles --- Cargo.lock | 1 + Cargo.toml | 3 +- plugins/bundle/Cargo.toml | 7 ++-- plugins/bundle/src/tool.rs | 6 +-- plugins/bundle/src/tool/dotfiles.rs | 61 ++++++++++++++++++++++++++--- plugins/bundle/src/tool/homebrew.rs | 2 +- 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd6e990..72594a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1308,6 +1308,7 @@ dependencies = [ "dirs", "reqwest", "tempfile", + "walkdir", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1166004..44b4c05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ cmd_lib = "1" config = "0.13" dioxus = { version = "0.2", features = ["fermi"] } dip = { version = "0.1", path = ".", features = ["desktop"] } -dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["full"] } +dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["dotfiles"] } dip_core = { version = "0.1", path = "./plugins/core" } dip_macro = { version = "0.1", path = "./plugins/macro" } dip_task = { version = "0.1", path = "./plugins/task" } @@ -39,6 +39,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_repr = "0.1" tempfile = "3" +walkdir = "2" [package] name = "dip" diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index fc10e86..3babdd2 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -10,10 +10,11 @@ dirs.workspace = true cmd_lib.workspace = true reqwest.workspace = true tempfile.workspace = true +walkdir.workspace = true [features] -default = ["full"] -full = ["brew", "dotfiles", "tailwind"] -brew = [] +# default = ["full"] +full = ["dotfiles", "brew", "tailwind"] dotfiles = [] +brew = [] tailwind = [] diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index fb03a2c..0bbf428 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -15,12 +15,12 @@ impl Plugin for ToolPlugin { fn build(&self, app: &mut App) { app.add_event::().add_event::(); - #[cfg(feature = "brew")] - app.add_plugin(HomebrewPlugin); - #[cfg(feature = "dotfiles")] app.add_plugin(DotfilesPlugin); + #[cfg(feature = "brew")] + app.add_plugin(HomebrewPlugin); + #[cfg(feature = "tailwind")] app.add_plugin(TailwindPlugin); } diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 474dfa1..9b0eec4 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -1,9 +1,13 @@ use crate::{ApplyBundle, BundleStage}; use bevy::{ app::{App, Plugin}, - ecs::event::EventReader, + ecs::{ + event::{EventReader, EventWriter}, + schedule::ParallelSystemDescriptorCoercion, + }, log, }; +use std::{env, fs, path::PathBuf}; // Plugin @@ -11,12 +15,59 @@ pub struct DotfilesPlugin; impl Plugin for DotfilesPlugin { fn build(&self, app: &mut App) { - app.add_system_to_stage(BundleStage::Apply, apply); + app.add_event::() + .add_system_to_stage(BundleStage::Apply, apply) + .add_system_to_stage(BundleStage::Apply, apply_dotfiles.after(apply)); } } -fn apply(mut events: EventReader) { - events.iter().for_each(|_e| { - log::info!("TODO: apply dotfiles"); +// Events + +struct ApplyDotfiles { + path: PathBuf, +} + +fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { + events.iter().for_each(|e| { + log::warn!("TODO: apply dotfiles"); + + // Walk through ./bundle/dotfiles/* + let current_path = env::current_dir().expect("Failed to get current directory."); + let dotfiles_path = current_path.join(&e.path).join("bundle").join("dotfiles"); + + if dotfiles_path.is_dir() { + log::info!("📌"); + fs::read_dir(dotfiles_path) + .unwrap() + .filter_map(|path| { + if let Ok(path) = path { + if path.file_type().unwrap().is_dir() { + Some(path) + } else { + None + } + } else { + None + } + }) + .for_each(|dir_entry| { + apply_dotfiles.send(ApplyDotfiles { + path: dir_entry.path(), + }); + }); + } else { + log::info!( + "dotfiles direcotry is empty: {}", + &dotfiles_path.into_os_string().into_string().unwrap() + ); + log::info!("🟡 Skip: Apply dotfiles"); + } + }); +} + +fn apply_dotfiles(mut events: EventReader) { + events.iter().for_each(|e| { + let path = &e.path.clone().into_os_string().into_string().unwrap(); + println!("{}", path); }); } diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index cb40b90..7556e51 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -1,7 +1,7 @@ use crate::{ApplyBundle, BundleStage}; use bevy::{ app::{App, Plugin}, - ecs::event::{EventReader, EventWriter}, + ecs::event::EventReader, log, }; use cmd_lib::{run_fun, spawn_with_output}; From a33f5efffe31f028d4234e9c07edd8afbb9460ff Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sat, 5 Nov 2022 16:23:57 +0100 Subject: [PATCH 08/22] [WIP] Get target path based on entry --- plugins/bundle/src/lib.rs | 6 +-- plugins/bundle/src/tool.rs | 13 ++----- plugins/bundle/src/tool/dotfiles.rs | 59 +++++++++++++++++------------ plugins/bundle/src/tool/unix.rs | 19 ++++++++++ 4 files changed, 60 insertions(+), 37 deletions(-) create mode 100644 plugins/bundle/src/tool/unix.rs diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index fa8dc94..3c25ca9 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -1,4 +1,4 @@ -mod config; +// mod config; mod schedule; mod tool; @@ -6,7 +6,7 @@ use bevy::{ app::{App, Plugin}, ecs::event::{EventReader, EventWriter}, }; -pub use config::BundleConfigPlugin; +// pub use config::BundleConfigPlugin; pub use schedule::{BundleSchedulePlugin, BundleStage}; use std::path::PathBuf; use tool::{ApplyTools, InstallTools, ToolPlugin}; @@ -18,7 +18,7 @@ impl Plugin for BundlePlugin { app.add_plugin(BundleSchedulePlugin) .add_event::() .add_event::() - .add_plugin(BundleConfigPlugin) + // .add_plugin(BundleConfigPlugin) .add_plugin(ToolPlugin) .add_system_to_stage(BundleStage::Prepare, apply_bundle); } diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index 0bbf428..f0baeb3 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -1,8 +1,9 @@ mod dotfiles; mod homebrew; mod tailwind; +mod unix; -pub use self::{dotfiles::DotfilesPlugin, homebrew::HomebrewPlugin, tailwind::TailwindPlugin}; +pub use self::unix::UnixToolPlugin; use bevy::{ app::{App, Plugin}, ecs::component::Component, @@ -15,14 +16,8 @@ impl Plugin for ToolPlugin { fn build(&self, app: &mut App) { app.add_event::().add_event::(); - #[cfg(feature = "dotfiles")] - app.add_plugin(DotfilesPlugin); - - #[cfg(feature = "brew")] - app.add_plugin(HomebrewPlugin); - - #[cfg(feature = "tailwind")] - app.add_plugin(TailwindPlugin); + #[cfg(target_family = "unix")] + app.add_plugin(UnixToolPlugin); } } diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 9b0eec4..efe7164 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -7,7 +7,8 @@ use bevy::{ }, log, }; -use std::{env, fs, path::PathBuf}; +use std::{env, fs, os::unix, path::PathBuf}; +use walkdir::WalkDir; // Plugin @@ -15,59 +16,67 @@ pub struct DotfilesPlugin; impl Plugin for DotfilesPlugin { fn build(&self, app: &mut App) { - app.add_event::() + app.add_event::() .add_system_to_stage(BundleStage::Apply, apply) - .add_system_to_stage(BundleStage::Apply, apply_dotfiles.after(apply)); + .add_system_to_stage(BundleStage::Apply, apply_symlinks.after(apply)); } } // Events -struct ApplyDotfiles { +struct ApplySymlinks { path: PathBuf, } -fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { +fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { events.iter().for_each(|e| { - log::warn!("TODO: apply dotfiles"); - // Walk through ./bundle/dotfiles/* - let current_path = env::current_dir().expect("Failed to get current directory."); - let dotfiles_path = current_path.join(&e.path).join("bundle").join("dotfiles"); + // let current_path = env::current_dir().expect("Failed to get current directory."); + // let dotfiles_path = current_path.join(&e.path).join("bundle").join("dotfiles"); + let dotfiles_path = &e.path.join("bundle").join("dotfiles"); if dotfiles_path.is_dir() { - log::info!("📌"); + log::info!("📌 Apply dotfiles"); fs::read_dir(dotfiles_path) .unwrap() - .filter_map(|path| { - if let Ok(path) = path { - if path.file_type().unwrap().is_dir() { - Some(path) - } else { - None - } - } else { - None - } - }) + .filter(|entry| entry.is_ok()) + .filter_map(Result::ok) + .filter(|entry| entry.file_type().unwrap().is_dir()) .for_each(|dir_entry| { - apply_dotfiles.send(ApplyDotfiles { + apply_dotfiles.send(ApplySymlinks { path: dir_entry.path(), }); }); } else { log::info!( "dotfiles direcotry is empty: {}", - &dotfiles_path.into_os_string().into_string().unwrap() + &dotfiles_path + .clone() + .into_os_string() + .into_string() + .unwrap() ); log::info!("🟡 Skip: Apply dotfiles"); } }); } -fn apply_dotfiles(mut events: EventReader) { +fn apply_symlinks(mut events: EventReader) { events.iter().for_each(|e| { + log::warn!("TODO: Get target path based on entry"); + let path = &e.path.clone().into_os_string().into_string().unwrap(); - println!("{}", path); + + WalkDir::new(path) + .into_iter() + .filter_map(|e| e.ok()) + .for_each(|entry| { + println!("----------------------------------------------------------"); + println!("entry : {:?}\ntarget: {:?}", entry.path(), entry.path()); + // let target_path = dirs::home_dir().unwrap().join(entry.path); + + // #[cfg(target_os = "unix")] + // unix::fs::symlink(entry.path(), link) + }); }); } diff --git a/plugins/bundle/src/tool/unix.rs b/plugins/bundle/src/tool/unix.rs new file mode 100644 index 0000000..7afcc9f --- /dev/null +++ b/plugins/bundle/src/tool/unix.rs @@ -0,0 +1,19 @@ +pub use crate::tool::{ + dotfiles::DotfilesPlugin, homebrew::HomebrewPlugin, tailwind::TailwindPlugin, +}; +use bevy::app::{App, Plugin}; + +pub struct UnixToolPlugin; + +impl Plugin for UnixToolPlugin { + fn build(&self, app: &mut App) { + #[cfg(feature = "dotfiles")] + app.add_plugin(DotfilesPlugin); + + #[cfg(feature = "brew")] + app.add_plugin(HomebrewPlugin); + + #[cfg(feature = "tailwind")] + app.add_plugin(TailwindPlugin); + } +} From 8346a76a7c084af1287f3227a091c5de58a1294a Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sat, 5 Nov 2022 20:55:39 +0100 Subject: [PATCH 09/22] Apply symlinks via DotfilesPlugin --- Cargo.lock | 1 + Cargo.toml | 3 +- plugins/bundle/Cargo.toml | 1 + plugins/bundle/src/tool/dotfiles.rs | 79 ++++++++++++++++++++++------- plugins/bundle/src/tool/homebrew.rs | 5 +- 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72594a4..15c621b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1306,6 +1306,7 @@ dependencies = [ "cmd_lib", "dip_core", "dirs", + "pathdiff", "reqwest", "tempfile", "walkdir", diff --git a/Cargo.toml b/Cargo.toml index 44b4c05..3613d25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,11 +28,12 @@ cmd_lib = "1" config = "0.13" dioxus = { version = "0.2", features = ["fermi"] } dip = { version = "0.1", path = ".", features = ["desktop"] } -dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["dotfiles"] } +dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["full"] } dip_core = { version = "0.1", path = "./plugins/core" } dip_macro = { version = "0.1", path = "./plugins/macro" } dip_task = { version = "0.1", path = "./plugins/task" } dirs = "4.0" +pathdiff = "0.2" reqwest = { version = "0.11", features = ["json", "blocking"] } tokio = { version = "1.18", features = ["rt-multi-thread", "sync", "macros", "fs"], default-features = false } serde = { version = "1.0", features = ["derive"] } diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index 3babdd2..1b64a80 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -8,6 +8,7 @@ bevy.workspace = true dip_core.workspace = true dirs.workspace = true cmd_lib.workspace = true +pathdiff.workspace = true reqwest.workspace = true tempfile.workspace = true walkdir.workspace = true diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index efe7164..27a2f1d 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -7,7 +7,8 @@ use bevy::{ }, log, }; -use std::{env, fs, os::unix, path::PathBuf}; +use pathdiff::diff_paths; +use std::{fs, os, path::PathBuf}; use walkdir::WalkDir; // Plugin @@ -25,14 +26,12 @@ impl Plugin for DotfilesPlugin { // Events struct ApplySymlinks { + dotfiles_path: PathBuf, path: PathBuf, } fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { events.iter().for_each(|e| { - // Walk through ./bundle/dotfiles/* - // let current_path = env::current_dir().expect("Failed to get current directory."); - // let dotfiles_path = current_path.join(&e.path).join("bundle").join("dotfiles"); let dotfiles_path = &e.path.join("bundle").join("dotfiles"); if dotfiles_path.is_dir() { @@ -44,6 +43,7 @@ fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter, mut apply_dotfiles: EventWriter) { events.iter().for_each(|e| { - log::warn!("TODO: Get target path based on entry"); - - let path = &e.path.clone().into_os_string().into_string().unwrap(); - - WalkDir::new(path) + WalkDir::new(&e.path) .into_iter() - .filter_map(|e| e.ok()) - .for_each(|entry| { - println!("----------------------------------------------------------"); - println!("entry : {:?}\ntarget: {:?}", entry.path(), entry.path()); - // let target_path = dirs::home_dir().unwrap().join(entry.path); + .filter_map(Result::ok) + .filter(|e| e.file_type().is_file()) + .map(|entry| { + let original = entry.path().to_path_buf(); + let diff = diff_paths(entry.path(), &e.dotfiles_path).unwrap(); + let dotfile_bundle_name = diff.iter().next().unwrap(); + let stripped = diff.strip_prefix(dotfile_bundle_name).unwrap(); + let link = dirs::home_dir().unwrap().join(stripped); - // #[cfg(target_os = "unix")] - // unix::fs::symlink(entry.path(), link) - }); + Symlink { original, link } + }) + .for_each(|symlink| symlink.apply()); }); } + +struct Symlink { + original: PathBuf, + link: PathBuf, +} + +impl Symlink { + fn apply(&self) { + if self.link.is_file() { + log::info!("----------------------------------------------------------"); + log::info!("🟡 Skip: File already exists"); + log::info!("original : {:?}", self.original); + log::info!("link : {:?}", self.link); + } else { + #[cfg(target_family = "unix")] + match os::unix::fs::symlink(&self.original, &self.link) { + Ok(_) => { + log::info!("----------------------------------------------------------"); + log::info!("original : {:?}", self.original); + log::info!("link : {:?}", self.link); + } + Err(e) => { + log::error!("----------------------------------------------------------"); + log::error!("{e}"); + log::error!("original : {:?}", self.original); + log::error!("link : {:?}", self.link); + } + } + + #[cfg(target_family = "windows")] + match os::windows::fs::symlink(&self.original, &self.link) { + Ok(_) => { + log::info!("----------------------------------------------------------"); + log::info!("original : {:?}", self.original); + log::info!("link : {:?}", self.link); + } + Err(e) => { + log::error!("----------------------------------------------------------"); + log::error!("{e}"); + log::error!("original : {:?}", self.original); + log::error!("link : {:?}", self.link); + } + } + } + } +} diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index 7556e51..4860971 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -37,14 +37,14 @@ fn install(mut events: EventReader) { .join("Brewfile"); if !brewfile_path.is_file() { + log::info!("🟡 Skip: Install Homebrew"); log::info!( "Brewfile does not exist: {}", brewfile_path.into_os_string().into_string().unwrap() ); - log::info!("🟡 Skip: Install Homebrew"); } else if run_fun!(which brew).is_ok() { - log::info!("brew path already exists"); log::info!("🟡 Skip: Install Homebrew"); + log::info!("brew path already exists"); } else { log::info!("📌 Install Homebrew"); @@ -82,7 +82,6 @@ fn install(mut events: EventReader) { if let Err(e) = result { log::error!("Failed to run brew install."); log::error!("{e}"); - log::info!("✅ Install Homebrew"); } else { log::info!("✅ Install Homebrew"); } From fa516d90c66b43597fa8bc1fd891ddef469c2d5e Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sun, 6 Nov 2022 16:58:04 +0100 Subject: [PATCH 10/22] Fix symlink path with canonicalize method --- plugins/bundle/src/tool/dotfiles.rs | 31 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 27a2f1d..fe2b259 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -8,8 +8,8 @@ use bevy::{ log, }; use pathdiff::diff_paths; -use std::{fs, os, path::PathBuf}; -use walkdir::WalkDir; +use std::{fs::{self, DirEntry}, os, path::PathBuf}; +use walkdir::{WalkDir}; // Plugin @@ -27,7 +27,7 @@ impl Plugin for DotfilesPlugin { struct ApplySymlinks { dotfiles_path: PathBuf, - path: PathBuf, + dir_entry: DirEntry, } fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { @@ -40,11 +40,10 @@ fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter, mut apply_dotfiles: EventWriter) { events.iter().for_each(|e| { - WalkDir::new(&e.path) + WalkDir::new(&e.dir_entry.path()) .into_iter() .filter_map(Result::ok) - .filter(|e| e.file_type().is_file()) - .map(|entry| { - let original = entry.path().to_path_buf(); + .filter_map(|entry| { + let original = entry.path().to_path_buf().canonicalize().unwrap(); let diff = diff_paths(entry.path(), &e.dotfiles_path).unwrap(); let dotfile_bundle_name = diff.iter().next().unwrap(); let stripped = diff.strip_prefix(dotfile_bundle_name).unwrap(); let link = dirs::home_dir().unwrap().join(stripped); - Symlink { original, link } + if entry.file_type().is_dir() { + fs::create_dir_all(link).unwrap(); + None + } else { + Some(Symlink { original, link }) + } }) .for_each(|symlink| symlink.apply()); }); @@ -87,7 +90,13 @@ struct Symlink { impl Symlink { fn apply(&self) { - if self.link.is_file() { + if self.link.is_symlink() { + log::info!("----------------------------------------------------------"); + log::info!("🟡 Skip: File is already symlinked"); + log::info!("original : {:?}", self.original); + log::info!("link : {:?}", self.link); + } + else if self.link.is_file() { log::info!("----------------------------------------------------------"); log::info!("🟡 Skip: File already exists"); log::info!("original : {:?}", self.original); From b0ba8e0e814cc8c1906675dc377bae1f1ae16c7f Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Sun, 6 Nov 2022 21:08:47 +0100 Subject: [PATCH 11/22] cleanup --- plugins/bundle/src/tool/dotfiles.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index fe2b259..3c87c74 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -8,8 +8,12 @@ use bevy::{ log, }; use pathdiff::diff_paths; -use std::{fs::{self, DirEntry}, os, path::PathBuf}; -use walkdir::{WalkDir}; +use std::{ + fs::{self, DirEntry}, + os, + path::PathBuf, +}; +use walkdir::WalkDir; // Plugin @@ -55,6 +59,7 @@ fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter Date: Sun, 6 Nov 2022 23:44:07 +0100 Subject: [PATCH 12/22] Add script bundle plugin --- Cargo.lock | 1 + Cargo.toml | 1 + plugins/bundle/Cargo.toml | 1 + plugins/bundle/src/lib.rs | 1 + plugins/bundle/src/schedule.rs | 16 +++- plugins/bundle/src/tool.rs | 1 + plugins/bundle/src/tool/homebrew.rs | 129 +++++++++++++--------------- plugins/bundle/src/tool/script.rs | 126 +++++++++++++++++++++++++++ plugins/bundle/src/tool/unix.rs | 5 +- plugins/core/src/schedule.rs | 2 +- plugins/macro/Cargo.toml | 2 +- 11 files changed, 210 insertions(+), 75 deletions(-) create mode 100644 plugins/bundle/src/tool/script.rs diff --git a/Cargo.lock b/Cargo.lock index 15c621b..0d89224 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1304,6 +1304,7 @@ version = "0.1.0" dependencies = [ "bevy", "cmd_lib", + "convert_case 0.5.0", "dip_core", "dirs", "pathdiff", diff --git a/Cargo.toml b/Cargo.toml index 3613d25..6828727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ bevy = { version = "0.8", default-features = false } bevy_ecs = "0.8" cmd_lib = "1" config = "0.13" +convert_case = "0.5" dioxus = { version = "0.2", features = ["fermi"] } dip = { version = "0.1", path = ".", features = ["desktop"] } dip_bundle = { version = "0.1", path = "./plugins/bundle", features = ["full"] } diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index 1b64a80..3241e5f 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -8,6 +8,7 @@ bevy.workspace = true dip_core.workspace = true dirs.workspace = true cmd_lib.workspace = true +convert_case.workspace = true pathdiff.workspace = true reqwest.workspace = true tempfile.workspace = true diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index 3c25ca9..3e92d96 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -26,6 +26,7 @@ impl Plugin for BundlePlugin { // Events +#[derive(Clone)] pub struct ApplyBundle { pub verbose: bool, pub path: PathBuf, diff --git a/plugins/bundle/src/schedule.rs b/plugins/bundle/src/schedule.rs index 7e63fc1..86150d7 100644 --- a/plugins/bundle/src/schedule.rs +++ b/plugins/bundle/src/schedule.rs @@ -9,12 +9,17 @@ pub struct BundleSchedulePlugin; impl Plugin for BundleSchedulePlugin { fn build(&self, app: &mut App) { app.add_stage_after( - DipStage::Prepare, + DipStage::Render, + BundleStage::First, + SystemStage::parallel(), + ) + .add_stage_after( + BundleStage::First, BundleStage::Prepare, SystemStage::parallel(), ) .add_stage_after( - DipStage::Apply, + BundleStage::Prepare, BundleStage::Install, SystemStage::parallel(), ) @@ -22,13 +27,20 @@ impl Plugin for BundleSchedulePlugin { BundleStage::Install, BundleStage::Apply, SystemStage::parallel(), + ) + .add_stage_after( + BundleStage::Apply, + BundleStage::Last, + SystemStage::parallel(), ); } } #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] pub enum BundleStage { + First, Prepare, Install, Apply, + Last, } diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index f0baeb3..6803418 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -1,5 +1,6 @@ mod dotfiles; mod homebrew; +mod script; mod tailwind; mod unix; diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index 4860971..07c40ba 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -28,85 +28,75 @@ impl Plugin for HomebrewPlugin { // Systems fn install(mut events: EventReader) { - events.iter().for_each(|e| { - let current_path = env::current_dir().expect("Failed to get current directory."); - let brewfile_path = current_path - .join(&e.path) - .join("bundle") - .join("homebrew") - .join("Brewfile"); + events.iter().for_each( + |e| match &e.path.join("bundle/homebrew/Brewfile").canonicalize() { + Ok(_brewfile_path) => { + if run_fun!(which brew).is_ok() { + log::info!("🟡 Skip: Install Homebrew"); + log::info!("brew path already exists"); + } else { + log::info!("📌 Install Homebrew"); - if !brewfile_path.is_file() { - log::info!("🟡 Skip: Install Homebrew"); - log::info!( - "Brewfile does not exist: {}", - brewfile_path.into_os_string().into_string().unwrap() - ); - } else if run_fun!(which brew).is_ok() { - log::info!("🟡 Skip: Install Homebrew"); - log::info!("brew path already exists"); - } else { - log::info!("📌 Install Homebrew"); + let install_sh = reqwest::blocking::get( + "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", + ) + .expect("Failed to fetch Homebrew installation script") + .text() + .expect("Failed to parse Homebrew installation script into text"); - let install_sh = reqwest::blocking::get( - "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", - ) - .expect("Failed to fetch Homebrew installation script") - .text() - .expect("Failed to parse Homebrew installation script into text"); + let dir = tempdir().unwrap(); + let file_path = dir.path().join("brew-install.sh"); + let file_path_str = file_path.clone().into_os_string(); + let mut file = File::create(file_path).unwrap(); + file.write_all(install_sh.as_bytes()) + .expect("Unable to write file"); - let dir = tempdir().unwrap(); - let file_path = dir.path().join("brew-install.sh"); - let file_path_str = file_path.clone().into_os_string(); - let mut file = File::create(file_path).unwrap(); - file.write_all(install_sh.as_bytes()) - .expect("Unable to write file"); + let mut install_brew = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); - let mut install_brew = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); + let result = if e.verbose { + install_brew.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| log::info!("{f}")); + }) + } else { + if let Err(e) = install_brew.wait_with_output() { + Err(e) + } else { + Ok(()) + } + }; - let result = if e.verbose { - install_brew.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|f| log::info!("{f}")); - }) - } else { - if let Err(e) = install_brew.wait_with_output() { - Err(e) - } else { - Ok(()) + if let Err(e) = result { + log::error!("Failed to run brew install."); + log::error!("{e}"); + } else { + log::info!("✅ Install Homebrew"); + } } - }; - - if let Err(e) = result { - log::error!("Failed to run brew install."); - log::error!("{e}"); - } else { - log::info!("✅ Install Homebrew"); } - } - }); + Err(_e) => { + log::info!("🟡 Skip: Install Homebrew"); + log::info!("bundle/homebrew/Brewfile does not exists.",); + } + }, + ); } - fn apply(mut events: EventReader) { events.iter().for_each(|e| { let current_path = env::current_dir().expect("Failed to get current directory."); - let brewfile_path = current_path - .join(&e.path) - .join("bundle") - .join("homebrew") - .join("Brewfile"); - let brewfile_path_str = &brewfile_path - .clone() - .into_os_string() - .into_string() - .unwrap(); + let brewfile_path = current_path.join(&e.path).join("bundle/homebrew/Brewfile"); - if brewfile_path.is_file() { - match run_fun!(which brew) { + match brewfile_path.canonicalize() { + Ok(_brewfile_path) => match run_fun!(which brew) { Ok(_brew_path) => { log::info!("📌 Apply Homebrew bundle"); + let brewfile_path_str = &brewfile_path + .clone() + .into_os_string() + .into_string() + .unwrap(); let mut brew_bundle = spawn_with_output!(brew bundle --file $brewfile_path_str).unwrap(); @@ -137,12 +127,11 @@ fn apply(mut events: EventReader) { log::error!("{e}"); log::error!("Could not find homebrew binary."); } + }, + Err(_e) => { + log::info!("🟡 Skip: Apply Homebrew bundle"); + log::info!("bundle/homebrew/Brewfile does not exists."); } - } else { - log::error!( - "Failed to apply Homebrew bundle. Make sure to have: {}", - brewfile_path_str - ); } }); } diff --git a/plugins/bundle/src/tool/script.rs b/plugins/bundle/src/tool/script.rs new file mode 100644 index 0000000..6cf6379 --- /dev/null +++ b/plugins/bundle/src/tool/script.rs @@ -0,0 +1,126 @@ +use bevy::{ + app::{App, Plugin}, + ecs::event::EventReader, + log, +}; +use cmd_lib::spawn_with_output; +use convert_case::{Case, Casing}; +use std::{ + io::{self, BufRead, BufReader}, + path::PathBuf, +}; + +use crate::{ApplyBundle, BundleStage}; + +pub struct ScriptPlugin; + +impl Plugin for ScriptPlugin { + fn build(&self, app: &mut App) { + app.add_system_to_stage(BundleStage::First, pre_script) + .add_system_to_stage(BundleStage::Last, post_script); + } +} + +fn pre_script(mut events: EventReader) { + events.iter().for_each(|e| Script::pre(e.clone()).run()); +} + +fn post_script(mut events: EventReader) { + events.iter().for_each(|e| Script::post(e.clone()).run()); +} + +struct Script { + event: ApplyBundle, + schedule: ScriptSchedule, +} + +impl Script { + fn pre(event: ApplyBundle) -> Self { + Self { + event, + schedule: ScriptSchedule::Pre, + } + } + + fn post(event: ApplyBundle) -> Self { + Self { + event, + schedule: ScriptSchedule::Post, + } + } + + fn run(&self) { + match self.find_file() { + Ok(file_path) => { + log::info!("📌 {} script", self.schedule.to_upper_camel()); + + let file_path_str = file_path.display(); + let mut script = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); + + let result = if self.event.verbose { + script.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| log::info!("{f}")); + }) + } else { + if let Err(e) = script.wait_with_output() { + Err(e) + } else { + Ok(()) + } + }; + + if let Err(e) = result { + log::error!("Failed to run {} script.", self.schedule.to_string()); + log::error!("{e}"); + } else { + log::info!("✅ {} script", self.schedule.to_upper_camel()); + } + } + Err(_e) => { + self.skip(); + } + } + } + + fn skip(&self) { + log::info!("🟡 Skip: {} script", &self.schedule.to_upper_camel()); + log::info!("{} does not exists.", &self.file_path().display()); + } + + fn find_file(&self) -> io::Result { + self.file_path().canonicalize() + } + + fn file_path(&self) -> PathBuf { + self.event + .path + .join(format!("bundle/scripts/{}", &self.file_name())) + } + + fn file_name(&self) -> String { + format!("{}.sh", self.schedule.to_string()) + } +} + +enum ScriptSchedule { + Pre, + Post, +} + +impl ScriptSchedule { + fn to_upper_camel(&self) -> String { + self.to_string().to_case(Case::UpperCamel) + } +} + +impl ToString for ScriptSchedule { + fn to_string(&self) -> String { + match self { + ScriptSchedule::Pre => "pre".into(), + ScriptSchedule::Post => "post".into(), + } + } +} diff --git a/plugins/bundle/src/tool/unix.rs b/plugins/bundle/src/tool/unix.rs index 7afcc9f..c42b110 100644 --- a/plugins/bundle/src/tool/unix.rs +++ b/plugins/bundle/src/tool/unix.rs @@ -1,5 +1,6 @@ pub use crate::tool::{ - dotfiles::DotfilesPlugin, homebrew::HomebrewPlugin, tailwind::TailwindPlugin, + dotfiles::DotfilesPlugin, homebrew::HomebrewPlugin, script::ScriptPlugin, + tailwind::TailwindPlugin, }; use bevy::app::{App, Plugin}; @@ -7,6 +8,8 @@ pub struct UnixToolPlugin; impl Plugin for UnixToolPlugin { fn build(&self, app: &mut App) { + app.add_plugin(ScriptPlugin); + #[cfg(feature = "dotfiles")] app.add_plugin(DotfilesPlugin); diff --git a/plugins/core/src/schedule.rs b/plugins/core/src/schedule.rs index 863b137..7f9e223 100644 --- a/plugins/core/src/schedule.rs +++ b/plugins/core/src/schedule.rs @@ -44,6 +44,6 @@ impl Plugin for UiSchedulePlugin { SystemStage::parallel(), ) .add_stage_after(DipStage::Prepare, DipStage::Apply, SystemStage::parallel()) - .add_stage_after(DipStage::Prepare, DipStage::Render, SystemStage::parallel()); + .add_stage_after(DipStage::Apply, DipStage::Render, SystemStage::parallel()); } } diff --git a/plugins/macro/Cargo.toml b/plugins/macro/Cargo.toml index c02ae57..5a60532 100644 --- a/plugins/macro/Cargo.toml +++ b/plugins/macro/Cargo.toml @@ -13,7 +13,7 @@ keywords.workspace = true proc-macro = true [dependencies] -convert_case = "0.5" +convert_case.workspace = true dirs.workspace = true quote = "1.0" proc-macro2 = "1.0" From 2d0d5abd887ea222afe0705827680943bbb2bbc1 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Mon, 7 Nov 2022 00:24:42 +0100 Subject: [PATCH 13/22] [WIP] Refactor Homebrew struct --- plugins/bundle/src/tool.rs | 1 + plugins/bundle/src/tool/homebrew.rs | 54 +++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index 6803418..823e2bb 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -24,6 +24,7 @@ impl Plugin for ToolPlugin { // Events +#[derive(Clone)] pub struct InstallTools { pub verbose: bool, pub path: PathBuf, diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index 07c40ba..f02de1c 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -6,9 +6,9 @@ use bevy::{ }; use cmd_lib::{run_fun, spawn_with_output}; use std::{ - env, fs::File, io::{BufRead, BufReader, Write}, + path::PathBuf, }; use tempfile::tempdir; @@ -28,8 +28,24 @@ impl Plugin for HomebrewPlugin { // Systems fn install(mut events: EventReader) { - events.iter().for_each( - |e| match &e.path.join("bundle/homebrew/Brewfile").canonicalize() { + events.iter().for_each(|e| { + Homebrew::from(e.clone()).install(); + }); +} +fn apply(mut events: EventReader) { + events.iter().for_each(|e| { + Homebrew::from(e.clone()).apply(); + }); +} + +struct Homebrew { + pub verbose: bool, + pub path: PathBuf, +} + +impl Homebrew { + fn install(&self) { + match &self.path.join("bundle/homebrew/Brewfile").canonicalize() { Ok(_brewfile_path) => { if run_fun!(which brew).is_ok() { log::info!("🟡 Skip: Install Homebrew"); @@ -53,7 +69,7 @@ fn install(mut events: EventReader) { let mut install_brew = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); - let result = if e.verbose { + let result = if self.verbose { install_brew.wait_with_pipe(&mut |pipe| { BufReader::new(pipe) .lines() @@ -80,16 +96,12 @@ fn install(mut events: EventReader) { log::info!("🟡 Skip: Install Homebrew"); log::info!("bundle/homebrew/Brewfile does not exists.",); } - }, - ); -} -fn apply(mut events: EventReader) { - events.iter().for_each(|e| { - let current_path = env::current_dir().expect("Failed to get current directory."); - let brewfile_path = current_path.join(&e.path).join("bundle/homebrew/Brewfile"); + } + } - match brewfile_path.canonicalize() { - Ok(_brewfile_path) => match run_fun!(which brew) { + fn apply(&self) { + match &self.path.join("bundle/homebrew/Brewfile").canonicalize() { + Ok(brewfile_path) => match run_fun!(which brew) { Ok(_brew_path) => { log::info!("📌 Apply Homebrew bundle"); let brewfile_path_str = &brewfile_path @@ -101,7 +113,7 @@ fn apply(mut events: EventReader) { let mut brew_bundle = spawn_with_output!(brew bundle --file $brewfile_path_str).unwrap(); - let result = if e.verbose { + let result = if self.verbose { brew_bundle.wait_with_pipe(&mut |pipe| { BufReader::new(pipe) .lines() @@ -133,5 +145,17 @@ fn apply(mut events: EventReader) { log::info!("bundle/homebrew/Brewfile does not exists."); } } - }); + } +} + +impl From for Homebrew { + fn from(InstallTools { verbose, path }: InstallTools) -> Self { + Self { verbose, path } + } +} + +impl From for Homebrew { + fn from(ApplyBundle { verbose, path }: ApplyBundle) -> Self { + Self { verbose, path } + } } From 9058c358deaf6de411eb0e066caec55670846d2c Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Mon, 7 Nov 2022 20:48:43 +0100 Subject: [PATCH 14/22] Remove prompt from homebrew installer --- plugins/bundle/src/tool/homebrew.rs | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index f02de1c..fd0f900 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -1,19 +1,17 @@ -use crate::{ApplyBundle, BundleStage}; +use crate::{tool::InstallTools, ApplyBundle, BundleStage}; use bevy::{ app::{App, Plugin}, ecs::event::EventReader, log, }; -use cmd_lib::{run_fun, spawn_with_output}; +use cmd_lib::spawn_with_output; use std::{ fs::File, io::{BufRead, BufReader, Write}, - path::PathBuf, + path::{Path, PathBuf}, }; use tempfile::tempdir; -use super::InstallTools; - // Plugin pub struct HomebrewPlugin; @@ -44,10 +42,18 @@ struct Homebrew { } impl Homebrew { + fn homebrew_path() -> &'static str { + "/opt/homebrew/bin/brew" + } + + fn brewfile_path(&self) -> PathBuf { + self.path.join("bundle/homebrew/Brewfile") + } + fn install(&self) { - match &self.path.join("bundle/homebrew/Brewfile").canonicalize() { + match &self.brewfile_path().canonicalize() { Ok(_brewfile_path) => { - if run_fun!(which brew).is_ok() { + if Path::new(Self::homebrew_path()).exists() { log::info!("🟡 Skip: Install Homebrew"); log::info!("brew path already exists"); } else { @@ -67,7 +73,8 @@ impl Homebrew { file.write_all(install_sh.as_bytes()) .expect("Unable to write file"); - let mut install_brew = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); + let mut install_brew = + spawn_with_output!(NONINTERACTIVE=1 /bin/bash -C $file_path_str).unwrap(); let result = if self.verbose { install_brew.wait_with_pipe(&mut |pipe| { @@ -100,9 +107,9 @@ impl Homebrew { } fn apply(&self) { - match &self.path.join("bundle/homebrew/Brewfile").canonicalize() { - Ok(brewfile_path) => match run_fun!(which brew) { - Ok(_brew_path) => { + match &self.brewfile_path().canonicalize() { + Ok(brewfile_path) => { + if Path::new(Self::homebrew_path()).exists() { log::info!("📌 Apply Homebrew bundle"); let brewfile_path_str = &brewfile_path .clone() @@ -111,7 +118,8 @@ impl Homebrew { .unwrap(); let mut brew_bundle = - spawn_with_output!(brew bundle --file $brewfile_path_str).unwrap(); + spawn_with_output!(brew bundle --cleanup --file $brewfile_path_str) + .unwrap(); let result = if self.verbose { brew_bundle.wait_with_pipe(&mut |pipe| { @@ -134,12 +142,10 @@ impl Homebrew { } else { log::info!("✅ Apply Homebrew bundle"); } - } - Err(e) => { - log::error!("{e}"); + } else { log::error!("Could not find homebrew binary."); } - }, + } Err(_e) => { log::info!("🟡 Skip: Apply Homebrew bundle"); log::info!("bundle/homebrew/Brewfile does not exists."); From 4561daf2325ee6ee8faf1bed0494e3833b201036 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Tue, 8 Nov 2022 15:33:27 +0100 Subject: [PATCH 15/22] Setup bundle clean subcommand without implementation --- plugins/bundle/src/lib.rs | 35 +++++++++++------------------ plugins/bundle/src/schedule.rs | 6 ++--- plugins/bundle/src/tool.rs | 7 +----- plugins/bundle/src/tool/dotfiles.rs | 11 +++++++-- src/cli.rs | 18 +++++++++++++-- src/cli/action.rs | 9 ++++++++ 6 files changed, 51 insertions(+), 35 deletions(-) diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index 3e92d96..6b8e1b6 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -9,7 +9,7 @@ use bevy::{ // pub use config::BundleConfigPlugin; pub use schedule::{BundleSchedulePlugin, BundleStage}; use std::path::PathBuf; -use tool::{ApplyTools, InstallTools, ToolPlugin}; +use tool::{InstallTools, ToolPlugin}; pub struct BundlePlugin; @@ -17,10 +17,10 @@ impl Plugin for BundlePlugin { fn build(&self, app: &mut App) { app.add_plugin(BundleSchedulePlugin) .add_event::() - .add_event::() + .add_event::() // .add_plugin(BundleConfigPlugin) .add_plugin(ToolPlugin) - .add_system_to_stage(BundleStage::Prepare, apply_bundle); + .add_system_to_stage(BundleStage::Apply, apply_bundle); } } @@ -32,29 +32,20 @@ pub struct ApplyBundle { pub path: PathBuf, } -pub struct BundleApplied; +#[derive(Clone)] +pub struct CleanBundle { + pub verbose: bool, + pub path: PathBuf, +} fn apply_bundle( mut events: EventReader, mut install_tools: EventWriter, - mut apply_tools: EventWriter, ) { - events - .iter() - .map(|e| { - ( - InstallTools { - verbose: e.verbose, - path: e.path.clone(), - }, - ApplyTools { - verbose: e.verbose, - path: e.path.clone(), - }, - ) - }) - .for_each(|(install, apply)| { - install_tools.send(install); - apply_tools.send(apply); + events.iter().for_each(|e| { + install_tools.send(InstallTools { + verbose: e.verbose, + path: e.path.clone(), }); + }); } diff --git a/plugins/bundle/src/schedule.rs b/plugins/bundle/src/schedule.rs index 86150d7..c92ee93 100644 --- a/plugins/bundle/src/schedule.rs +++ b/plugins/bundle/src/schedule.rs @@ -15,11 +15,11 @@ impl Plugin for BundleSchedulePlugin { ) .add_stage_after( BundleStage::First, - BundleStage::Prepare, + BundleStage::Clean, SystemStage::parallel(), ) .add_stage_after( - BundleStage::Prepare, + BundleStage::Clean, BundleStage::Install, SystemStage::parallel(), ) @@ -39,7 +39,7 @@ impl Plugin for BundleSchedulePlugin { #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)] pub enum BundleStage { First, - Prepare, + Clean, Install, Apply, Last, diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index 823e2bb..8814d90 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -15,7 +15,7 @@ pub struct ToolPlugin; impl Plugin for ToolPlugin { fn build(&self, app: &mut App) { - app.add_event::().add_event::(); + app.add_event::(); #[cfg(target_family = "unix")] app.add_plugin(UnixToolPlugin); @@ -30,11 +30,6 @@ pub struct InstallTools { pub path: PathBuf, } -pub struct ApplyTools { - pub verbose: bool, - pub path: PathBuf, -} - // Commponents #[derive(Component)] diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 3c87c74..5b701ff 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -1,4 +1,4 @@ -use crate::{ApplyBundle, BundleStage}; +use crate::{ApplyBundle, BundleStage, CleanBundle}; use bevy::{ app::{App, Plugin}, ecs::{ @@ -23,7 +23,8 @@ impl Plugin for DotfilesPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_system_to_stage(BundleStage::Apply, apply) - .add_system_to_stage(BundleStage::Apply, apply_symlinks.after(apply)); + .add_system_to_stage(BundleStage::Apply, apply_symlinks.after(apply)) + .add_system_to_stage(BundleStage::Clean, clean); } } @@ -88,6 +89,12 @@ fn apply_symlinks(mut events: EventReader) { }); } +fn clean(mut events: EventReader) { + events.iter().for_each(|_e| { + println!("hey"); + }); +} + struct Symlink { original: PathBuf, link: PathBuf, diff --git a/src/cli.rs b/src/cli.rs index c11de37..e208e8b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,8 @@ mod action; -use crate::cli::action::{ActionPlugin, ApplyBundleAction, BundleActionPlugin, CliPlugin}; +use crate::cli::action::{ + ActionPlugin, ApplyBundleAction, BundleActionPlugin, CleanBundleAction, CliPlugin, +}; use dip::{ bevy::{ app::{App, Plugin}, @@ -9,6 +11,7 @@ use dip::{ bundle::{ApplyBundle, BundlePlugin}, core::task::NoAsyncAction, }; +use dip_bundle::CleanBundle; use std::path::PathBuf; pub struct DipCliPlugin; @@ -19,7 +22,8 @@ impl Plugin for DipCliPlugin { .add_plugin(ActionPlugin) .add_plugin(BundleActionPlugin) .add_plugin(BundlePlugin) - .add_system(apply_bundle); + .add_system(apply_bundle) + .add_system(clean_bundle); } } @@ -32,3 +36,13 @@ fn apply_bundle(mut actions: EventReader, mut apply: EventWri }); }); } + +fn clean_bundle(mut actions: EventReader, mut clean: EventWriter) { + actions.iter().for_each(|a| { + clean.send(CleanBundle { + // verbose: a.verbose, + verbose: true, + path: PathBuf::from(&a.path), + }) + }); +} diff --git a/src/cli/action.rs b/src/cli/action.rs index e476223..ee1d9e0 100644 --- a/src/cli/action.rs +++ b/src/cli/action.rs @@ -40,6 +40,7 @@ pub struct BuildArgs { #[derive(SubcommandPlugin, clap::Subcommand, Clone, Debug)] pub enum BundleAction { Apply(ApplyBundleArgs), + Clean(CleanBundleArgs), } #[derive(clap::Args, Clone, Debug)] @@ -49,3 +50,11 @@ pub struct ApplyBundleArgs { #[clap(short, long, default_value_t = String::from("."))] pub path: String, } + +#[derive(clap::Args, Clone, Debug)] +pub struct CleanBundleArgs { + // #[clap(short, long, required = false)] + // pub verbose: bool, + #[clap(short, long, default_value_t = String::from("."))] + pub path: String, +} From a6f56df602887b4df8b00630877809112c5cc718 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Wed, 9 Nov 2022 09:17:47 +0100 Subject: [PATCH 16/22] Replace logs with println --- plugins/bundle/src/lib.rs | 4 ++ plugins/bundle/src/tool/dotfiles.rs | 80 +++++++++++++++++++---------- plugins/bundle/src/tool/homebrew.rs | 45 ++++++++-------- plugins/bundle/src/tool/script.rs | 15 +++--- src/cli.rs | 10 ++-- src/main.rs | 19 +------ 6 files changed, 96 insertions(+), 77 deletions(-) diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index 6b8e1b6..7117925 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -38,6 +38,10 @@ pub struct CleanBundle { pub path: PathBuf, } +pub trait Bundle { + fn bundle_path(&self) -> PathBuf; +} + fn apply_bundle( mut events: EventReader, mut install_tools: EventWriter, diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 5b701ff..a954e00 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -1,11 +1,10 @@ -use crate::{ApplyBundle, BundleStage, CleanBundle}; +use crate::{ApplyBundle, Bundle, BundleStage, CleanBundle}; use bevy::{ app::{App, Plugin}, ecs::{ event::{EventReader, EventWriter}, schedule::ParallelSystemDescriptorCoercion, }, - log, }; use pathdiff::diff_paths; use std::{ @@ -37,10 +36,11 @@ struct ApplySymlinks { fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { events.iter().for_each(|e| { - let dotfiles_path = &e.path.join("bundle").join("dotfiles"); + let dotfiles = Dotfiles::from(e.clone()); + let dotfiles_path = &dotfiles.bundle_path(); if dotfiles_path.is_dir() { - log::info!("📌 Apply dotfiles"); + println!("📌 Apply dotfiles"); fs::read_dir(dotfiles_path) .unwrap() .filter(|entry| entry.is_ok()) @@ -52,7 +52,7 @@ fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter, mut apply_dotfiles: EventWriter) { }); } +struct Dotfiles { + pub verbose: bool, + pub path: PathBuf, +} + +impl Bundle for Dotfiles { + fn bundle_path(&self) -> PathBuf { + self.path.join("bundle/dotfiles") + } +} + +impl From for Dotfiles { + fn from(ApplyBundle { verbose, path }: ApplyBundle) -> Self { + Self { verbose, path } + } +} + +impl From for Dotfiles { + fn from(CleanBundle { verbose, path }: CleanBundle) -> Self { + Self { verbose, path } + } +} + fn clean(mut events: EventReader) { events.iter().for_each(|_e| { println!("hey"); @@ -103,45 +126,46 @@ struct Symlink { impl Symlink { fn apply(&self) { if self.link.is_symlink() { - log::info!("----------------------------------------------------------"); - log::info!("🟡 Skip: File is already symlinked"); - log::info!("original : {:?}", self.original); - log::info!("link : {:?}", self.link); + println!( + "{}", + &self.symlink_log_message(Some("🟡 Skip: File is already symlinked")) + ); } else if self.link.is_file() { - log::info!("----------------------------------------------------------"); - log::info!("🟡 Skip: File already exists"); - log::info!("original : {:?}", self.original); - log::info!("link : {:?}", self.link); + println!( + "{}", + &self.symlink_log_message(Some("🟡 Skip: File already exists")) + ); } else { #[cfg(target_family = "unix")] match os::unix::fs::symlink(&self.original, &self.link) { Ok(_) => { - log::info!("----------------------------------------------------------"); - log::info!("original : {:?}", self.original); - log::info!("link : {:?}", self.link); + println!("{}", &self.symlink_log_message(None)); } Err(e) => { - log::error!("----------------------------------------------------------"); - log::error!("{e}"); - log::error!("original : {:?}", self.original); - log::error!("link : {:?}", self.link); + eprintln!("{}", &self.symlink_log_message(Some(&e.to_string()))); } } #[cfg(target_family = "windows")] match os::windows::fs::symlink(&self.original, &self.link) { Ok(_) => { - log::info!("----------------------------------------------------------"); - log::info!("original : {:?}", self.original); - log::info!("link : {:?}", self.link); + println!("{}", &self.symlink_log_message(None)); } Err(e) => { - log::error!("----------------------------------------------------------"); - log::error!("{e}"); - log::error!("original : {:?}", self.original); - log::error!("link : {:?}", self.link); + printlne!("{}", &self.symlink_log_message(Some(&e.to_string()))); } } } } + + fn symlink_log_message<'a>(&self, message: Option<&'a str>) -> String { + let message = message.unwrap_or("".into()); + format!( + "----------------------------------------------------------\n\ + {message}\n\ + original : {:?}\n\ + link : {:?}", + &self.original, &self.link, + ) + } } diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index fd0f900..b3fafd8 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -1,8 +1,7 @@ -use crate::{tool::InstallTools, ApplyBundle, BundleStage}; +use crate::{tool::InstallTools, ApplyBundle, Bundle, BundleStage}; use bevy::{ app::{App, Plugin}, ecs::event::EventReader, - log, }; use cmd_lib::spawn_with_output; use std::{ @@ -41,23 +40,29 @@ struct Homebrew { pub path: PathBuf, } +impl Bundle for Homebrew { + fn bundle_path(&self) -> PathBuf { + self.path.join("bundle/homebrew") + } +} + impl Homebrew { fn homebrew_path() -> &'static str { "/opt/homebrew/bin/brew" } fn brewfile_path(&self) -> PathBuf { - self.path.join("bundle/homebrew/Brewfile") + self.bundle_path().join("bundle/homebrew/Brewfile") } fn install(&self) { match &self.brewfile_path().canonicalize() { Ok(_brewfile_path) => { if Path::new(Self::homebrew_path()).exists() { - log::info!("🟡 Skip: Install Homebrew"); - log::info!("brew path already exists"); + println!("🟡 Skip: Install Homebrew"); + println!("brew path already exists"); } else { - log::info!("📌 Install Homebrew"); + println!("📌 Install Homebrew"); let install_sh = reqwest::blocking::get( "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", @@ -81,7 +86,7 @@ impl Homebrew { BufReader::new(pipe) .lines() .filter_map(|line| line.ok()) - .for_each(|f| log::info!("{f}")); + .for_each(|f| println!("{f}")); }) } else { if let Err(e) = install_brew.wait_with_output() { @@ -92,16 +97,16 @@ impl Homebrew { }; if let Err(e) = result { - log::error!("Failed to run brew install."); - log::error!("{e}"); + println!("Failed to run brew install."); + eprintln!("{e}"); } else { - log::info!("✅ Install Homebrew"); + println!("✅ Install Homebrew"); } } } Err(_e) => { - log::info!("🟡 Skip: Install Homebrew"); - log::info!("bundle/homebrew/Brewfile does not exists.",); + println!("🟡 Skip: Install Homebrew"); + println!("bundle/homebrew/Brewfile does not exists.",); } } } @@ -110,7 +115,7 @@ impl Homebrew { match &self.brewfile_path().canonicalize() { Ok(brewfile_path) => { if Path::new(Self::homebrew_path()).exists() { - log::info!("📌 Apply Homebrew bundle"); + println!("📌 Apply Homebrew bundle"); let brewfile_path_str = &brewfile_path .clone() .into_os_string() @@ -126,7 +131,7 @@ impl Homebrew { BufReader::new(pipe) .lines() .filter_map(|line| line.ok()) - .for_each(|line| log::info!("{:?}", line)); + .for_each(|line| println!("{:?}", line)); }) } else { if let Err(e) = brew_bundle.wait_with_output() { @@ -137,18 +142,18 @@ impl Homebrew { }; if let Err(e) = result { - log::error!("{e}"); - log::error!("Failed to run brew bundle."); + println!("Failed to run brew bundle."); + eprintln!("{e}"); } else { - log::info!("✅ Apply Homebrew bundle"); + println!("✅ Apply Homebrew bundle"); } } else { - log::error!("Could not find homebrew binary."); + eprintln!("Could not find homebrew binary."); } } Err(_e) => { - log::info!("🟡 Skip: Apply Homebrew bundle"); - log::info!("bundle/homebrew/Brewfile does not exists."); + println!("🟡 Skip: Apply Homebrew bundle"); + println!("bundle/homebrew/Brewfile does not exists."); } } } diff --git a/plugins/bundle/src/tool/script.rs b/plugins/bundle/src/tool/script.rs index 6cf6379..63bfc88 100644 --- a/plugins/bundle/src/tool/script.rs +++ b/plugins/bundle/src/tool/script.rs @@ -1,7 +1,6 @@ use bevy::{ app::{App, Plugin}, ecs::event::EventReader, - log, }; use cmd_lib::spawn_with_output; use convert_case::{Case, Casing}; @@ -52,7 +51,7 @@ impl Script { fn run(&self) { match self.find_file() { Ok(file_path) => { - log::info!("📌 {} script", self.schedule.to_upper_camel()); + println!("📌 {} script", self.schedule.to_upper_camel()); let file_path_str = file_path.display(); let mut script = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); @@ -62,7 +61,7 @@ impl Script { BufReader::new(pipe) .lines() .filter_map(|line| line.ok()) - .for_each(|f| log::info!("{f}")); + .for_each(|f| println!("{f}")); }) } else { if let Err(e) = script.wait_with_output() { @@ -73,10 +72,10 @@ impl Script { }; if let Err(e) = result { - log::error!("Failed to run {} script.", self.schedule.to_string()); - log::error!("{e}"); + println!("Failed to run {} script.", self.schedule.to_string()); + eprintln!("{e}"); } else { - log::info!("✅ {} script", self.schedule.to_upper_camel()); + println!("✅ {} script", self.schedule.to_upper_camel()); } } Err(_e) => { @@ -86,8 +85,8 @@ impl Script { } fn skip(&self) { - log::info!("🟡 Skip: {} script", &self.schedule.to_upper_camel()); - log::info!("{} does not exists.", &self.file_path().display()); + println!("🟡 Skip: {} script", &self.schedule.to_upper_camel()); + println!("{} does not exists.", &self.file_path().display()); } fn find_file(&self) -> io::Result { diff --git a/src/cli.rs b/src/cli.rs index e208e8b..989f788 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -8,10 +8,9 @@ use dip::{ app::{App, Plugin}, ecs::event::{EventReader, EventWriter}, }, - bundle::{ApplyBundle, BundlePlugin}, + bundle::{ApplyBundle, BundlePlugin, CleanBundle}, core::task::NoAsyncAction, }; -use dip_bundle::CleanBundle; use std::path::PathBuf; pub struct DipCliPlugin; @@ -22,12 +21,15 @@ impl Plugin for DipCliPlugin { .add_plugin(ActionPlugin) .add_plugin(BundleActionPlugin) .add_plugin(BundlePlugin) - .add_system(apply_bundle) + .add_system(install_bundle) .add_system(clean_bundle); } } -fn apply_bundle(mut actions: EventReader, mut apply: EventWriter) { +fn install_bundle( + mut actions: EventReader, + mut apply: EventWriter, +) { actions.iter().for_each(|a| { apply.send(ApplyBundle { // verbose: a.verbose, diff --git a/src/main.rs b/src/main.rs index c016b71..ca12c8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,25 +1,10 @@ mod cli; use crate::cli::DipCliPlugin; -use dip::bevy::{ - app::App, - log::{LogPlugin, LogSettings}, -}; +use dip::bevy::app::App; fn main() { let mut app = App::new(); - #[cfg(debug_assertions)] - app.insert_resource(LogSettings { - filter: "info,dip=debug".into(), - level: bevy::log::Level::DEBUG, - }); - - #[cfg(not(debug_assertions))] - app.insert_resource(LogSettings { - filter: "".into(), - level: bevy::log::Level::INFO, - }); - - app.add_plugin(DipCliPlugin).add_plugin(LogPlugin).run(); + app.add_plugin(DipCliPlugin).run(); } From 66cf206f6932c6cabbb91a801ee77d3c39381aa6 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Wed, 9 Nov 2022 09:33:03 +0100 Subject: [PATCH 17/22] Remove verbose flag --- plugins/bundle/src/lib.rs | 3 -- plugins/bundle/src/tool.rs | 1 - plugins/bundle/src/tool/dotfiles.rs | 9 +++--- plugins/bundle/src/tool/homebrew.rs | 49 ++++++++++------------------- plugins/bundle/src/tool/script.rs | 20 ++++-------- src/cli.rs | 4 --- src/cli/action.rs | 4 --- 7 files changed, 26 insertions(+), 64 deletions(-) diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index 7117925..c2459f2 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -28,13 +28,11 @@ impl Plugin for BundlePlugin { #[derive(Clone)] pub struct ApplyBundle { - pub verbose: bool, pub path: PathBuf, } #[derive(Clone)] pub struct CleanBundle { - pub verbose: bool, pub path: PathBuf, } @@ -48,7 +46,6 @@ fn apply_bundle( ) { events.iter().for_each(|e| { install_tools.send(InstallTools { - verbose: e.verbose, path: e.path.clone(), }); }); diff --git a/plugins/bundle/src/tool.rs b/plugins/bundle/src/tool.rs index 8814d90..fc460b4 100644 --- a/plugins/bundle/src/tool.rs +++ b/plugins/bundle/src/tool.rs @@ -26,7 +26,6 @@ impl Plugin for ToolPlugin { #[derive(Clone)] pub struct InstallTools { - pub verbose: bool, pub path: PathBuf, } diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index a954e00..5a1569a 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -90,7 +90,6 @@ fn apply_symlinks(mut events: EventReader) { } struct Dotfiles { - pub verbose: bool, pub path: PathBuf, } @@ -101,14 +100,14 @@ impl Bundle for Dotfiles { } impl From for Dotfiles { - fn from(ApplyBundle { verbose, path }: ApplyBundle) -> Self { - Self { verbose, path } + fn from(ApplyBundle { path }: ApplyBundle) -> Self { + Self { path } } } impl From for Dotfiles { - fn from(CleanBundle { verbose, path }: CleanBundle) -> Self { - Self { verbose, path } + fn from(CleanBundle { path }: CleanBundle) -> Self { + Self { path } } } diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index b3fafd8..eab80bc 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -36,7 +36,6 @@ fn apply(mut events: EventReader) { } struct Homebrew { - pub verbose: bool, pub path: PathBuf, } @@ -81,20 +80,12 @@ impl Homebrew { let mut install_brew = spawn_with_output!(NONINTERACTIVE=1 /bin/bash -C $file_path_str).unwrap(); - let result = if self.verbose { - install_brew.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|f| println!("{f}")); - }) - } else { - if let Err(e) = install_brew.wait_with_output() { - Err(e) - } else { - Ok(()) - } - }; + let result = install_brew.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| println!("{f}")); + }); if let Err(e) = result { println!("Failed to run brew install."); @@ -126,20 +117,12 @@ impl Homebrew { spawn_with_output!(brew bundle --cleanup --file $brewfile_path_str) .unwrap(); - let result = if self.verbose { - brew_bundle.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|line| println!("{:?}", line)); - }) - } else { - if let Err(e) = brew_bundle.wait_with_output() { - Err(e) - } else { - Ok(()) - } - }; + let result = brew_bundle.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|line| println!("{:?}", line)); + }); if let Err(e) = result { println!("Failed to run brew bundle."); @@ -160,13 +143,13 @@ impl Homebrew { } impl From for Homebrew { - fn from(InstallTools { verbose, path }: InstallTools) -> Self { - Self { verbose, path } + fn from(InstallTools { path }: InstallTools) -> Self { + Self { path } } } impl From for Homebrew { - fn from(ApplyBundle { verbose, path }: ApplyBundle) -> Self { - Self { verbose, path } + fn from(ApplyBundle { path }: ApplyBundle) -> Self { + Self { path } } } diff --git a/plugins/bundle/src/tool/script.rs b/plugins/bundle/src/tool/script.rs index 63bfc88..4fabe02 100644 --- a/plugins/bundle/src/tool/script.rs +++ b/plugins/bundle/src/tool/script.rs @@ -56,20 +56,12 @@ impl Script { let file_path_str = file_path.display(); let mut script = spawn_with_output!(/bin/bash -C $file_path_str).unwrap(); - let result = if self.event.verbose { - script.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|f| println!("{f}")); - }) - } else { - if let Err(e) = script.wait_with_output() { - Err(e) - } else { - Ok(()) - } - }; + let result = script.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| println!("{f}")); + }); if let Err(e) = result { println!("Failed to run {} script.", self.schedule.to_string()); diff --git a/src/cli.rs b/src/cli.rs index 989f788..201a382 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -32,8 +32,6 @@ fn install_bundle( ) { actions.iter().for_each(|a| { apply.send(ApplyBundle { - // verbose: a.verbose, - verbose: true, path: PathBuf::from(&a.path), }); }); @@ -42,8 +40,6 @@ fn install_bundle( fn clean_bundle(mut actions: EventReader, mut clean: EventWriter) { actions.iter().for_each(|a| { clean.send(CleanBundle { - // verbose: a.verbose, - verbose: true, path: PathBuf::from(&a.path), }) }); diff --git a/src/cli/action.rs b/src/cli/action.rs index ee1d9e0..2cb1922 100644 --- a/src/cli/action.rs +++ b/src/cli/action.rs @@ -45,16 +45,12 @@ pub enum BundleAction { #[derive(clap::Args, Clone, Debug)] pub struct ApplyBundleArgs { - // #[clap(short, long, required = false)] - // pub verbose: bool, #[clap(short, long, default_value_t = String::from("."))] pub path: String, } #[derive(clap::Args, Clone, Debug)] pub struct CleanBundleArgs { - // #[clap(short, long, required = false)] - // pub verbose: bool, #[clap(short, long, default_value_t = String::from("."))] pub path: String, } From 4b3e3be986bed87df9a4c5b508aa12444800baa7 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Thu, 10 Nov 2022 09:02:42 +0100 Subject: [PATCH 18/22] Cleanup Symlink methods --- plugins/bundle/src/tool/dotfiles.rs | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 5a1569a..143f824 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -34,7 +34,7 @@ struct ApplySymlinks { dir_entry: DirEntry, } -fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter) { +fn apply(mut events: EventReader, mut apply_symlinks: EventWriter) { events.iter().for_each(|e| { let dotfiles = Dotfiles::from(e.clone()); let dotfiles_path = &dotfiles.bundle_path(); @@ -46,7 +46,7 @@ fn apply(mut events: EventReader, mut apply_dotfiles: EventWriter { - println!("{}", &self.symlink_log_message(None)); - } - Err(e) => { - eprintln!("{}", &self.symlink_log_message(Some(&e.to_string()))); - } - } + let res = os::unix::fs::symlink(&self.original, &self.link); #[cfg(target_family = "windows")] - match os::windows::fs::symlink(&self.original, &self.link) { + let res = os::windows::fs::symlink(&self.original, &self.link); + + match res { Ok(_) => { - println!("{}", &self.symlink_log_message(None)); + println!("{}", &self.fmt()); } Err(e) => { - printlne!("{}", &self.symlink_log_message(Some(&e.to_string()))); + eprintln!("{}", &self.fmt_with_message(&e.to_string())); } } } } - fn symlink_log_message<'a>(&self, message: Option<&'a str>) -> String { + fn fmt(&self) -> String { + self.fmt_message(None) + } + + fn fmt_with_message<'a>(&self, message: &'a str) -> String { + self.fmt_message(Some(message)) + } + + fn fmt_message<'a>(&self, message: Option<&'a str>) -> String { let message = message.unwrap_or("".into()); format!( "----------------------------------------------------------\n\ From b310b76cca8fa1be8e8deaa28567bb504e1691fa Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Thu, 10 Nov 2022 09:40:21 +0100 Subject: [PATCH 19/22] Refactor dotfiles system with custom struct --- plugins/bundle/src/tool/dotfiles.rs | 107 ++++++++++++---------------- plugins/bundle/src/tool/homebrew.rs | 2 +- 2 files changed, 46 insertions(+), 63 deletions(-) diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index 143f824..d659ee3 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -1,10 +1,7 @@ use crate::{ApplyBundle, Bundle, BundleStage, CleanBundle}; use bevy::{ app::{App, Plugin}, - ecs::{ - event::{EventReader, EventWriter}, - schedule::ParallelSystemDescriptorCoercion, - }, + ecs::event::EventReader, }; use pathdiff::diff_paths; use std::{ @@ -20,79 +17,65 @@ pub struct DotfilesPlugin; impl Plugin for DotfilesPlugin { fn build(&self, app: &mut App) { - app.add_event::() - .add_system_to_stage(BundleStage::Apply, apply) - .add_system_to_stage(BundleStage::Apply, apply_symlinks.after(apply)) + app.add_system_to_stage(BundleStage::Apply, apply) .add_system_to_stage(BundleStage::Clean, clean); } } // Events -struct ApplySymlinks { - dotfiles_path: PathBuf, - dir_entry: DirEntry, -} - -fn apply(mut events: EventReader, mut apply_symlinks: EventWriter) { +fn apply(mut events: EventReader) { events.iter().for_each(|e| { let dotfiles = Dotfiles::from(e.clone()); - let dotfiles_path = &dotfiles.bundle_path(); - if dotfiles_path.is_dir() { + if dotfiles.bundle_path().is_dir() { println!("📌 Apply dotfiles"); - fs::read_dir(dotfiles_path) - .unwrap() - .filter(|entry| entry.is_ok()) - .filter_map(Result::ok) - .for_each(|dir_entry| { - apply_symlinks.send(ApplySymlinks { - dotfiles_path: dotfiles_path.to_path_buf(), - dir_entry, - }); - }); - } else { - println!( - "dotfiles direcotry is empty: {}", - &dotfiles_path - .clone() - .into_os_string() - .into_string() - .unwrap() - ); + dotfiles.symlinks().for_each(|sym| sym.apply()); + } else { println!("🟡 Skip: Apply dotfiles"); + println!("bundle/dotfiles directory is empty",); } }); } -fn apply_symlinks(mut events: EventReader) { - events.iter().for_each(|e| { - WalkDir::new(&e.dir_entry.path()) - .into_iter() - .filter_map(Result::ok) - .filter_map(|entry| { - let original = entry.path().to_path_buf().canonicalize().unwrap(); - let diff = diff_paths(entry.path(), &e.dotfiles_path).unwrap(); - let dotfile_bundle_name = diff.iter().next().unwrap(); - let stripped = diff.strip_prefix(dotfile_bundle_name).unwrap(); - let link = dirs::home_dir().unwrap().join(stripped); - - if entry.file_type().is_dir() { - fs::create_dir_all(link).unwrap(); - None - } else { - Some(Symlink { original, link }) - } - }) - .for_each(|symlink| symlink.apply()); - }); -} - struct Dotfiles { pub path: PathBuf, } +impl Dotfiles { + fn symlinks(&self) -> std::boxed::Box + '_> { + Box::new( + self.packages() + .flat_map(|dir| WalkDir::new(&dir.path().into_iter())) + .filter_map(Result::ok) + .filter_map(|dir| { + let original = dir.path().to_path_buf().canonicalize().unwrap(); + let diff = diff_paths(dir.path(), &self.path).unwrap(); + let dotfile_bundle_name = diff.iter().next().unwrap(); + let stripped = diff.strip_prefix(dotfile_bundle_name).unwrap(); + let link = dirs::home_dir().unwrap().join(stripped); + + if dir.file_type().is_dir() { + fs::create_dir_all(link).unwrap(); + None + } else { + Some(Symlink { original, link }) + } + }), + ) + } + + fn packages(&self) -> std::boxed::Box + '_> { + Box::new( + fs::read_dir(&self.bundle_path()) + .unwrap() + .filter(|entry| entry.is_ok()) + .filter_map(Result::ok), + ) + } +} + impl Bundle for Dotfiles { fn bundle_path(&self) -> PathBuf { self.path.join("bundle/dotfiles") @@ -125,12 +108,12 @@ struct Symlink { impl Symlink { fn apply(&self) { if self.link.is_symlink() { - println!( - "{}", - &self.fmt_with_message("🟡 Skip: File is already symlinked") - ); + // println!( + // "{}", + // &self.fmt_with_message("🟡 Skip: File is already symlinked") + // ); } else if self.link.is_file() { - println!("{}", &self.fmt_with_message("🟡 Skip: File already exists")); + // println!("{}", &self.fmt_with_message("🟡 Skip: File already exists")); } else { #[cfg(target_family = "unix")] let res = os::unix::fs::symlink(&self.original, &self.link); diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index eab80bc..8c4abaa 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -51,7 +51,7 @@ impl Homebrew { } fn brewfile_path(&self) -> PathBuf { - self.bundle_path().join("bundle/homebrew/Brewfile") + self.bundle_path().join("Brewfile") } fn install(&self) { From af8e9c415077b914c21a2ca2727507260c338b46 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Fri, 11 Nov 2022 13:14:26 +0100 Subject: [PATCH 20/22] Move condition check logic from Homebrew methods to system --- Cargo.lock | 1 + plugins/bundle/Cargo.toml | 1 + plugins/bundle/src/lib.rs | 6 +- plugins/bundle/src/tool/dotfiles.rs | 84 ++++++++------ plugins/bundle/src/tool/homebrew.rs | 163 ++++++++++++++-------------- 5 files changed, 135 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d89224..952e0de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1302,6 +1302,7 @@ dependencies = [ name = "dip_bundle" version = "0.1.0" dependencies = [ + "anyhow", "bevy", "cmd_lib", "convert_case 0.5.0", diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index 3241e5f..762289d 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -4,6 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] +anyhow.workspac = true bevy.workspace = true dip_core.workspace = true dirs.workspace = true diff --git a/plugins/bundle/src/lib.rs b/plugins/bundle/src/lib.rs index c2459f2..7c652be 100644 --- a/plugins/bundle/src/lib.rs +++ b/plugins/bundle/src/lib.rs @@ -20,7 +20,7 @@ impl Plugin for BundlePlugin { .add_event::() // .add_plugin(BundleConfigPlugin) .add_plugin(ToolPlugin) - .add_system_to_stage(BundleStage::Apply, apply_bundle); + .add_system_to_stage(BundleStage::First, apply_bundle); } } @@ -36,10 +36,6 @@ pub struct CleanBundle { pub path: PathBuf, } -pub trait Bundle { - fn bundle_path(&self) -> PathBuf; -} - fn apply_bundle( mut events: EventReader, mut install_tools: EventWriter, diff --git a/plugins/bundle/src/tool/dotfiles.rs b/plugins/bundle/src/tool/dotfiles.rs index d659ee3..44d0989 100644 --- a/plugins/bundle/src/tool/dotfiles.rs +++ b/plugins/bundle/src/tool/dotfiles.rs @@ -1,4 +1,4 @@ -use crate::{ApplyBundle, Bundle, BundleStage, CleanBundle}; +use crate::{ApplyBundle, BundleStage, CleanBundle}; use bevy::{ app::{App, Plugin}, ecs::event::EventReader, @@ -22,13 +22,13 @@ impl Plugin for DotfilesPlugin { } } -// Events +// Systems fn apply(mut events: EventReader) { events.iter().for_each(|e| { let dotfiles = Dotfiles::from(e.clone()); - if dotfiles.bundle_path().is_dir() { + if dotfiles.bundle_exists() { println!("📌 Apply dotfiles"); dotfiles.symlinks().for_each(|sym| sym.apply()); @@ -36,6 +36,25 @@ fn apply(mut events: EventReader) { println!("🟡 Skip: Apply dotfiles"); println!("bundle/dotfiles directory is empty",); } + + println!("✅ Apply dotfiles"); + }); +} + +fn clean(mut events: EventReader) { + events.iter().for_each(|e| { + let dotfiles = Dotfiles::from(e.clone()); + + if dotfiles.bundle_exists() { + println!("📌 Clean dotfiles"); + + dotfiles.symlinks().for_each(|sym| sym.clean()); + } else { + println!("🟡 Skip: Clean dotfiles"); + println!("bundle/dotfiles directory is empty",); + } + + println!("✅ Clean dotfiles"); }); } @@ -44,6 +63,14 @@ struct Dotfiles { } impl Dotfiles { + fn bundle_path(&self) -> PathBuf { + self.path.join("bundle/dotfiles") + } + + fn bundle_exists(&self) -> bool { + self.bundle_path().is_dir() + } + fn symlinks(&self) -> std::boxed::Box + '_> { Box::new( self.packages() @@ -51,7 +78,7 @@ impl Dotfiles { .filter_map(Result::ok) .filter_map(|dir| { let original = dir.path().to_path_buf().canonicalize().unwrap(); - let diff = diff_paths(dir.path(), &self.path).unwrap(); + let diff = diff_paths(dir.path(), &self.bundle_path()).unwrap(); let dotfile_bundle_name = diff.iter().next().unwrap(); let stripped = diff.strip_prefix(dotfile_bundle_name).unwrap(); let link = dirs::home_dir().unwrap().join(stripped); @@ -67,18 +94,11 @@ impl Dotfiles { } fn packages(&self) -> std::boxed::Box + '_> { - Box::new( - fs::read_dir(&self.bundle_path()) - .unwrap() - .filter(|entry| entry.is_ok()) - .filter_map(Result::ok), - ) - } -} + let dir = fs::read_dir(&self.bundle_path()) + .unwrap() + .filter_map(Result::ok); -impl Bundle for Dotfiles { - fn bundle_path(&self) -> PathBuf { - self.path.join("bundle/dotfiles") + Box::new(dir) } } @@ -94,12 +114,6 @@ impl From for Dotfiles { } } -fn clean(mut events: EventReader) { - events.iter().for_each(|_e| { - println!("hey"); - }); -} - struct Symlink { original: PathBuf, link: PathBuf, @@ -110,10 +124,10 @@ impl Symlink { if self.link.is_symlink() { // println!( // "{}", - // &self.fmt_with_message("🟡 Skip: File is already symlinked") + // &self.format("🟡 Skip: File is already symlinked") // ); } else if self.link.is_file() { - // println!("{}", &self.fmt_with_message("🟡 Skip: File already exists")); + // println!("{}", &self.format("🟡 Skip: File already exists")); } else { #[cfg(target_family = "unix")] let res = os::unix::fs::symlink(&self.original, &self.link); @@ -123,25 +137,29 @@ impl Symlink { match res { Ok(_) => { - println!("{}", &self.fmt()); + println!("{}", &self.format("Symlink created")); } Err(e) => { - eprintln!("{}", &self.fmt_with_message(&e.to_string())); + eprintln!("{}", &self.format(&e.to_string())); } } } } - fn fmt(&self) -> String { - self.fmt_message(None) - } - - fn fmt_with_message<'a>(&self, message: &'a str) -> String { - self.fmt_message(Some(message)) + fn clean(&self) { + if self.link.is_symlink() { + match fs::remove_file(&self.link) { + Ok(_) => { + println!("{}", &self.format("Symlink removed")); + } + Err(e) => { + eprintln!("{}", &self.format(&e.to_string())); + } + } + } } - fn fmt_message<'a>(&self, message: Option<&'a str>) -> String { - let message = message.unwrap_or("".into()); + fn format<'a>(&self, message: &'a str) -> String { format!( "----------------------------------------------------------\n\ {message}\n\ diff --git a/plugins/bundle/src/tool/homebrew.rs b/plugins/bundle/src/tool/homebrew.rs index 8c4abaa..42c2464 100644 --- a/plugins/bundle/src/tool/homebrew.rs +++ b/plugins/bundle/src/tool/homebrew.rs @@ -1,4 +1,4 @@ -use crate::{tool::InstallTools, ApplyBundle, Bundle, BundleStage}; +use crate::{tool::InstallTools, ApplyBundle, BundleStage}; use bevy::{ app::{App, Plugin}, ecs::event::EventReader, @@ -6,7 +6,7 @@ use bevy::{ use cmd_lib::spawn_with_output; use std::{ fs::File, - io::{BufRead, BufReader, Write}, + io::{self, BufRead, BufReader, Write}, path::{Path, PathBuf}, }; use tempfile::tempdir; @@ -26,68 +26,17 @@ impl Plugin for HomebrewPlugin { fn install(mut events: EventReader) { events.iter().for_each(|e| { - Homebrew::from(e.clone()).install(); - }); -} -fn apply(mut events: EventReader) { - events.iter().for_each(|e| { - Homebrew::from(e.clone()).apply(); - }); -} - -struct Homebrew { - pub path: PathBuf, -} - -impl Bundle for Homebrew { - fn bundle_path(&self) -> PathBuf { - self.path.join("bundle/homebrew") - } -} - -impl Homebrew { - fn homebrew_path() -> &'static str { - "/opt/homebrew/bin/brew" - } - - fn brewfile_path(&self) -> PathBuf { - self.bundle_path().join("Brewfile") - } + let brew = Homebrew::from(e.clone()); - fn install(&self) { - match &self.brewfile_path().canonicalize() { + match &brew.brewfile_path() { Ok(_brewfile_path) => { - if Path::new(Self::homebrew_path()).exists() { + if brew.installed() { println!("🟡 Skip: Install Homebrew"); - println!("brew path already exists"); + println!("brew is already installed"); } else { - println!("📌 Install Homebrew"); - - let install_sh = reqwest::blocking::get( - "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", - ) - .expect("Failed to fetch Homebrew installation script") - .text() - .expect("Failed to parse Homebrew installation script into text"); - - let dir = tempdir().unwrap(); - let file_path = dir.path().join("brew-install.sh"); - let file_path_str = file_path.clone().into_os_string(); - let mut file = File::create(file_path).unwrap(); - file.write_all(install_sh.as_bytes()) - .expect("Unable to write file"); - - let mut install_brew = - spawn_with_output!(NONINTERACTIVE=1 /bin/bash -C $file_path_str).unwrap(); - - let result = install_brew.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|f| println!("{f}")); - }); - - if let Err(e) = result { + println!("📌 Install Homebrew bundle"); + + if let Err(e) = brew.install() { println!("Failed to run brew install."); eprintln!("{e}"); } else { @@ -100,31 +49,19 @@ impl Homebrew { println!("bundle/homebrew/Brewfile does not exists.",); } } - } + }); +} - fn apply(&self) { - match &self.brewfile_path().canonicalize() { +fn apply(mut events: EventReader) { + events.iter().for_each(|e| { + let brew = Homebrew::from(e.clone()); + + match &brew.brewfile_path() { Ok(brewfile_path) => { - if Path::new(Self::homebrew_path()).exists() { + if brew.installed() { println!("📌 Apply Homebrew bundle"); - let brewfile_path_str = &brewfile_path - .clone() - .into_os_string() - .into_string() - .unwrap(); - - let mut brew_bundle = - spawn_with_output!(brew bundle --cleanup --file $brewfile_path_str) - .unwrap(); - - let result = brew_bundle.wait_with_pipe(&mut |pipe| { - BufReader::new(pipe) - .lines() - .filter_map(|line| line.ok()) - .for_each(|line| println!("{:?}", line)); - }); - - if let Err(e) = result { + + if let Err(e) = brew.apply(&brewfile_path) { println!("Failed to run brew bundle."); eprintln!("{e}"); } else { @@ -139,6 +76,68 @@ impl Homebrew { println!("bundle/homebrew/Brewfile does not exists."); } } + }); +} + +struct Homebrew { + pub path: PathBuf, +} + +impl Homebrew { + fn homebrew_path() -> &'static str { + "/opt/homebrew/bin/brew" + } + + fn bundle_path(&self) -> PathBuf { + self.path.join("bundle/homebrew") + } + + fn brewfile_path(&self) -> io::Result { + self.bundle_path().join("Brewfile").canonicalize() + } + + fn installed(&self) -> bool { + Path::new(Self::homebrew_path()).exists() + } + + fn install(&self) -> anyhow::Result<()> { + let install_sh = reqwest::blocking::get( + "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh", + )? + .text()?; + + let dir = tempdir()?; + let file_path = dir.path().join("brew-install.sh"); + let file_path_str = file_path.display().to_string(); + let mut file = File::create(file_path)?; + file.write_all(install_sh.as_bytes()) + .expect("Unable to write file"); + + let mut install_brew = spawn_with_output!(NONINTERACTIVE=1 /bin/bash -C $file_path_str)?; + + let result = install_brew.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|f| println!("{f}")); + })?; + + Ok(result) + } + + fn apply(&self, brewfile_path: &PathBuf) -> anyhow::Result<()> { + let brewfile_path_str = &brewfile_path.display(); + + let mut brew_bundle = spawn_with_output!(brew bundle --cleanup --file $brewfile_path_str)?; + + let result = brew_bundle.wait_with_pipe(&mut |pipe| { + BufReader::new(pipe) + .lines() + .filter_map(|line| line.ok()) + .for_each(|line| println!("{:?}", line)); + })?; + + Ok(result) } } From 0053e306ed6db7b0ea13952ef3a570cac1d4c9a3 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Fri, 11 Nov 2022 13:39:14 +0100 Subject: [PATCH 21/22] Move Obsidian vault to project root --- .gitignore | 14 +++++----- .../community-plugins.json | 0 .../.obsidian => .obsidian}/core-plugins.json | 0 .../.obsidian => .obsidian}/graph.json | 0 .../themes/GitHub theme/manifest.json | 0 .../themes/GitHub theme/theme.css | 0 .../themes/Minimal/manifest.json | 0 .../themes/Minimal/theme.css | 0 README.md | 1 + .../.obsidian/plugins/obsidian-git/data.json | 27 ------------------- 10 files changed, 8 insertions(+), 34 deletions(-) rename {docs/handbook/.obsidian => .obsidian}/community-plugins.json (100%) rename {docs/handbook/.obsidian => .obsidian}/core-plugins.json (100%) rename {docs/handbook/.obsidian => .obsidian}/graph.json (100%) rename {docs/handbook/.obsidian => .obsidian}/themes/GitHub theme/manifest.json (100%) rename {docs/handbook/.obsidian => .obsidian}/themes/GitHub theme/theme.css (100%) rename {docs/handbook/.obsidian => .obsidian}/themes/Minimal/manifest.json (100%) rename {docs/handbook/.obsidian => .obsidian}/themes/Minimal/theme.css (100%) delete mode 100644 docs/handbook/.obsidian/plugins/obsidian-git/data.json diff --git a/.gitignore b/.gitignore index dc5e6fd..c09504c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,11 +19,11 @@ tarpaulin-report.html # Jetbrain .idea/ -/docs/handbook/.obsidian/app.json -/docs/handbook/.obsidian/appearance.json -/docs/handbook/.obsidian/hotkeys.json -/docs/handbook/.obsidian/workspace.json -/docs/handbook/.obsidian/plugins -!/docs/handbook/.obsidian/plugins/obsidian-git/data.json -!/docs/handbook/.obsidian/plugins/obsidian-linter/data.json +.obsidian/app.json +.obsidian/appearance.json +.obsidian/hotkeys.json +.obsidian/workspace.json +.obsidian/plugins +!.obsidian/plugins/obsidian-git/data.json +!.obsidian/plugins/obsidian-linter/data.json diff --git a/docs/handbook/.obsidian/community-plugins.json b/.obsidian/community-plugins.json similarity index 100% rename from docs/handbook/.obsidian/community-plugins.json rename to .obsidian/community-plugins.json diff --git a/docs/handbook/.obsidian/core-plugins.json b/.obsidian/core-plugins.json similarity index 100% rename from docs/handbook/.obsidian/core-plugins.json rename to .obsidian/core-plugins.json diff --git a/docs/handbook/.obsidian/graph.json b/.obsidian/graph.json similarity index 100% rename from docs/handbook/.obsidian/graph.json rename to .obsidian/graph.json diff --git a/docs/handbook/.obsidian/themes/GitHub theme/manifest.json b/.obsidian/themes/GitHub theme/manifest.json similarity index 100% rename from docs/handbook/.obsidian/themes/GitHub theme/manifest.json rename to .obsidian/themes/GitHub theme/manifest.json diff --git a/docs/handbook/.obsidian/themes/GitHub theme/theme.css b/.obsidian/themes/GitHub theme/theme.css similarity index 100% rename from docs/handbook/.obsidian/themes/GitHub theme/theme.css rename to .obsidian/themes/GitHub theme/theme.css diff --git a/docs/handbook/.obsidian/themes/Minimal/manifest.json b/.obsidian/themes/Minimal/manifest.json similarity index 100% rename from docs/handbook/.obsidian/themes/Minimal/manifest.json rename to .obsidian/themes/Minimal/manifest.json diff --git a/docs/handbook/.obsidian/themes/Minimal/theme.css b/.obsidian/themes/Minimal/theme.css similarity index 100% rename from docs/handbook/.obsidian/themes/Minimal/theme.css rename to .obsidian/themes/Minimal/theme.css diff --git a/README.md b/README.md index cc4bb06..683270c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +

dip

diff --git a/docs/handbook/.obsidian/plugins/obsidian-git/data.json b/docs/handbook/.obsidian/plugins/obsidian-git/data.json deleted file mode 100644 index 9ce6101..0000000 --- a/docs/handbook/.obsidian/plugins/obsidian-git/data.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "commitMessage": "vault backup: {{date}}", - "autoCommitMessage": "vault backup: {{date}}", - "commitDateFormat": "YYYY-MM-DD HH:mm:ss", - "autoSaveInterval": 0, - "autoPushInterval": 0, - "autoPullInterval": 0, - "autoPullOnBoot": false, - "disablePush": false, - "pullBeforePush": true, - "disablePopups": false, - "listChangedFilesInMessageBody": false, - "showStatusBar": true, - "updateSubmodules": true, - "syncMethod": "merge", - "customMessageOnAutoBackup": false, - "autoBackupAfterFileChange": false, - "treeStructure": false, - "refreshSourceControl": true, - "basePath": "../..", - "differentIntervalCommitAndPush": false, - "changedFilesInStatusBar": false, - "username": "", - "showedMobileNotice": true, - "refreshSourceControlTimer": 7000, - "showBranchStatusBar": true -} From c26dca7fab29170f2fb2f8200aa81449e641c3a6 Mon Sep 17 00:00:00 2001 From: JunichiSugiura Date: Fri, 11 Nov 2022 16:18:20 +0100 Subject: [PATCH 22/22] Cleanup --- plugins/bundle/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/bundle/Cargo.toml b/plugins/bundle/Cargo.toml index 762289d..13fb180 100644 --- a/plugins/bundle/Cargo.toml +++ b/plugins/bundle/Cargo.toml @@ -4,7 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] -anyhow.workspac = true +anyhow.workspace = true bevy.workspace = true dip_core.workspace = true dirs.workspace = true