@repokit/core 3.0.6 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/Cargo.lock +96 -11
  2. package/Cargo.toml +2 -2
  3. package/installation/install.sh +39 -28
  4. package/internals/caches/crawl_cache.rs +124 -0
  5. package/internals/caches/file_cache.rs +104 -0
  6. package/internals/caches/mod.rs +5 -0
  7. package/internals/caches/repokit_version_resolver.rs +50 -0
  8. package/internals/caches/settings_cache.rs +73 -0
  9. package/internals/caches/version_cache.rs +128 -0
  10. package/internals/context/cache_scope.rs +76 -0
  11. package/internals/context/file_system.rs +66 -0
  12. package/internals/context/git_scope.rs +55 -0
  13. package/internals/context/mod.rs +5 -0
  14. package/internals/context/node_scope.rs +133 -0
  15. package/internals/context/typescript_bridge.rs +68 -0
  16. package/internals/executables/internal_executable.rs +8 -2
  17. package/internals/executables/internal_executable_definition.rs +0 -8
  18. package/internals/executor/executor.rs +13 -0
  19. package/internals/file_walker/file_walker.rs +59 -0
  20. package/internals/file_walker/mod.rs +1 -0
  21. package/internals/internal_commands/help.rs +4 -3
  22. package/internals/internal_commands/internal_registry.rs +14 -20
  23. package/internals/internal_commands/list_commands.rs +7 -16
  24. package/internals/internal_commands/list_owners.rs +3 -16
  25. package/internals/internal_commands/list_themes.rs +11 -10
  26. package/internals/internal_commands/list_version.rs +17 -18
  27. package/internals/internal_commands/locate_command.rs +11 -17
  28. package/internals/internal_commands/onboarder.rs +5 -16
  29. package/internals/internal_commands/register_command.rs +12 -20
  30. package/internals/internal_commands/search_commands.rs +29 -20
  31. package/internals/internal_commands/upgrade_repokit.rs +19 -30
  32. package/internals/internal_filesystem/file_builder.rs +4 -9
  33. package/internals/internal_filesystem/mod.rs +0 -1
  34. package/internals/logger/logger.rs +19 -6
  35. package/internals/main.rs +8 -11
  36. package/internals/repokit/mod.rs +1 -1
  37. package/internals/repokit/repokit.rs +49 -57
  38. package/internals/repokit/repokit_command.rs +69 -38
  39. package/internals/repokit/repokit_config.rs +42 -18
  40. package/internals/repokit/repokit_construct_validator.rs +1 -4
  41. package/internals/repokit/repokit_runtime.rs +43 -0
  42. package/internals/themes/theme_registry.rs +5 -7
  43. package/internals/validations/command_validations.rs +39 -62
  44. package/package.json +3 -3
  45. package/internals/configuration/configuration.rs +0 -45
  46. package/internals/configuration/mod.rs +0 -3
  47. package/internals/configuration/recovery.rs +0 -42
  48. package/internals/configuration/typescript_command.rs +0 -65
  49. package/internals/internal_filesystem/internal_filesystem.rs +0 -308
  50. package/internals/repokit/runtime_compiler.rs +0 -62
@@ -0,0 +1,128 @@
1
+ use std::{
2
+ fs::File,
3
+ io::{BufRead, BufReader},
4
+ path::PathBuf,
5
+ sync::LazyLock,
6
+ };
7
+
8
+ use futures::{executor::block_on, join};
9
+ use regex::Regex;
10
+
11
+ use crate::{
12
+ caches::{file_cache::FileCache, repokit_version_resolver::RepoKitVersionResolver},
13
+ context::file_system::FileSystem,
14
+ logger::logger::Logger,
15
+ };
16
+
17
+ #[derive(Clone)]
18
+ pub struct VersionCache {
19
+ pub runtime_version: String,
20
+ pub installed_version: String,
21
+ pub cache_directory: Option<PathBuf>,
22
+ }
23
+
24
+ static UNKNOWN: &str = "UNKNOWN";
25
+
26
+ pub static VERSION_REGEX: LazyLock<Regex> =
27
+ LazyLock::new(|| Regex::new(r#"\d*\.\d*.\d*"#).unwrap());
28
+
29
+ impl VersionCache {
30
+ pub fn new(cache_directory: &Option<PathBuf>) -> Self {
31
+ VersionCache {
32
+ runtime_version: UNKNOWN.to_string(),
33
+ installed_version: UNKNOWN.to_string(),
34
+ cache_directory: cache_directory.clone(),
35
+ }
36
+ }
37
+
38
+ pub fn refresh_installed_version(&self, files: &FileSystem) -> Option<String> {
39
+ let installed_version = block_on(self.installed_repokit_version(files));
40
+ if let Some(version) = &installed_version
41
+ && *version != self.installed_version
42
+ {
43
+ return Some(version.to_string());
44
+ }
45
+ None
46
+ }
47
+
48
+ pub async fn initialize(&mut self, files: &FileSystem) {
49
+ let (runtime_result, install_result) = join!(
50
+ self.runtime_version(),
51
+ self.installed_repokit_version(files)
52
+ );
53
+ if let Some(installed_version) = install_result {
54
+ self.installed_version = installed_version;
55
+ }
56
+ if let Some(runtime_version) = runtime_result {
57
+ self.runtime_version = runtime_version;
58
+ }
59
+ if self.installed_version != self.runtime_version
60
+ && VERSION_REGEX.is_match(&self.installed_version)
61
+ {
62
+ self.hop_to_installed_version(files);
63
+ }
64
+ }
65
+
66
+ fn hop_to_installed_version(&self, files: &FileSystem) {
67
+ Logger::info(
68
+ format!(
69
+ "Switching to version {}",
70
+ Logger::with_theme(|theme| theme.highlight(&self.installed_version))
71
+ )
72
+ .as_str(),
73
+ );
74
+ RepoKitVersionResolver::hop_to_installed_version(files);
75
+ }
76
+
77
+ async fn runtime_version(&self) -> Option<String> {
78
+ if let Some((mut lines, _)) = self.read() {
79
+ let last_known_version = self.unwrap_line(lines.nth(0), "");
80
+ if VERSION_REGEX.is_match(&last_known_version) {
81
+ return Some(last_known_version);
82
+ }
83
+ return None;
84
+ }
85
+ None
86
+ }
87
+
88
+ async fn installed_repokit_version(&self, files: &FileSystem) -> Option<String> {
89
+ let package_path = FileSystem::join_with(&files.package_directory, "package.json");
90
+ if !package_path.exists() || !package_path.is_file() {
91
+ return None;
92
+ }
93
+ let file = File::open(package_path);
94
+ if file.is_err() {
95
+ return None;
96
+ }
97
+ let lines = BufReader::new(file.unwrap()).lines();
98
+ let version_matcher = Regex::new(r#""([^"]*)""#).unwrap();
99
+ for line in lines.map_while(Result::ok) {
100
+ if line.contains("\"version\": ") {
101
+ let captures: Vec<String> = version_matcher
102
+ .captures_iter(&line)
103
+ .filter_map(|item| {
104
+ item.get(1)
105
+ .map(|match_text| match_text.as_str().to_string())
106
+ })
107
+ .collect();
108
+ if let Some(version) = captures.get(1)
109
+ && VERSION_REGEX.is_match(version)
110
+ {
111
+ return Some(version.to_string());
112
+ }
113
+ return None;
114
+ }
115
+ }
116
+ None
117
+ }
118
+ }
119
+
120
+ impl FileCache for VersionCache {
121
+ fn cache_file(&self) -> &str {
122
+ "../.version"
123
+ }
124
+
125
+ fn cache_directory(&self) -> &Option<PathBuf> {
126
+ &self.cache_directory
127
+ }
128
+ }
@@ -0,0 +1,76 @@
1
+ use futures::{executor::block_on, join};
2
+ use normalize_path::NormalizePath;
3
+ use shellexpand::tilde;
4
+ use std::{
5
+ fs::create_dir_all,
6
+ path::{Path, PathBuf},
7
+ };
8
+
9
+ use crate::{
10
+ caches::{
11
+ crawl_cache::CrawlCache, file_cache::FileCache, settings_cache::SettingsCache,
12
+ version_cache::VersionCache,
13
+ },
14
+ context::{file_system::FileSystem, git_scope::GitScope},
15
+ };
16
+
17
+ #[derive(Clone)]
18
+ pub struct CacheScope {
19
+ pub version_cache: VersionCache,
20
+ pub settings_cache: SettingsCache,
21
+ pub crawl_cache: CrawlCache,
22
+ }
23
+
24
+ static CACHE_DIRECTORY: &str = ".repokit_cache";
25
+
26
+ impl CacheScope {
27
+ pub fn new(git_scope: &GitScope, file_system: &FileSystem) -> CacheScope {
28
+ let cache_directory = CacheScope::resolve_cache_directory(&git_scope.root_commit_hash);
29
+ let mut instance = CacheScope {
30
+ crawl_cache: CrawlCache::new(&cache_directory),
31
+ version_cache: VersionCache::new(&cache_directory),
32
+ settings_cache: SettingsCache::new(&cache_directory),
33
+ };
34
+ block_on(instance.initialize_all(git_scope, file_system));
35
+ instance
36
+ }
37
+
38
+ async fn initialize_all(&mut self, git_scope: &GitScope, file_system: &FileSystem) {
39
+ self.create_cache_files().await;
40
+ join!(
41
+ self.version_cache.initialize(file_system),
42
+ self.settings_cache.initialize(),
43
+ self.crawl_cache.initialize(git_scope),
44
+ );
45
+ }
46
+
47
+ async fn create_cache_files(&self) {
48
+ join!(
49
+ self.version_cache.create_cache_file_if_not_exists(),
50
+ self.settings_cache.create_cache_file_if_not_exists(),
51
+ self.crawl_cache.create_cache_file_if_not_exists(),
52
+ );
53
+ }
54
+
55
+ pub fn home() -> Option<PathBuf> {
56
+ let expanded_path_str = tilde("~/");
57
+ let path = Path::new(expanded_path_str.as_ref()).normalize();
58
+ if path.is_absolute() && path.exists() {
59
+ return Some(path);
60
+ }
61
+ None
62
+ }
63
+
64
+ fn resolve_cache_directory(root_commit: &Option<String>) -> Option<PathBuf> {
65
+ if let Some(home) = CacheScope::home()
66
+ && let Some(commit_hash) = root_commit
67
+ {
68
+ let cache_dir = home.join(CACHE_DIRECTORY).join(commit_hash);
69
+ if !cache_dir.exists() && create_dir_all(&cache_dir).is_err() {
70
+ return None;
71
+ }
72
+ return Some(cache_dir);
73
+ }
74
+ None
75
+ }
76
+ }
@@ -0,0 +1,66 @@
1
+ use normalize_path::NormalizePath;
2
+
3
+ use std::{
4
+ fs::File,
5
+ path::{Path, PathBuf},
6
+ };
7
+
8
+ use crate::{internal_filesystem::file_builder::FileBuilder, logger::logger::Logger};
9
+
10
+ #[derive(Clone)]
11
+ pub struct FileSystem {
12
+ pub git_root: String,
13
+ pub git_root_path: PathBuf,
14
+ pub package_directory: PathBuf,
15
+ pub commands_directory: PathBuf,
16
+ pub templates_directory: PathBuf,
17
+ pub install_script_path: PathBuf,
18
+ pub install_script_location: &'static str,
19
+ }
20
+
21
+ static INSTALL_SCRIPT_LOCATION: &str = "installation/install.sh";
22
+ static INSTALLED_PACKAGE_PATH: &str = "node_modules/@repokit/core";
23
+ static TYPESCRIPT_COMMANDS: &str = "dist/commands";
24
+ static TYPESCRIPT_TEMPLATES: &str = "externals/templates";
25
+
26
+ impl FileSystem {
27
+ pub fn new(git_root: &str) -> FileSystem {
28
+ let git_root_path = Path::new(&git_root).normalize();
29
+ let package_directory = FileSystem::join_with(&git_root_path, INSTALLED_PACKAGE_PATH);
30
+ FileSystem {
31
+ git_root_path,
32
+ git_root: git_root.to_owned(),
33
+ install_script_path: FileSystem::join_with(&package_directory, INSTALL_SCRIPT_LOCATION),
34
+ commands_directory: FileSystem::join_with(&package_directory, TYPESCRIPT_COMMANDS),
35
+ templates_directory: FileSystem::join_with(&package_directory, TYPESCRIPT_TEMPLATES),
36
+ package_directory,
37
+ install_script_location: INSTALL_SCRIPT_LOCATION,
38
+ }
39
+ }
40
+
41
+ pub fn join_with(root: &PathBuf, segment: &str) -> PathBuf {
42
+ root.join(segment).normalize()
43
+ }
44
+
45
+ pub fn resolve_command(&self, command_name: &str) -> String {
46
+ FileSystem::path_buf_to_str(&FileSystem::join_with(
47
+ &self.commands_directory,
48
+ format!("{command_name}.mjs").as_str(),
49
+ ))
50
+ }
51
+
52
+ pub fn resolve_template(&self, file_name: &str) -> File {
53
+ FileBuilder::open(
54
+ FileSystem::join_with(&self.templates_directory, file_name),
55
+ |_| {
56
+ Logger::error(format!("Unable to locate internal {file_name}").as_str());
57
+ Logger::error("Please file a bug here");
58
+ Logger::log_issue_link();
59
+ },
60
+ )
61
+ }
62
+
63
+ pub fn path_buf_to_str(path: &PathBuf) -> String {
64
+ path.to_string_lossy().to_string()
65
+ }
66
+ }
@@ -0,0 +1,55 @@
1
+ use std::path::Path;
2
+
3
+ use futures::{executor::block_on, join};
4
+
5
+ use crate::{executor::executor::Executor, logger::logger::Logger};
6
+
7
+ #[derive(Clone)]
8
+ pub struct GitScope {
9
+ pub root: String,
10
+ pub root_commit_hash: Option<String>,
11
+ pub head_commit_hash: Option<String>,
12
+ }
13
+
14
+ impl GitScope {
15
+ pub fn new() -> GitScope {
16
+ let mut instance = GitScope {
17
+ root: "".to_string(),
18
+ root_commit_hash: None,
19
+ head_commit_hash: None,
20
+ };
21
+ block_on(instance.resolve());
22
+ instance
23
+ }
24
+
25
+ async fn resolve(&mut self) {
26
+ let (root, root_commit, head_commit) = join!(
27
+ GitScope::find_root(),
28
+ GitScope::get_root_commit(),
29
+ GitScope::get_head_commit()
30
+ );
31
+ self.root = root;
32
+ self.root_commit_hash = root_commit;
33
+ self.head_commit_hash = head_commit;
34
+ }
35
+
36
+ async fn find_root() -> String {
37
+ if let Some(root) = Executor::exec_with_stdout("git rev-parse --show-toplevel", |cmd| cmd)
38
+ && !root.is_empty()
39
+ && Path::new(&root).exists()
40
+ {
41
+ return root;
42
+ }
43
+ Logger::info("Please initialize your repository by running");
44
+ Logger::log_file_path("git init");
45
+ panic!();
46
+ }
47
+
48
+ async fn get_head_commit() -> Option<String> {
49
+ Executor::exec_with_stdout("git rev-parse HEAD", |cmd| cmd)
50
+ }
51
+
52
+ async fn get_root_commit() -> Option<String> {
53
+ Executor::exec_with_stdout("git rev-list --parents HEAD | tail -1", |cmd| cmd)
54
+ }
55
+ }
@@ -0,0 +1,5 @@
1
+ pub mod cache_scope;
2
+ pub mod file_system;
3
+ pub mod git_scope;
4
+ pub mod node_scope;
5
+ pub mod typescript_bridge;
@@ -0,0 +1,133 @@
1
+ use std::{collections::HashMap, path::Path};
2
+
3
+ use normalize_path::NormalizePath;
4
+
5
+ use crate::{
6
+ caches::version_cache::VERSION_REGEX, executor::executor::Executor, logger::logger::Logger,
7
+ };
8
+
9
+ #[derive(Clone)]
10
+ pub struct NodeScope {
11
+ pub install_command: String,
12
+ pub command_executor: String,
13
+ pub package_manager: String,
14
+ pub resolved_typescript_version: Option<u32>,
15
+ }
16
+
17
+ impl NodeScope {
18
+ pub fn new(git_root: &str) -> NodeScope {
19
+ let package_manager = NodeScope::get_package_manager(git_root).to_string();
20
+ NodeScope {
21
+ resolved_typescript_version: None,
22
+ command_executor: NodeScope::get_node_executor(&package_manager).to_string(),
23
+ install_command: NodeScope::get_install_command(&package_manager).to_string(),
24
+ package_manager,
25
+ }
26
+ }
27
+
28
+ pub fn type_check_file(&mut self, file_path: &str) {
29
+ let command = self.get_typecheck_command(file_path);
30
+ Executor::with_stdio(command, |cmd| cmd);
31
+ }
32
+
33
+ pub fn get_typecheck_command(&mut self, file_path: &str) -> String {
34
+ let typescript_version = self.get_typescript_version();
35
+ let ignore_config = if typescript_version >= 6 {
36
+ " --ignoreConfig".to_string()
37
+ } else {
38
+ "".to_string()
39
+ };
40
+ let tsc_command = format!(
41
+ "{} tsc {} --noEmit{}",
42
+ self.command_executor, file_path, ignore_config
43
+ );
44
+ tsc_command
45
+ }
46
+
47
+ pub fn prompt_to_fix_errors(config_path: &str) {
48
+ Logger::info(
49
+ "Please fix the above type-errors and rerun your command"
50
+ .to_string()
51
+ .as_str(),
52
+ );
53
+ Logger::log_file_path(config_path);
54
+ }
55
+
56
+ fn get_typescript_version(&mut self) -> u32 {
57
+ if let Some(resolved_version) = self.resolved_typescript_version {
58
+ return resolved_version;
59
+ }
60
+ let stdout = Executor::exec(format!("{} tsc --version", self.command_executor), |cmd| {
61
+ cmd
62
+ });
63
+ let lines: Vec<&str> = stdout
64
+ .split("\n")
65
+ .filter_map(|s| {
66
+ let trimmed = s.trim();
67
+ if trimmed.is_empty() {
68
+ return None;
69
+ }
70
+ Some(trimmed)
71
+ })
72
+ .collect();
73
+ let fallback_version = "5.0.0";
74
+ let version = lines.last().unwrap_or(&fallback_version);
75
+ let captures: Vec<String> = VERSION_REGEX
76
+ .captures_iter(version)
77
+ .filter_map(|item| {
78
+ item.get(0)
79
+ .map(|match_text| match_text.as_str().to_string())
80
+ })
81
+ .collect();
82
+ let fallback_version_str = fallback_version.to_string();
83
+ let semver = captures.first().unwrap_or(&fallback_version_str);
84
+ let major = semver
85
+ .chars()
86
+ .next()
87
+ .unwrap_or('5')
88
+ .to_digit(10)
89
+ .unwrap_or(5);
90
+ self.resolved_typescript_version = Some(major);
91
+ major
92
+ }
93
+
94
+ fn get_install_command(package_manager: &str) -> &str {
95
+ let npm_install = "npm i -D";
96
+ let manager_map = HashMap::from([
97
+ ("npm", npm_install),
98
+ ("yarn", "yarn add -D"),
99
+ ("pnpm", "pnpm i -D"),
100
+ ("bun", "bun add -D"),
101
+ ]);
102
+ manager_map.get(package_manager).unwrap_or(&npm_install)
103
+ }
104
+
105
+ fn get_node_executor(package_manager: &str) -> &str {
106
+ let npx = "npx";
107
+ let manager_map = HashMap::from([
108
+ ("npm", "npx"),
109
+ ("yarn", "yarn run -T"),
110
+ ("pnpm", "pnpm run"),
111
+ ("bun", "bunx"),
112
+ ]);
113
+ manager_map.get(package_manager).unwrap_or(&npx)
114
+ }
115
+
116
+ fn get_package_manager(root: &str) -> &str {
117
+ let manager_map = HashMap::from([
118
+ ("npm", ["package-lock.json"].to_vec()),
119
+ ("yarn", ["yarn.lock"].to_vec()),
120
+ ("pnpm", ["pnpm-lock.yaml"].to_vec()),
121
+ ("bun", ["bun.lockb", "bun.lock"].to_vec()),
122
+ ]);
123
+ for (manager, lock_files) in manager_map {
124
+ for lock_file in lock_files {
125
+ let path = Path::new(root).join(lock_file).normalize();
126
+ if path.exists() && path.is_file() {
127
+ return manager;
128
+ }
129
+ }
130
+ }
131
+ "npm"
132
+ }
133
+ }
@@ -0,0 +1,68 @@
1
+ use core::panic;
2
+ use std::{
3
+ path::{Path, PathBuf},
4
+ sync::MutexGuard,
5
+ };
6
+
7
+ use serde_json::{Value, from_str};
8
+
9
+ use crate::{
10
+ context::{file_system::FileSystem, node_scope::NodeScope},
11
+ executor::executor::Executor,
12
+ repokit::{
13
+ repokit_command::RepoKitCommand, repokit_config::RepoKitConfig,
14
+ repokit_runtime::RepoKitRuntime,
15
+ },
16
+ };
17
+
18
+ pub struct TypeScriptBridge;
19
+
20
+ impl TypeScriptBridge {
21
+ pub fn parse_configuration(files: &FileSystem, node: &mut NodeScope) -> RepoKitConfig {
22
+ let executable = files.resolve_command("parse_configuration");
23
+ let stdout = TypeScriptBridge::execute_with_node(
24
+ &files.git_root_path,
25
+ format!("{executable} --root {}", &files.git_root).as_str(),
26
+ );
27
+ if stdout.is_empty() {
28
+ RepoKitConfig::create(files);
29
+ }
30
+ let result: Result<Value, serde_json::Error> = from_str(stdout.as_str());
31
+ match result {
32
+ Ok(config) => RepoKitConfig::from_input(&files.git_root, node, config),
33
+ Err(_) => {
34
+ RepoKitConfig::on_parsing_error(&files.git_root, node, Value::Null);
35
+ panic!();
36
+ }
37
+ }
38
+ }
39
+
40
+ pub fn parse_commands(path_list: &MutexGuard<Vec<String>>) -> Vec<RepoKitCommand> {
41
+ let paths = path_list.join(",");
42
+ let stdout = RepoKitRuntime::with_runtime(|runtime| {
43
+ let executable = runtime.files.resolve_command("parse_commands");
44
+ TypeScriptBridge::execute_with_node(
45
+ &runtime.files.git_root_path,
46
+ format!(
47
+ "{executable} --paths {paths} --root {}",
48
+ runtime.files.git_root
49
+ )
50
+ .as_str(),
51
+ )
52
+ });
53
+ let result: Result<Vec<Value>, serde_json::Error> = serde_json::from_str(&stdout);
54
+ match result {
55
+ Ok(commands) => RepoKitCommand::from_input(commands),
56
+ Err(_) => {
57
+ RepoKitCommand::full_blown_crash();
58
+ panic!();
59
+ }
60
+ }
61
+ }
62
+
63
+ fn execute_with_node(root: &PathBuf, args: &str) -> String {
64
+ Executor::exec(format!("node {args}"), |cmd| {
65
+ cmd.current_dir(Path::new(root))
66
+ })
67
+ }
68
+ }
@@ -1,9 +1,15 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::executables::internal_executable_definition::InternalExecutableDefinition;
3
+ use crate::{
4
+ executables::internal_executable_definition::InternalExecutableDefinition,
5
+ internal_commands::help::Help,
6
+ };
4
7
 
5
8
  pub trait InternalExecutable {
6
9
  fn run(&self, args: Vec<String>, internals: &HashMap<String, Box<dyn InternalExecutable>>);
7
- fn help(&self);
8
10
  fn get_definition(&self) -> &InternalExecutableDefinition;
11
+
12
+ fn help(&self) {
13
+ Help::log_internal_command(self.get_definition());
14
+ }
9
15
  }
@@ -1,13 +1,5 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::repokit::repokit_config::RepoKitConfig;
4
-
5
- #[derive(Clone)]
6
- pub struct RepoKitScope {
7
- pub root: String,
8
- pub configuration: RepoKitConfig,
9
- }
10
-
11
3
  #[derive(Clone)]
12
4
  pub struct InternalExecutableDefinition {
13
5
  pub name: String,
@@ -31,6 +31,19 @@ impl Executor {
31
31
  Some(Executor::unwrap(&output.stderr))
32
32
  }
33
33
 
34
+ pub fn exec_with_stdout<T: AsRef<OsStr>>(
35
+ command: T,
36
+ composer: impl Fn(&mut Command) -> &mut Command,
37
+ ) -> Option<String> {
38
+ let output = composer(&mut Executor::spawn(command))
39
+ .output()
40
+ .expect("command failed to execute");
41
+ if output.status.success() {
42
+ return Some(Executor::unwrap(&output.stdout));
43
+ }
44
+ None
45
+ }
46
+
34
47
  pub fn with_stdio<T: AsRef<OsStr>>(
35
48
  command: T,
36
49
  composer: impl Fn(&mut Command) -> &mut Command,
@@ -0,0 +1,59 @@
1
+ use std::sync::{Arc, Mutex, MutexGuard};
2
+
3
+ use ignore::WalkBuilder;
4
+
5
+ use crate::{file_walker::walker::TSFileVisitorBuilder, repokit::repokit_runtime::RepoKitRuntime};
6
+
7
+ pub struct FileWalker {
8
+ pub command_paths: Arc<Mutex<Vec<String>>>,
9
+ }
10
+
11
+ impl FileWalker {
12
+ pub fn new() -> Self {
13
+ let instance = FileWalker {
14
+ command_paths: Arc::new(Mutex::new(Vec::new())),
15
+ };
16
+ instance.resolve();
17
+ instance
18
+ }
19
+
20
+ pub fn get(&self) -> MutexGuard<'_, Vec<String>> {
21
+ self.command_paths.lock().unwrap()
22
+ }
23
+
24
+ fn resolve(&self) {
25
+ if RepoKitRuntime::with_runtime(|runtime| runtime.caches.crawl_cache.crawl_cache_enabled())
26
+ {
27
+ self.from_cache();
28
+ } else {
29
+ self.crawl_file_system();
30
+ }
31
+ }
32
+
33
+ fn crawl_file_system(&self) {
34
+ RepoKitRuntime::with_runtime(|runtime| {
35
+ let mut visitor = TSFileVisitorBuilder::new(&runtime.git.root, &self.command_paths);
36
+ WalkBuilder::new(&runtime.files.git_root_path)
37
+ .build_parallel()
38
+ .visit(&mut visitor);
39
+ if let Some(head_commit) = &runtime.git.head_commit_hash {
40
+ let files = self.command_paths.lock().unwrap();
41
+ runtime
42
+ .caches
43
+ .crawl_cache
44
+ .cache_crawl_results([head_commit.to_owned(), files.join("\n")].join("\n"));
45
+ }
46
+ });
47
+ }
48
+
49
+ fn from_cache(&self) {
50
+ let mut paths_to_search = self.command_paths.lock().unwrap();
51
+ RepoKitRuntime::with_runtime(|runtime| {
52
+ if let Some(files_to_crawl) = &runtime.caches.crawl_cache.files_to_crawl {
53
+ for file in files_to_crawl {
54
+ paths_to_search.push(file.to_owned());
55
+ }
56
+ }
57
+ })
58
+ }
59
+ }
@@ -1 +1,2 @@
1
+ pub mod file_walker;
1
2
  pub mod walker;
@@ -10,7 +10,7 @@ use crate::{
10
10
  logger::logger::Logger,
11
11
  repokit::{
12
12
  command_definition::CommandDefinition, repokit_command::RepoKitCommand,
13
- repokit_config::RootCommand,
13
+ repokit_config::RootCommand, repokit_runtime::RepoKitRuntime,
14
14
  },
15
15
  };
16
16
 
@@ -18,12 +18,13 @@ pub struct Help;
18
18
 
19
19
  impl Help {
20
20
  pub fn list_all(
21
- root_commands: &HashMap<String, CommandDefinition>,
22
21
  internals: &HashMap<String, Box<dyn InternalExecutable>>,
23
22
  externals: &HashMap<String, RepoKitCommand>,
24
23
  ) {
25
24
  Help::log_internal_commands(internals);
26
- Help::log_root_commands(root_commands);
25
+ RepoKitRuntime::with_runtime(|runtime| {
26
+ Help::log_root_commands(&runtime.configuration.commands);
27
+ });
27
28
  Help::log_external_commands(externals);
28
29
  }
29
30