From b19517c91e7e510c1bd9fe71fd218d7e5aeb5bf0 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 24 Nov 2025 16:40:13 +0100 Subject: [PATCH 1/9] fix: Actions now receive all files including in sub folders --- crane_bricks/src/brick.rs | 13 ++++-- crane_bricks/src/file_utils.rs | 44 ++++++++++++++++--- .../insert_multiple_with_subfolder/TEST_C1 | 1 + .../insert_multiple_with_subfolder/TEST_DONT | 1 + .../insert_multiple_with_subfolder/brick.toml | 9 ++++ .../sub/TEST_C2 | 1 + crane_bricks/tests/integration_test.rs | 16 +++++++ 7 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 create mode 100644 crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT create mode 100644 crane_bricks/tests/bricks/insert_multiple_with_subfolder/brick.toml create mode 100644 crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 diff --git a/crane_bricks/src/brick.rs b/crane_bricks/src/brick.rs index 15cbad3..0b1375b 100644 --- a/crane_bricks/src/brick.rs +++ b/crane_bricks/src/brick.rs @@ -9,7 +9,7 @@ use serde::Deserialize; use crate::{ actions::{Action, ExecuteAction, insert_file::InsertFileAction}, context::ActionContext, - file_utils::{sub_dirs, sub_paths}, + file_utils::{all_file_paths, sub_dirs}, }; const BRICK_CONFIG_FILE: &str = "brick.toml"; @@ -100,15 +100,20 @@ impl Brick { Ok(()) } - /// Returns a list of all files that + /// Returns a list of all files that are in the brick dir pub fn files(&self) -> Vec { - let Ok(paths) = sub_paths(self.path()) else { + let Ok(paths) = all_file_paths(self.path()) else { return vec![]; }; + + let brick_path = format!("{}/", self.path().display()); paths .iter() .filter_map(|path| { - let name = path.file_name()?.display().to_string(); + let name = path + .display() + .to_string() + .replace(&brick_path, ""); if !path.is_file() || name == BRICK_CONFIG_FILE { return None; } diff --git a/crane_bricks/src/file_utils.rs b/crane_bricks/src/file_utils.rs index afdaf90..db8b65c 100644 --- a/crane_bricks/src/file_utils.rs +++ b/crane_bricks/src/file_utils.rs @@ -1,5 +1,5 @@ use std::{ - fs::{self, File}, + fs::{self, File, create_dir_all}, io::{self, Write}, path::{Path, PathBuf}, }; @@ -15,7 +15,27 @@ pub fn sub_dirs(dir: &Path) -> anyhow::Result> { .collect::>()) } -/// Get a vec of all files and folders in the given dir if valid +/// Returns the path to every file located in the given dir, including +/// paths in subdirectories +pub fn all_file_paths(dir: &Path) -> anyhow::Result> { + let dir = PathBuf::from(shellexpand::tilde(&dir.display().to_string()).to_string()); + if !dir.exists() || !dir.is_dir() { + return Err(anyhow!("Target does not exist or not a directory")); + } + let mut paths: Vec = Vec::new(); + if let Ok(children) = sub_paths(dir.as_path()) { + for path in children { + if path.is_dir() { + paths.append(&mut all_file_paths(path.as_path()).unwrap()); + } else if path.is_file() { + paths.push(path); + } + } + } + Ok(paths) +} + +/// Returns a vec of all files and folders in the given dir (without subdirs) if valid pub fn sub_paths(dir: &Path) -> anyhow::Result> { let dir = PathBuf::from(shellexpand::tilde(&dir.display().to_string()).to_string()); if !dir.exists() || !dir.is_dir() { @@ -32,11 +52,23 @@ pub fn file_create_new( path: &Path, content: Option, ) -> anyhow::Result<()> { - if !ctx.dry_run { - debug!("Creating new file '{:?}'", path); - let mut file = File::create_new(path)?; - file.write_all(content.unwrap_or_default().as_bytes())?; + if ctx.dry_run { + return Ok(()); + } + debug!("Creating new file '{:?}'", path); + if let Some(parent_dir) = path.parent() { + if !parent_dir.exists() { + debug!("Adding all missing parent dir(s)."); + match create_dir_all(parent_dir) { + Ok(_) => {}, + Err(_) => return Err(anyhow!("Couldn't create parent dir(s)!")), + } + } + } else { + debug!("Parent dirs exists"); } + let mut file = File::create_new(path)?; + file.write_all(content.unwrap_or_default().as_bytes())?; Ok(()) } diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 new file mode 100644 index 0000000..9d9c20c --- /dev/null +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 @@ -0,0 +1 @@ +C1 \ No newline at end of file diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT new file mode 100644 index 0000000..388e580 --- /dev/null +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT @@ -0,0 +1 @@ +This file should not exist at target location \ No newline at end of file diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/brick.toml b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/brick.toml new file mode 100644 index 0000000..44376cd --- /dev/null +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/brick.toml @@ -0,0 +1,9 @@ +name = "test" + +[[actions]] +action = "insert_file" +if_file_exists = "replace" +sources = [ + "TEST_C1", + "sub/TEST_C2" +] diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 new file mode 100644 index 0000000..0d43a85 --- /dev/null +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 @@ -0,0 +1 @@ +C2 \ No newline at end of file diff --git a/crane_bricks/tests/integration_test.rs b/crane_bricks/tests/integration_test.rs index 053466f..250a6ca 100644 --- a/crane_bricks/tests/integration_test.rs +++ b/crane_bricks/tests/integration_test.rs @@ -60,6 +60,22 @@ fn test_insert_file() { assert!(!tmpdir.path().join("brick.toml").exists()); } +#[test] +fn test_insert_files_with_sub() { + init_logger(); + + let brick = Brick::try_from(brick_dir("insert_multiple_with_subfolder")).unwrap(); + debug!("{:?}", brick); + + let ctx = ActionContext { dry_run: false }; + let tmpdir = tempfile::tempdir().unwrap(); + brick.execute(&ctx, tmpdir.path()).unwrap(); + assert!(tmpdir.path().join("TEST_C1").exists()); + assert!(tmpdir.path().join("sub/TEST_C2").exists()); + assert!(!tmpdir.path().join("TEST_DONT").exists()); + assert!(!tmpdir.path().join("brick.toml").exists()); +} + #[test] fn test_without_config() { init_logger(); From 8fb563571134537456e49ab8cce1987919e52c7d Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 24 Nov 2025 17:24:13 +0100 Subject: [PATCH 2/9] feat: Modify content can now be read from file --- crane_bricks/src/actions/modify_file.rs | 54 +++++++++++++------ .../modify_with_file_content/brick.toml | 8 +++ .../modify_with_file_content/sub/content | 1 + crane_bricks/tests/integration_test.rs | 17 ++++++ 4 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 crane_bricks/tests/bricks/modify_with_file_content/brick.toml create mode 100644 crane_bricks/tests/bricks/modify_with_file_content/sub/content diff --git a/crane_bricks/src/actions/modify_file.rs b/crane_bricks/src/actions/modify_file.rs index 36eaedb..ec750ad 100644 --- a/crane_bricks/src/actions/modify_file.rs +++ b/crane_bricks/src/actions/modify_file.rs @@ -3,6 +3,7 @@ use serde::Deserialize; use crate::{ actions::{ExecuteAction, common::Common}, + brick::BrickFile, file_utils::{file_read_content, file_replace_content}, }; @@ -62,12 +63,34 @@ enum ModifyType { } impl ModifyFileAction { - pub fn content(&self) -> String { - // TODO: Get content from somewhere else if not set - self.content.clone().unwrap_or_default() + pub fn content( + &self, + brick: &crate::brick::Brick, + ) -> anyhow::Result { + let content = self.content.clone().unwrap_or_default(); + if let Some(file) = content.strip_prefix("file:") { + let content_file: Vec = brick + .files() + .into_iter() + .filter(|f| f.name() == file) + .collect(); + if content_file.len() != 1 { + return Err(anyhow!( + "The file '{}' that was defined for taking the content from does not exis, or multiple results found. (Found {})", + file, + content_file.len() + )); + } + return Ok(content_file.first().unwrap().content().to_string()); + }; + Ok(content) } - pub fn modify_content(&self, source_text: String) -> anyhow::Result { + pub fn modify_content( + &self, + brick: &crate::brick::Brick, + source_text: String, + ) -> anyhow::Result { // TODO: Handle regex // TODO: insert for all or just one? @@ -83,6 +106,8 @@ impl ModifyFileAction { info!("Found {} match", locations.len()); } + let content = &self.content(brick)?; + let mut output = source_text.clone(); let start_length = source_text.len(); @@ -94,11 +119,11 @@ impl ModifyFileAction { ModifyType::Append => { output.insert_str( (modified_index + selected.len()).max(0), - &self.content(), + &content, ); } ModifyType::Prepend => { - output.insert_str(modified_index, &self.content()); + output.insert_str(modified_index, &content); } ModifyType::Replace => { // TODO: Something isnt right here but im so tired rn pls @@ -110,11 +135,11 @@ impl ModifyFileAction { output.len() ); if modified_index > output.len() { - output.insert_str(output.len(), &self.content()); + output.insert_str(output.len(), &content); } else { output.replace_range( modified_index..(modified_index + selected.len()), - &self.content(), + &content, ); } } @@ -142,12 +167,7 @@ impl ExecuteAction for ModifyFileAction { brick: &crate::brick::Brick, cwd: &std::path::Path, ) -> anyhow::Result<()> { - let mut files: Vec = brick - .files() - .iter() - .map(|brick_file| brick_file.name().to_string()) - .collect(); - files.extend(self.common.sources.clone()); + let files: Vec = self.common.sources.clone(); for file in files { let target_path = cwd.join(file); if !target_path.exists() { @@ -155,7 +175,11 @@ impl ExecuteAction for ModifyFileAction { } info!("Modifying file '{}'", target_path.display()); let content = file_read_content(context, &target_path)?; - file_replace_content(context, &target_path, &self.modify_content(content)?)?; + file_replace_content( + context, + &target_path, + &self.modify_content(brick, content)?, + )?; } Ok(()) } diff --git a/crane_bricks/tests/bricks/modify_with_file_content/brick.toml b/crane_bricks/tests/bricks/modify_with_file_content/brick.toml new file mode 100644 index 0000000..688e9f5 --- /dev/null +++ b/crane_bricks/tests/bricks/modify_with_file_content/brick.toml @@ -0,0 +1,8 @@ +name = "test" + +[[actions]] +sources = ["Test.toml"] +action = "modify_file" +type = "replace" +content = "file:sub/content" +selector = "[dependencies]" diff --git a/crane_bricks/tests/bricks/modify_with_file_content/sub/content b/crane_bricks/tests/bricks/modify_with_file_content/sub/content new file mode 100644 index 0000000..7644c1e --- /dev/null +++ b/crane_bricks/tests/bricks/modify_with_file_content/sub/content @@ -0,0 +1 @@ +NEW_CONTENT diff --git a/crane_bricks/tests/integration_test.rs b/crane_bricks/tests/integration_test.rs index 250a6ca..9d585ba 100644 --- a/crane_bricks/tests/integration_test.rs +++ b/crane_bricks/tests/integration_test.rs @@ -140,6 +140,23 @@ fn test_modify_replace() { assert!(res_content.contains("[dev-dependencies]")); } +#[test] +fn test_modify_with_file_content() { + init_logger(); + + let brick = Brick::try_from(brick_dir("modify_with_file_content")).unwrap(); + + let tmpdir = tempfile::tempdir().unwrap(); + add_test_data(tmpdir.path(), "Test.toml"); + let ctx = ActionContext { dry_run: false }; + + brick.execute(&ctx, tmpdir.path()).unwrap(); + let res_content = file_content(&tmpdir.path().join("Test.toml")); + debug!("{}", res_content); + assert!(!res_content.contains("[dependencies]")); + assert!(res_content.contains("NEW_CONTENT\n")); +} + #[test] fn test_command() { init_logger(); From 826b3ef548356cbfaa97a66c42dd3f7452a940b7 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 11:33:07 +0100 Subject: [PATCH 3/9] feat: Add codeowners file --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c96a853 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @timothebot \ No newline at end of file From d9eb013d2ca0fe62eef40d2f642b78a4ed0b34ea Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 11:33:56 +0100 Subject: [PATCH 4/9] docs: Remove file command docs and fix spelling mistake --- book/src/configuration/brick_config.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/configuration/brick_config.md b/book/src/configuration/brick_config.md index e4c8d1d..4cb706f 100644 --- a/book/src/configuration/brick_config.md +++ b/book/src/configuration/brick_config.md @@ -84,8 +84,8 @@ Allows you to run a command or a script file. [[actions]] action = "run_command" -command = "echo 'hi'" # command or a script file (prefix with file:) +command = "echo 'hi'" ``` This is by far the most simple yet powerful action. -If you need more complex behaviour, you can add a custom script that does what you need. +If you need more complex behavior, you can add a custom script that does what you need. From a46ac689534847f733ae3ddea7eecbe6dc7bcec7 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 11:34:13 +0100 Subject: [PATCH 5/9] docs: Add todo to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a0a0d9e..a5da0dc 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,4 @@ executes or lines getting replaced in a target file. - [ ] Path support - [ ] Improve readme - [ ] Variables support + - [ ] Input variables (ask for variable or command or something) From 715de161847c5aceccd322985fca1055bd790c7f Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 12:29:05 +0100 Subject: [PATCH 6/9] feat: Add regex selector for modify content actions --- Cargo.lock | 9 +-- crane_bricks/Cargo.toml | 1 + crane_bricks/src/actions/modify_file.rs | 61 ++++++++++++++----- .../bricks/modify_append_regex/brick.toml | 8 +++ .../bricks/modify_prepend_regex/brick.toml | 8 +++ .../bricks/modify_replace_regex/brick.toml | 8 +++ crane_bricks/tests/integration_test.rs | 51 ++++++++++++++++ 7 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 crane_bricks/tests/bricks/modify_append_regex/brick.toml create mode 100644 crane_bricks/tests/bricks/modify_prepend_regex/brick.toml create mode 100644 crane_bricks/tests/bricks/modify_replace_regex/brick.toml diff --git a/Cargo.lock b/Cargo.lock index 38d711c..19c2e0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,7 @@ dependencies = [ "anyhow", "env_logger", "log", + "regex", "serde", "shellexpand", "tempfile", @@ -440,9 +441,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -452,9 +453,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", diff --git a/crane_bricks/Cargo.toml b/crane_bricks/Cargo.toml index 468441d..b374a85 100644 --- a/crane_bricks/Cargo.toml +++ b/crane_bricks/Cargo.toml @@ -12,6 +12,7 @@ toml = "0.9.6" anyhow = "1.0.99" log = "0.4.28" shellexpand = "3.1.1" +regex = "1.12.2" [dev-dependencies] tempfile = "3" diff --git a/crane_bricks/src/actions/modify_file.rs b/crane_bricks/src/actions/modify_file.rs index ec750ad..ee6d651 100644 --- a/crane_bricks/src/actions/modify_file.rs +++ b/crane_bricks/src/actions/modify_file.rs @@ -1,4 +1,5 @@ use anyhow::{Ok, anyhow}; +use regex::Regex; use serde::Deserialize; use crate::{ @@ -62,11 +63,37 @@ enum ModifyType { Replace, } +fn modify_content_using_regex( + source_text: String, + selector: &str, + content: String, + modify_type: &ModifyType, +) -> anyhow::Result { + let re = Regex::new(selector)?; + return match modify_type { + ModifyType::Append => Ok(re + .replace_all( + &source_text, + format!("$0{}", content) + ) + .to_string()), + ModifyType::Prepend => Ok(re + .replace_all( + &source_text, + format!("{}$0", content) + ) + .to_string()), + ModifyType::Replace => Ok(re + .replace_all( + &source_text, + content + ) + .to_string()), + }; +} + impl ModifyFileAction { - pub fn content( - &self, - brick: &crate::brick::Brick, - ) -> anyhow::Result { + pub fn content(&self, brick: &crate::brick::Brick) -> anyhow::Result { let content = self.content.clone().unwrap_or_default(); if let Some(file) = content.strip_prefix("file:") { let content_file: Vec = brick @@ -94,6 +121,18 @@ impl ModifyFileAction { // TODO: Handle regex // TODO: insert for all or just one? + let content = &self.content(brick)?; + + if self.selector.starts_with("regex:") { + info!("Modifying content with regex selector."); + return modify_content_using_regex( + source_text, + self.selector.strip_prefix("regex:").unwrap_or_default(), + content.to_string(), + &self.r#type, + ); + } + let locations: Vec<(usize, &str)> = source_text.match_indices(&self.selector).collect(); @@ -106,8 +145,6 @@ impl ModifyFileAction { info!("Found {} match", locations.len()); } - let content = &self.content(brick)?; - let mut output = source_text.clone(); let start_length = source_text.len(); @@ -117,22 +154,16 @@ impl ModifyFileAction { let modified_index = index + output.len().abs_diff(start_length); match &self.r#type { ModifyType::Append => { - output.insert_str( - (modified_index + selected.len()).max(0), - &content, - ); + output.insert_str((modified_index + selected.len()).max(0), &content); } ModifyType::Prepend => { output.insert_str(modified_index, &content); } ModifyType::Replace => { - // TODO: Something isnt right here but im so tired rn pls - // future tiimo fix this debug!( - "replacing from {} to {} (total chars {})", + "Replacing from {} to {}", modified_index, - (modified_index + selected.len()).max(0), - output.len() + (modified_index + selected.len()).max(0) ); if modified_index > output.len() { output.insert_str(output.len(), &content); diff --git a/crane_bricks/tests/bricks/modify_append_regex/brick.toml b/crane_bricks/tests/bricks/modify_append_regex/brick.toml new file mode 100644 index 0000000..acdc1dc --- /dev/null +++ b/crane_bricks/tests/bricks/modify_append_regex/brick.toml @@ -0,0 +1,8 @@ +name = "test" + +[[actions]] +sources = ["Test.toml"] +action = "modify_file" +type = "append" +content = "\nserde = \"1\"" +selector = "regex:\\[[a-z]+\\]" diff --git a/crane_bricks/tests/bricks/modify_prepend_regex/brick.toml b/crane_bricks/tests/bricks/modify_prepend_regex/brick.toml new file mode 100644 index 0000000..86be927 --- /dev/null +++ b/crane_bricks/tests/bricks/modify_prepend_regex/brick.toml @@ -0,0 +1,8 @@ +name = "test" + +[[actions]] +sources = ["Test.toml"] +action = "modify_file" +type = "prepend" +content = "# This is group $group\n" +selector = "regex:\\[(?[a-z]+)\\]" diff --git a/crane_bricks/tests/bricks/modify_replace_regex/brick.toml b/crane_bricks/tests/bricks/modify_replace_regex/brick.toml new file mode 100644 index 0000000..223eb83 --- /dev/null +++ b/crane_bricks/tests/bricks/modify_replace_regex/brick.toml @@ -0,0 +1,8 @@ +name = "test" + +[[actions]] +sources = ["Test.toml"] +action = "modify_file" +type = "replace" +content = "[dev-$group]" +selector = "regex:\\[(?d[a-z]+)\\]" diff --git a/crane_bricks/tests/integration_test.rs b/crane_bricks/tests/integration_test.rs index 9d585ba..3d23dc6 100644 --- a/crane_bricks/tests/integration_test.rs +++ b/crane_bricks/tests/integration_test.rs @@ -107,6 +107,22 @@ fn test_modify_append() { assert!(res_content.contains("[dependencies]\nserde = \"1\"\n")) } +#[test] +fn test_modify_append_with_regex() { + init_logger(); + + let brick = Brick::try_from(brick_dir("modify_append_regex")).unwrap(); + + let tmpdir = tempfile::tempdir().unwrap(); + add_test_data(tmpdir.path(), "Test.toml"); + let ctx = ActionContext { dry_run: false }; + + brick.execute(&ctx, tmpdir.path()).unwrap(); + let res_content = file_content(&tmpdir.path().join("Test.toml")); + debug!("{}", res_content); + assert!(res_content.contains("[dependencies]\nserde = \"1\"\n")) +} + #[test] fn test_modify_prepend() { init_logger(); @@ -123,6 +139,24 @@ fn test_modify_prepend() { assert!(res_content.contains("serde = \"1\"\n[dependencies]")) } + +#[test] +fn test_modify_prepend_regex() { + init_logger(); + + let brick = Brick::try_from(brick_dir("modify_prepend_regex")).unwrap(); + + let tmpdir = tempfile::tempdir().unwrap(); + add_test_data(tmpdir.path(), "Test.toml"); + let ctx = ActionContext { dry_run: false }; + + brick.execute(&ctx, tmpdir.path()).unwrap(); + let res_content = file_content(&tmpdir.path().join("Test.toml")); + debug!("{}", res_content); + assert!(res_content.contains("# This is group dependencies\n[dependencies]")); + assert!(res_content.contains("# This is group package\n[package]")); +} + #[test] fn test_modify_replace() { init_logger(); @@ -140,6 +174,23 @@ fn test_modify_replace() { assert!(res_content.contains("[dev-dependencies]")); } +#[test] +fn test_modify_replace_regex() { + init_logger(); + + let brick = Brick::try_from(brick_dir("modify_replace")).unwrap(); + + let tmpdir = tempfile::tempdir().unwrap(); + add_test_data(tmpdir.path(), "Test.toml"); + let ctx = ActionContext { dry_run: false }; + + brick.execute(&ctx, tmpdir.path()).unwrap(); + let res_content = file_content(&tmpdir.path().join("Test.toml")); + debug!("{}", res_content); + assert!(!res_content.contains("[dependencies]")); + assert!(res_content.contains("[dev-dependencies]")); +} + #[test] fn test_modify_with_file_content() { init_logger(); From 119d858dc2f05dfd371cdf88beb0c19466c80d06 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 12:51:00 +0100 Subject: [PATCH 7/9] style: Run cargo fmt and cargo clippy --- crane_bricks/src/actions/modify_file.rs | 29 ++++++++----------------- crane_bricks/src/brick.rs | 5 +---- crane_bricks/src/file_utils.rs | 2 +- crane_bricks/tests/integration_test.rs | 1 - 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/crane_bricks/src/actions/modify_file.rs b/crane_bricks/src/actions/modify_file.rs index ee6d651..5a313f0 100644 --- a/crane_bricks/src/actions/modify_file.rs +++ b/crane_bricks/src/actions/modify_file.rs @@ -70,26 +70,15 @@ fn modify_content_using_regex( modify_type: &ModifyType, ) -> anyhow::Result { let re = Regex::new(selector)?; - return match modify_type { + match modify_type { ModifyType::Append => Ok(re - .replace_all( - &source_text, - format!("$0{}", content) - ) + .replace_all(&source_text, format!("$0{}", content)) .to_string()), ModifyType::Prepend => Ok(re - .replace_all( - &source_text, - format!("{}$0", content) - ) + .replace_all(&source_text, format!("{}$0", content)) .to_string()), - ModifyType::Replace => Ok(re - .replace_all( - &source_text, - content - ) - .to_string()), - }; + ModifyType::Replace => Ok(re.replace_all(&source_text, content).to_string()), + } } impl ModifyFileAction { @@ -154,10 +143,10 @@ impl ModifyFileAction { let modified_index = index + output.len().abs_diff(start_length); match &self.r#type { ModifyType::Append => { - output.insert_str((modified_index + selected.len()).max(0), &content); + output.insert_str((modified_index + selected.len()).max(0), content); } ModifyType::Prepend => { - output.insert_str(modified_index, &content); + output.insert_str(modified_index, content); } ModifyType::Replace => { debug!( @@ -166,11 +155,11 @@ impl ModifyFileAction { (modified_index + selected.len()).max(0) ); if modified_index > output.len() { - output.insert_str(output.len(), &content); + output.insert_str(output.len(), content); } else { output.replace_range( modified_index..(modified_index + selected.len()), - &content, + content, ); } } diff --git a/crane_bricks/src/brick.rs b/crane_bricks/src/brick.rs index 0b1375b..3376f5b 100644 --- a/crane_bricks/src/brick.rs +++ b/crane_bricks/src/brick.rs @@ -110,10 +110,7 @@ impl Brick { paths .iter() .filter_map(|path| { - let name = path - .display() - .to_string() - .replace(&brick_path, ""); + let name = path.display().to_string().replace(&brick_path, ""); if !path.is_file() || name == BRICK_CONFIG_FILE { return None; } diff --git a/crane_bricks/src/file_utils.rs b/crane_bricks/src/file_utils.rs index db8b65c..226c4bf 100644 --- a/crane_bricks/src/file_utils.rs +++ b/crane_bricks/src/file_utils.rs @@ -60,7 +60,7 @@ pub fn file_create_new( if !parent_dir.exists() { debug!("Adding all missing parent dir(s)."); match create_dir_all(parent_dir) { - Ok(_) => {}, + Ok(_) => {} Err(_) => return Err(anyhow!("Couldn't create parent dir(s)!")), } } diff --git a/crane_bricks/tests/integration_test.rs b/crane_bricks/tests/integration_test.rs index 3d23dc6..b363584 100644 --- a/crane_bricks/tests/integration_test.rs +++ b/crane_bricks/tests/integration_test.rs @@ -139,7 +139,6 @@ fn test_modify_prepend() { assert!(res_content.contains("serde = \"1\"\n[dependencies]")) } - #[test] fn test_modify_prepend_regex() { init_logger(); From 60cb3040f08dade8df337a9b64945eaa8ffba202 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 13:16:29 +0100 Subject: [PATCH 8/9] style: Add newline to EOF where missing --- .github/CODEOWNERS | 2 +- .github/workflows/rust-ci.yml | 2 +- book/src/intro.md | 4 ++-- .../tests/bricks/insert_multiple_with_subfolder/TEST_C1 | 2 +- .../tests/bricks/insert_multiple_with_subfolder/TEST_DONT | 2 +- .../tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 | 2 +- crane_bricks/tests/bricks/insert_no_config/TEST_B | 2 +- crane_bricks/tests/bricks/insert_with_config/TEST_A | 2 +- example/bricks/serde/brick.toml | 2 +- example/foo/other_bricks/smile/smile.txt | 2 +- rustfmt.toml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c96a853..44d0d5d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @timothebot \ No newline at end of file +* @timothebot diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 5713c5e..49a4ef6 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -59,4 +59,4 @@ jobs: - name: doesn't detect powershell if: ${{ matrix.os != 'macos-14' }} shell: bash - run: cargo test --release -- --ignored is_powershell_false \ No newline at end of file + run: cargo test --release -- --ignored is_powershell_false diff --git a/book/src/intro.md b/book/src/intro.md index 60d1efa..86c4c12 100644 --- a/book/src/intro.md +++ b/book/src/intro.md @@ -14,7 +14,7 @@ Instead of having to look up and copy your desired license from the web, you can You can create multiple bricks and combine them behind an alias. -This way, you can easily bootstrap new projects! +This way, you can easily bootstrap new projects! ```shell $ cargo new my_project && cd my_project @@ -26,4 +26,4 @@ $ crane add rust • rustfmt • rustauthor # ... -``` \ No newline at end of file +``` diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 index 9d9c20c..e2cf5e7 100644 --- a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_C1 @@ -1 +1 @@ -C1 \ No newline at end of file +C1 diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT index 388e580..988f732 100644 --- a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/TEST_DONT @@ -1 +1 @@ -This file should not exist at target location \ No newline at end of file +This file should not exist at target location diff --git a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 index 0d43a85..c4b2d41 100644 --- a/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 +++ b/crane_bricks/tests/bricks/insert_multiple_with_subfolder/sub/TEST_C2 @@ -1 +1 @@ -C2 \ No newline at end of file +C2 diff --git a/crane_bricks/tests/bricks/insert_no_config/TEST_B b/crane_bricks/tests/bricks/insert_no_config/TEST_B index 5e1c309..557db03 100644 --- a/crane_bricks/tests/bricks/insert_no_config/TEST_B +++ b/crane_bricks/tests/bricks/insert_no_config/TEST_B @@ -1 +1 @@ -Hello World \ No newline at end of file +Hello World diff --git a/crane_bricks/tests/bricks/insert_with_config/TEST_A b/crane_bricks/tests/bricks/insert_with_config/TEST_A index 3b12464..2a02d41 100644 --- a/crane_bricks/tests/bricks/insert_with_config/TEST_A +++ b/crane_bricks/tests/bricks/insert_with_config/TEST_A @@ -1 +1 @@ -TEST \ No newline at end of file +TEST diff --git a/example/bricks/serde/brick.toml b/example/bricks/serde/brick.toml index 768563e..a1ee91e 100644 --- a/example/bricks/serde/brick.toml +++ b/example/bricks/serde/brick.toml @@ -17,4 +17,4 @@ type = "replace" # Specify which files this action applies to sources = [ "LICENSE" -] \ No newline at end of file +] diff --git a/example/foo/other_bricks/smile/smile.txt b/example/foo/other_bricks/smile/smile.txt index 93c710d..337c56e 100644 --- a/example/foo/other_bricks/smile/smile.txt +++ b/example/foo/other_bricks/smile/smile.txt @@ -1 +1 @@ -:D \ No newline at end of file +:D diff --git a/rustfmt.toml b/rustfmt.toml index 8518ab0..26ba63e 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1 @@ -max_width = 90 \ No newline at end of file +max_width = 90 From 3ef2681d3f717629ede22ba46ca3945b10991fd7 Mon Sep 17 00:00:00 2001 From: Timo Borer Date: Mon, 22 Dec 2025 13:18:13 +0100 Subject: [PATCH 9/9] style: Remove unused import --- crane/src/cmd/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crane/src/cmd/commands.rs b/crane/src/cmd/commands.rs index b00174c..26902b8 100644 --- a/crane/src/cmd/commands.rs +++ b/crane/src/cmd/commands.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use clap::{Parser, Subcommand, ValueHint, command}; +use clap::{Parser, Subcommand, ValueHint}; use clap_verbosity::{InfoLevel, Verbosity}; #[derive(Debug, Parser)]