@repokit/core 3.0.5 → 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 +37 -25
  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
@@ -6,24 +6,21 @@ use crate::{
6
6
  executables::{
7
7
  internal_executable::InternalExecutable,
8
8
  internal_executable_definition::{
9
- InternalExecutableDefinition, InternalExecutableDefinitionInput, RepoKitScope,
9
+ InternalExecutableDefinition, InternalExecutableDefinitionInput,
10
10
  },
11
11
  },
12
12
  executor::executor::Executor,
13
- internal_commands::help::Help,
14
- internal_filesystem::internal_filesystem::InternalFileSystem,
15
13
  logger::logger::Logger,
14
+ repokit::repokit_runtime::RepoKitRuntime,
16
15
  };
17
16
 
18
17
  pub struct UpgradeRepoKit {
19
- pub scope: RepoKitScope,
20
18
  pub definition: InternalExecutableDefinition,
21
19
  }
22
20
 
23
21
  impl UpgradeRepoKit {
24
- pub fn new(scope: &RepoKitScope) -> UpgradeRepoKit {
22
+ pub fn new() -> UpgradeRepoKit {
25
23
  UpgradeRepoKit {
26
- scope: scope.clone(),
27
24
  definition: InternalExecutableDefinition::define(InternalExecutableDefinitionInput {
28
25
  name: "upgrade",
29
26
  description: "Upgrades your installation of repokit to the latest stable version",
@@ -32,50 +29,42 @@ impl UpgradeRepoKit {
32
29
  }
33
30
  }
34
31
 
35
- pub fn static_execute(root: &str) {
32
+ pub fn static_execute(&self) {
36
33
  Logger::info("Upgrading installation");
37
34
  let handle = SpinnerBuilder::new()
38
35
  .spinner(&BOUNCING_BALL)
39
36
  .text(" Installing")
40
37
  .start();
41
- let command_prefix = InternalFileSystem::get_install_command(root);
42
- Executor::exec(
43
- format!("{} @repokit/core@latest", command_prefix).as_str(),
44
- |cmd| cmd.current_dir(root),
45
- );
38
+ RepoKitRuntime::with_runtime(|runtime| {
39
+ Executor::exec(
40
+ format!("{} @repokit/core@latest", runtime.node.install_command).as_str(),
41
+ |cmd| cmd.current_dir(&runtime.git.root),
42
+ )
43
+ });
46
44
  handle.done();
45
+ Logger::info("Upgrade Complete!");
47
46
  }
48
47
  }
49
48
 
50
49
  impl InternalExecutable for UpgradeRepoKit {
51
50
  fn run(&self, _: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
52
- let internal_fs = InternalFileSystem::new(&self.scope.root);
53
- let fallback = "unknown";
54
- let runtime_version = internal_fs
55
- .installed_repokit_version()
56
- .unwrap_or(fallback.to_string());
57
- UpgradeRepoKit::static_execute(&self.scope.root);
58
- let installed_version = internal_fs
59
- .installed_repokit_version()
60
- .unwrap_or(fallback.to_string());
61
- if runtime_version != installed_version {
62
- Logger::info("Upgrade Complete!");
51
+ self.static_execute();
52
+ if let Some(new_version) = RepoKitRuntime::with_runtime(|runtime| {
53
+ runtime
54
+ .caches
55
+ .version_cache
56
+ .refresh_installed_version(&runtime.files)
57
+ }) {
63
58
  Logger::info(
64
59
  format!(
65
60
  "The currently installed version is {}",
66
- Logger::with_theme(|theme| theme.highlight(&installed_version))
61
+ Logger::with_theme(|theme| theme.highlight(&new_version))
67
62
  )
68
63
  .as_str(),
69
64
  );
70
- } else {
71
- Logger::info("The latest version is already installed");
72
65
  }
73
66
  }
74
67
 
75
- fn help(&self) {
76
- Help::log_internal_command(&self.definition);
77
- }
78
-
79
68
  fn get_definition(&self) -> &InternalExecutableDefinition {
80
69
  &self.definition
81
70
  }
@@ -1,22 +1,19 @@
1
- use crate::post_processing::post_processor::PostProcessor;
2
1
  use std::{
3
2
  fs::{File, create_dir_all},
4
3
  io::{Error, copy},
5
4
  path::Path,
6
- process::exit,
7
5
  };
8
6
 
9
7
  pub struct FileBuilder;
10
8
 
11
9
  impl FileBuilder {
12
- pub fn open(source: &str, on_error: impl Fn(Error)) -> File {
10
+ pub fn open<P: AsRef<Path>>(source: P, on_error: impl Fn(Error)) -> File {
13
11
  let source = File::open(source);
14
12
  match source {
15
13
  Ok(file) => file,
16
14
  Err(error) => {
17
15
  on_error(error);
18
- PostProcessor::get().flush();
19
- exit(0);
16
+ panic!();
20
17
  }
21
18
  }
22
19
  }
@@ -27,8 +24,7 @@ impl FileBuilder {
27
24
  Ok(file) => file,
28
25
  Err(error) => {
29
26
  on_error(error);
30
- PostProcessor::get().flush();
31
- exit(0);
27
+ panic!();
32
28
  }
33
29
  }
34
30
  }
@@ -53,8 +49,7 @@ impl FileBuilder {
53
49
  Ok(result) => result,
54
50
  Err(error) => {
55
51
  on_error(error);
56
- PostProcessor::get().flush();
57
- exit(0);
52
+ panic!();
58
53
  }
59
54
  }
60
55
  }
@@ -1,2 +1 @@
1
1
  pub mod file_builder;
2
- pub mod internal_filesystem;
@@ -1,10 +1,11 @@
1
+ use core::panic;
1
2
  use std::sync::LazyLock;
2
3
  use std::sync::Mutex;
3
4
  use std::sync::MutexGuard;
4
5
 
5
6
  use colored::{ColoredString, Colorize};
6
7
 
7
- use crate::post_processing::post_processor::PostProcessor;
8
+ use crate::repokit::repokit_runtime::RepoKitRuntime;
8
9
  use crate::themes::theme::Theme;
9
10
  use crate::themes::theme_registry::ThemeRegistry;
10
11
 
@@ -16,8 +17,16 @@ static THEMES: LazyLock<Mutex<ThemeRegistry>> = LazyLock::new(|| Mutex::new(Them
16
17
  pub struct Logger;
17
18
 
18
19
  impl Logger {
19
- pub fn set_name(value: &str) {
20
- *REGISTERED_NAME.lock().unwrap() = value.to_string();
20
+ pub fn initialize() {
21
+ RepoKitRuntime::with_runtime(|runtime| {
22
+ Logger::set_name(&runtime.configuration.project);
23
+ for theme in &runtime.configuration.themes {
24
+ Logger::with_registry(|mut registry| registry.register_user_theme(theme))
25
+ }
26
+ Logger::with_registry(|mut registry| {
27
+ registry.set_theme(&runtime.caches.settings_cache.theme_preference)
28
+ });
29
+ });
21
30
  }
22
31
 
23
32
  pub fn info(message: &str) {
@@ -30,12 +39,12 @@ impl Logger {
30
39
 
31
40
  pub fn exit_with_info(message: &str) {
32
41
  Logger::info(message);
33
- PostProcessor::get().flush();
42
+ panic!();
34
43
  }
35
44
 
36
45
  pub fn exit_with_error(message: &str) {
37
46
  Logger::error(message);
38
- PostProcessor::get().flush();
47
+ panic!();
39
48
  }
40
49
 
41
50
  pub fn list(items: &[&str], indentation: Option<i32>) {
@@ -121,7 +130,7 @@ impl Logger {
121
130
  Logger::info(format!("I was unable to {operation} in your repository").as_str());
122
131
  Logger::error("Please verify the permissions on your working directory or file a bug here");
123
132
  Logger::log_issue_link();
124
- PostProcessor::get().flush();
133
+ panic!();
125
134
  }
126
135
 
127
136
  fn info_prefix() -> String {
@@ -133,4 +142,8 @@ impl Logger {
133
142
  format!("{}: ", theme.error_prefix(&REGISTERED_NAME.lock().unwrap()))
134
143
  })
135
144
  }
145
+
146
+ fn set_name(value: &str) {
147
+ *REGISTERED_NAME.lock().unwrap() = value.to_string();
148
+ }
136
149
  }
package/internals/main.rs CHANGED
@@ -1,11 +1,10 @@
1
- use crate::{
2
- configuration::typescript_command::TypescriptCommand,
3
- internal_filesystem::internal_filesystem::InternalFileSystem,
4
- repokit::{repokit::RepoKit, runtime_compiler::RuntimeCompiler},
5
- };
1
+ use std::panic;
2
+
3
+ use crate::{post_processing::post_processor::PostProcessor, repokit::repokit::RepoKit};
6
4
 
7
5
  mod argv;
8
- mod configuration;
6
+ mod caches;
7
+ mod context;
9
8
  mod executables;
10
9
  mod executor;
11
10
  mod file_walker;
@@ -18,9 +17,7 @@ mod themes;
18
17
  mod validations;
19
18
 
20
19
  fn main() {
21
- let root = InternalFileSystem::find_root();
22
- RuntimeCompiler::hop_to_runtime_version(&root);
23
- let config = TypescriptCommand::new(&root).parse_configuration();
24
- let kit = RepoKit::new(&root, config);
25
- kit.invoke();
20
+ panic::set_hook(Box::new(|_| PostProcessor::get().flush()));
21
+ RepoKit::new().invoke();
22
+ PostProcessor::get().flush();
26
23
  }
@@ -3,4 +3,4 @@ pub mod repokit;
3
3
  pub mod repokit_command;
4
4
  pub mod repokit_config;
5
5
  pub mod repokit_construct_validator;
6
- pub mod runtime_compiler;
6
+ pub mod repokit_runtime;
@@ -1,77 +1,52 @@
1
1
  use std::{collections::HashMap, env::args, path::Path};
2
2
 
3
3
  use crate::{
4
- executables::{
5
- internal_executable::InternalExecutable, internal_executable_definition::RepoKitScope,
6
- },
4
+ executables::internal_executable::InternalExecutable,
7
5
  executor::executor::Executor,
8
6
  internal_commands::help::Help,
9
- internal_filesystem::internal_filesystem::InternalFileSystem,
10
7
  logger::logger::Logger,
11
- post_processing::post_processor::PostProcessor,
12
- repokit::{repokit_command::RepoKitCommand, repokit_config::RepoKitConfig},
8
+ repokit::{repokit_command::RepoKitCommand, repokit_runtime::RepoKitRuntime},
13
9
  validations::command_validations::CommandValidations,
14
10
  };
15
11
 
16
- pub struct RepoKit {
17
- pub scope: RepoKitScope,
18
- }
12
+ pub struct RepoKit {}
19
13
 
20
14
  impl RepoKit {
21
- pub fn new(root: &str, configuration: RepoKitConfig) -> RepoKit {
22
- Logger::set_name(&configuration.project);
23
- for theme in &configuration.themes {
24
- Logger::with_registry(|mut registry| registry.register_user_theme(theme))
25
- }
26
- let theme = InternalFileSystem::new(root).read_theme_preference();
27
- Logger::with_registry(|mut registry| registry.set_theme(root, &theme));
28
- RepoKit {
29
- scope: RepoKitScope {
30
- configuration,
31
- root: root.to_string(),
32
- },
33
- }
15
+ pub fn new() -> RepoKit {
16
+ Logger::initialize();
17
+ RepoKit {}
34
18
  }
35
19
 
36
20
  pub fn invoke(&self) {
37
21
  let (command, args) = self.parse();
38
- let validator = CommandValidations::from(self);
39
- let internals = validator.collect_and_validate_internals();
40
- if internals.contains_key(&command) {
41
- let interface = internals.get(&command).expect("known command");
42
- return interface.run(args, &internals);
43
- }
44
- if self.scope.configuration.commands.contains_key(&command) {
45
- let root_script = self
46
- .scope
47
- .configuration
48
- .commands
49
- .get(&command)
50
- .expect("Unknown command");
51
- return Executor::with_stdio(
52
- format!("{} {}", root_script.command, &args.join(" ")),
53
- |cmd| cmd.current_dir(Path::new(&self.scope.root)),
54
- );
22
+ let internals = CommandValidations::collect_and_validate_internals();
23
+ if let Some(internal_command) = internals.get(&command) {
24
+ return internal_command.run(args, &internals);
55
25
  }
56
- let externals = validator.collect_and_validate_externals();
26
+ RepoKitRuntime::with_runtime(|runtime| {
27
+ if let Some(root_script) = runtime.configuration.commands.get(&command) {
28
+ Executor::with_stdio(
29
+ format!("{} {}", root_script.command, &args.join(" ")),
30
+ |cmd| cmd.current_dir(&runtime.files.git_root_path),
31
+ );
32
+ panic!();
33
+ }
34
+ });
35
+ let externals = CommandValidations::collect_and_validate_externals();
57
36
  CommandValidations::detect_collisions_between_internals_and_externals(
58
37
  &internals, &externals,
59
38
  );
60
- if externals.contains_key(&command) {
61
- let interface = externals.get(&command).expect("Unknown command");
39
+ if let Some(interface) = externals.get(&command) {
62
40
  if args.is_empty() {
63
41
  return self.log_external_command(interface);
64
42
  }
65
43
  let sub_command = &args[0];
66
- if interface.commands.contains_key(sub_command) {
67
- let script = interface.commands.get(sub_command).expect("Unknown script");
68
- let working_dir = Path::new(&interface.location)
69
- .parent()
70
- .expect("Working directory not found");
71
- return Executor::with_stdio(
72
- format!("{} {}", &script.command, &args[1..].join(" ")),
73
- |cmd| cmd.current_dir(working_dir),
74
- );
44
+ if let Some(script) = interface.commands.get(sub_command) {
45
+ let executable = format!("{} {}", &script.command, &args[1..].join(" "));
46
+ if let Some(working_dir) = Path::new(&interface.location).parent() {
47
+ return Executor::with_stdio(executable, |cmd| cmd.current_dir(working_dir));
48
+ }
49
+ return self.working_directory_not_found(interface, &executable);
75
50
  }
76
51
  return self.subcommand_not_found(interface, sub_command);
77
52
  }
@@ -82,8 +57,8 @@ impl RepoKit {
82
57
  let argv: Vec<String> = args().collect();
83
58
  if argv.len() < 2 {
84
59
  let (internals, externals) = self.collect_and_validate();
85
- Help::list_all(&self.scope.configuration.commands, &internals, &externals);
86
- PostProcessor::get().flush();
60
+ Help::list_all(&internals, &externals);
61
+ panic!();
87
62
  }
88
63
  let command = &argv[1];
89
64
  let args = &(&argv)[2..];
@@ -96,9 +71,8 @@ impl RepoKit {
96
71
  HashMap<String, Box<dyn InternalExecutable>>,
97
72
  HashMap<String, RepoKitCommand>,
98
73
  ) {
99
- let validator = CommandValidations::from(self);
100
- let internals = validator.collect_and_validate_internals();
101
- let externals = validator.collect_and_validate_externals();
74
+ let internals = CommandValidations::collect_and_validate_internals();
75
+ let externals = CommandValidations::collect_and_validate_externals();
102
76
  CommandValidations::detect_collisions_between_internals_and_externals(
103
77
  &internals, &externals,
104
78
  );
@@ -111,7 +85,7 @@ impl RepoKit {
111
85
  internals: &HashMap<String, Box<dyn InternalExecutable>>,
112
86
  externals: &HashMap<String, RepoKitCommand>,
113
87
  ) {
114
- Help::list_all(&self.scope.configuration.commands, internals, externals);
88
+ Help::list_all(internals, externals);
115
89
  Logger::info(
116
90
  format!(
117
91
  "I'm not aware of a command named {}",
@@ -151,4 +125,22 @@ impl RepoKit {
151
125
  Help::log_external_subcommands(&command.commands, 3);
152
126
  println!();
153
127
  }
128
+
129
+ fn working_directory_not_found(&self, interface: &RepoKitCommand, executable: &str) {
130
+ Logger::info("I was unable to determine the working directory for this command");
131
+ Logger::info(
132
+ format!(
133
+ "This typically indicates a bug within {}",
134
+ Logger::with_theme(|theme| theme.highlight("Repokit"))
135
+ )
136
+ .as_str(),
137
+ );
138
+ Logger::info("Please file an issue at");
139
+ Logger::log_issue_link();
140
+ Logger::info("To run this command from your terminal, you can run:");
141
+ Logger::log_file_path(executable);
142
+ Logger::info("From the parent directory of");
143
+ Logger::log_file_path(&interface.location);
144
+ panic!();
145
+ }
154
146
  }
@@ -1,7 +1,4 @@
1
- use std::{
2
- collections::HashMap,
3
- sync::LazyLock,
4
- };
1
+ use std::{collections::HashMap, sync::LazyLock};
5
2
 
6
3
  use jsonschema::Validator;
7
4
  use schemars::JsonSchema;
@@ -9,12 +6,11 @@ use serde::Deserialize;
9
6
  use serde_json::{Value, from_value, to_value};
10
7
 
11
8
  use crate::{
12
- configuration::recovery::Recovery,
13
9
  logger::logger::Logger,
14
10
  post_processing::post_processor::PostProcessor,
15
11
  repokit::{
16
12
  command_definition::CommandDefinition,
17
- repokit_construct_validator::RepoKitConstructValidator,
13
+ repokit_construct_validator::RepoKitConstructValidator, repokit_runtime::RepoKitRuntime,
18
14
  },
19
15
  };
20
16
 
@@ -31,37 +27,14 @@ static REPOKIT_COMMAND_VALIDATOR: LazyLock<Validator> = LazyLock::new(|| {
31
27
  Validator::new(&to_value(schemars::schema_for!(RepoKitCommand)).unwrap()).unwrap()
32
28
  });
33
29
 
34
- impl RepoKitCommand {
35
- fn register_encountered_errors(root: &str, failed_paths: Vec<String>) {
36
- let root_clone = root.to_string();
37
- PostProcessor::get().register_task(move || {
38
- println!();
39
- if !failed_paths.is_empty() {
40
- let appendage = if failed_paths.len() != 1 { "s" } else { "" };
41
- Logger::error(
42
- format!(
43
- "I encountered an error in the following command{}",
44
- appendage
45
- )
46
- .as_str(),
47
- );
48
- Logger::list_file_paths(&failed_paths);
49
- } else {
50
- Logger::info("There was an error parsing one or more of your commands");
51
- }
52
- Logger::info("You can validate a command file's syntactical correctness by running");
53
- Logger::log_file_path(
54
- &Recovery::new(&root_clone).get_typecheck_command("<optional-path-to-file>"),
55
- );
56
- });
57
- }
58
- }
30
+ impl RepoKitConstructValidator for RepoKitCommand {}
59
31
 
60
- impl RepoKitConstructValidator<Vec<Value>, Vec<RepoKitCommand>> for RepoKitCommand {
61
- fn from_input(root: &str, input: Vec<Value>) -> Vec<RepoKitCommand> {
32
+ impl RepoKitCommand {
33
+ pub fn from_input(input: Vec<Value>) -> Vec<RepoKitCommand> {
62
34
  let mut result: Vec<RepoKitCommand> = Vec::new();
63
35
  let mut failures = 0;
64
36
  let mut failed_paths: Vec<String> = Vec::new();
37
+ let git_root = RepoKitRuntime::with_runtime(|runtime| runtime.git.root.clone());
65
38
  for command in input {
66
39
  let repokit_command: Result<RepoKitCommand, serde_json::Error> =
67
40
  from_value(command.clone());
@@ -69,28 +42,86 @@ impl RepoKitConstructValidator<Vec<Value>, Vec<RepoKitCommand>> for RepoKitComma
69
42
  || repokit_command.is_err()
70
43
  {
71
44
  failures += 1;
72
- if let Some(path) = RepoKitCommand::on_parsing_error(root, command) {
45
+ if let Some(path) = RepoKitCommand::on_parsing_error(command) {
73
46
  failed_paths.push(path);
74
47
  }
75
48
  } else {
76
49
  let mut valid_command = repokit_command.expect("assertion success");
77
- valid_command.location = format!("{}/{}", root, valid_command.location);
50
+ valid_command.location = format!("{}/{}", git_root, valid_command.location);
78
51
  result.push(valid_command);
79
52
  }
80
53
  }
81
54
  if failures != 0 {
82
- RepoKitCommand::register_encountered_errors(root, failed_paths);
55
+ RepoKitCommand::register_encountered_errors(failed_paths);
83
56
  }
84
57
  result
85
58
  }
86
59
 
87
- fn on_parsing_error(root: &str, command: Value) -> Option<String> {
60
+ pub fn on_parsing_error(command: Value) -> Option<String> {
88
61
  let location = command.get("location");
89
62
  println!();
90
63
  if location.is_some_and(|v| v.is_string()) {
91
- let path = format!("{}/{}", &root, location.unwrap().as_str().unwrap());
64
+ let path = RepoKitRuntime::with_runtime(|runtime| {
65
+ format!(
66
+ "{}/{}",
67
+ runtime.git.root,
68
+ location.unwrap().as_str().unwrap()
69
+ )
70
+ });
92
71
  return Some(path);
93
72
  }
94
73
  None
95
74
  }
75
+
76
+ pub fn full_blown_crash() {
77
+ Logger::error("I hit a snag parsing your commands");
78
+ Logger::error(
79
+ format!(
80
+ "This kind of error is indicative of a bug within {}",
81
+ Logger::with_theme(|theme| theme.highlight("Repokit"))
82
+ )
83
+ .as_str(),
84
+ );
85
+ println!();
86
+ Logger::info("Let's blaim the AI's for this one");
87
+ let version = RepoKitRuntime::with_runtime(|runtime| {
88
+ runtime.caches.version_cache.installed_version.clone()
89
+ });
90
+ Logger::info(
91
+ format!(
92
+ "In the interim, please file a bug here and downgrade to the most recent version behind {}",
93
+ Logger::with_theme(|theme| theme.highlight(&version))
94
+ )
95
+ .as_str(),
96
+ );
97
+ Logger::log_issue_link();
98
+ Logger::info("We'll get a hotfix out asap!");
99
+ panic!();
100
+ }
101
+
102
+ fn register_encountered_errors(failed_paths: Vec<String>) {
103
+ PostProcessor::get().register_task(move || {
104
+ println!();
105
+ if !failed_paths.is_empty() {
106
+ let appendage = if failed_paths.len() != 1 { "s" } else { "" };
107
+ Logger::error(
108
+ format!(
109
+ "I encountered an error in the following command{}",
110
+ appendage
111
+ )
112
+ .as_str(),
113
+ );
114
+ Logger::list_file_paths(&failed_paths);
115
+ } else {
116
+ Logger::info("There was an error parsing one or more of your commands");
117
+ }
118
+ Logger::info("You can validate a command file's syntactical correctness by running");
119
+ let type_check_command = RepoKitRuntime::with_runtime(|mut runtime| {
120
+ runtime
121
+ .node
122
+ .get_typecheck_command("<optional-path-to-file>")
123
+ });
124
+ Logger::log_file_path(&type_check_command);
125
+ });
126
+ }
96
127
  }
@@ -1,19 +1,14 @@
1
- use std::{
2
- collections::HashMap,
3
- path::Path,
4
- process::exit,
5
- sync::LazyLock,
6
- };
7
-
1
+ use core::panic;
8
2
  use jsonschema::Validator;
9
3
  use schemars::JsonSchema;
10
4
  use serde::Deserialize;
11
5
  use serde_json::{Value, from_value, to_value};
6
+ use std::{collections::HashMap, path::Path, sync::LazyLock};
12
7
 
13
8
  use crate::{
14
- configuration::recovery::Recovery,
9
+ context::{file_system::FileSystem, node_scope::NodeScope},
10
+ internal_filesystem::file_builder::FileBuilder,
15
11
  logger::logger::Logger,
16
- post_processing::post_processor::PostProcessor,
17
12
  repokit::{
18
13
  command_definition::CommandDefinition, repokit_command::RepoKitCommand,
19
14
  repokit_construct_validator::RepoKitConstructValidator,
@@ -52,24 +47,53 @@ static REPOKIT_CONFIG_VALIDATOR: LazyLock<Validator> = LazyLock::new(|| {
52
47
  Validator::new(&to_value(schemars::schema_for!(RepoKitConfig)).unwrap()).unwrap()
53
48
  });
54
49
 
55
- impl RepoKitConstructValidator<Value, RepoKitConfig> for RepoKitConfig {
56
- fn from_input(root: &str, input: Value) -> RepoKitConfig {
50
+ impl RepoKitConstructValidator for RepoKitConfig {}
51
+
52
+ impl RepoKitConfig {
53
+ pub fn from_input(root: &str, node: &mut NodeScope, input: Value) -> RepoKitConfig {
57
54
  let repokit_config: Result<RepoKitConfig, serde_json::Error> = from_value(input.clone());
58
55
  if !RepoKitConfig::is_valid(&REPOKIT_CONFIG_VALIDATOR, &input) || repokit_config.is_err() {
59
- RepoKitConfig::on_parsing_error(root, Value::Null);
56
+ RepoKitConfig::on_parsing_error(root, node, Value::Null);
60
57
  }
61
58
  repokit_config.expect("assertions succeeded")
62
59
  }
63
60
 
64
- fn on_parsing_error(root: &str, _: Value) -> Option<String> {
61
+ pub fn on_parsing_error(root: &str, node: &mut NodeScope, _: Value) -> Option<String> {
65
62
  let path_buf = Path::new(&root).join("repokit.ts");
66
63
  let path = path_buf.to_str().expect("exists");
67
- let mut recovery = Recovery::new(root);
68
- recovery.run(path);
64
+ node.type_check_file(path);
69
65
  println!();
70
66
  Logger::info("There was an error parsing your configuration");
71
- recovery.prompt_to_fix_errors(path);
72
- PostProcessor::get().flush();
73
- exit(0);
67
+ NodeScope::prompt_to_fix_errors(path);
68
+ panic!();
69
+ }
70
+
71
+ pub fn create(files: &FileSystem) {
72
+ let file_path = format!("{}/repokit.ts", &files.git_root);
73
+ let path = Path::new(&file_path);
74
+ if path.exists() {
75
+ Logger::info(
76
+ format!(
77
+ "I found a Repokit configuration without an exported {} instance",
78
+ Logger::with_theme(|theme| theme.highlight("RepokitConfig"))
79
+ )
80
+ .as_str(),
81
+ );
82
+ return Logger::exit_with_info("Please create an instance and export it");
83
+ }
84
+ Logger::info("Welcome to Repokit! Let's get you setup");
85
+ Logger::info("Creating your configuration file:");
86
+ let mut source = files.resolve_template("configuration_template.txt");
87
+ let mut target = FileBuilder::create(path, |_| Logger::file_create_error());
88
+ FileBuilder::copy_to(&mut source, &mut target, |_| Logger::file_write_error());
89
+ Logger::info(
90
+ format!(
91
+ "Please fill out this file with your desired settings. Then run {}",
92
+ Logger::with_theme(|theme| theme.highlight("repokit onboard"))
93
+ )
94
+ .as_str(),
95
+ );
96
+ Logger::log_file_path(file_path.as_str());
97
+ panic!();
74
98
  }
75
99
  }
@@ -1,10 +1,7 @@
1
1
  use jsonschema::Validator;
2
2
  use serde_json::Value;
3
3
 
4
- pub trait RepoKitConstructValidator<T, V> {
5
- fn from_input(root: &str, input: T) -> V;
6
- fn on_parsing_error(root: &str, value: Value) -> Option<String>;
7
-
4
+ pub trait RepoKitConstructValidator {
8
5
  fn is_valid(validator: &Validator, input: &Value) -> bool {
9
6
  if validator.validate(input).is_err() {
10
7
  return false;