@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
package/Cargo.lock CHANGED
@@ -293,6 +293,94 @@ dependencies = [
293
293
  "num",
294
294
  ]
295
295
 
296
+ [[package]]
297
+ name = "futures"
298
+ version = "0.3.32"
299
+ source = "registry+https://github.com/rust-lang/crates.io-index"
300
+ checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
301
+ dependencies = [
302
+ "futures-channel",
303
+ "futures-core",
304
+ "futures-executor",
305
+ "futures-io",
306
+ "futures-sink",
307
+ "futures-task",
308
+ "futures-util",
309
+ ]
310
+
311
+ [[package]]
312
+ name = "futures-channel"
313
+ version = "0.3.32"
314
+ source = "registry+https://github.com/rust-lang/crates.io-index"
315
+ checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
316
+ dependencies = [
317
+ "futures-core",
318
+ "futures-sink",
319
+ ]
320
+
321
+ [[package]]
322
+ name = "futures-core"
323
+ version = "0.3.32"
324
+ source = "registry+https://github.com/rust-lang/crates.io-index"
325
+ checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
326
+
327
+ [[package]]
328
+ name = "futures-executor"
329
+ version = "0.3.32"
330
+ source = "registry+https://github.com/rust-lang/crates.io-index"
331
+ checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
332
+ dependencies = [
333
+ "futures-core",
334
+ "futures-task",
335
+ "futures-util",
336
+ ]
337
+
338
+ [[package]]
339
+ name = "futures-io"
340
+ version = "0.3.32"
341
+ source = "registry+https://github.com/rust-lang/crates.io-index"
342
+ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
343
+
344
+ [[package]]
345
+ name = "futures-macro"
346
+ version = "0.3.32"
347
+ source = "registry+https://github.com/rust-lang/crates.io-index"
348
+ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
349
+ dependencies = [
350
+ "proc-macro2",
351
+ "quote",
352
+ "syn",
353
+ ]
354
+
355
+ [[package]]
356
+ name = "futures-sink"
357
+ version = "0.3.32"
358
+ source = "registry+https://github.com/rust-lang/crates.io-index"
359
+ checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
360
+
361
+ [[package]]
362
+ name = "futures-task"
363
+ version = "0.3.32"
364
+ source = "registry+https://github.com/rust-lang/crates.io-index"
365
+ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
366
+
367
+ [[package]]
368
+ name = "futures-util"
369
+ version = "0.3.32"
370
+ source = "registry+https://github.com/rust-lang/crates.io-index"
371
+ checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
372
+ dependencies = [
373
+ "futures-channel",
374
+ "futures-core",
375
+ "futures-io",
376
+ "futures-macro",
377
+ "futures-sink",
378
+ "futures-task",
379
+ "memchr",
380
+ "pin-project-lite",
381
+ "slab",
382
+ ]
383
+
296
384
  [[package]]
297
385
  name = "getrandom"
298
386
  version = "0.2.17"
@@ -900,10 +988,11 @@ checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
900
988
 
901
989
  [[package]]
902
990
  name = "repokit"
903
- version = "3.0.6"
991
+ version = "4.0.0"
904
992
  dependencies = [
905
993
  "alphanumeric-sort",
906
994
  "colored",
995
+ "futures",
907
996
  "ignore",
908
997
  "jsonschema",
909
998
  "normalize-path",
@@ -913,7 +1002,6 @@ dependencies = [
913
1002
  "serde_json",
914
1003
  "shellexpand",
915
1004
  "terminal-spinners",
916
- "tokio",
917
1005
  ]
918
1006
 
919
1007
  [[package]]
@@ -1056,6 +1144,12 @@ dependencies = [
1056
1144
  "libc",
1057
1145
  ]
1058
1146
 
1147
+ [[package]]
1148
+ name = "slab"
1149
+ version = "0.4.12"
1150
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1151
+ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
1152
+
1059
1153
  [[package]]
1060
1154
  name = "smallvec"
1061
1155
  version = "1.15.1"
@@ -1173,15 +1267,6 @@ dependencies = [
1173
1267
  "zerovec",
1174
1268
  ]
1175
1269
 
1176
- [[package]]
1177
- name = "tokio"
1178
- version = "1.50.0"
1179
- source = "registry+https://github.com/rust-lang/crates.io-index"
1180
- checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
1181
- dependencies = [
1182
- "pin-project-lite",
1183
- ]
1184
-
1185
1270
  [[package]]
1186
1271
  name = "unicode-general-category"
1187
1272
  version = "1.1.0"
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "repokit"
3
- version = "3.0.6"
3
+ version = "4.0.0"
4
4
  edition = "2024"
5
5
 
6
6
  [[bin]]
@@ -14,9 +14,9 @@ serde_json = "1.0"
14
14
  colored = "3"
15
15
  normalize-path = "0.2.1"
16
16
  alphanumeric-sort = "1.5.5"
17
- tokio = "1.50.0"
18
17
  ignore = "0.4.25"
19
18
  regex = { version = "1.12.3", features = ["std", "unicode"] }
20
19
  shellexpand = "3.1.2"
21
20
  schemars = "1.2.1"
22
21
  terminal-spinners = "0.3.2"
22
+ futures = "0.3.32"
@@ -1,10 +1,10 @@
1
- CURRENT_VERSION="3.0.6"
1
+ CURRENT_VERSION="4.0.0"
2
2
  CWD=$(pwd)
3
3
 
4
4
  REPLACEMENT="/node_modules"
5
5
  FALLBACK_ROOT="${CWD%${REPLACEMENT}*}"
6
6
 
7
- GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
7
+ GIT_ROOT=$(git rev-parse --show-toplevel)
8
8
  REPO_ROOT=${GIT_ROOT:-$FALLBACK_ROOT}
9
9
 
10
10
  if [[ "$CWD" != *"$REPLACEMENT"* ]]; then
@@ -31,39 +31,50 @@ ROOT_COMMIT=$(git rev-list --parents HEAD | tail -1) || ROOT_COMMIT=""
31
31
 
32
32
  cd
33
33
 
34
- CACHE_FILE=".repokit";
34
+ OLD_CACHE_FILE=".repokit";
35
35
  CACHE_DIRECTORY=".repokit_cache";
36
- NEW_SETTINGS_FILE=".settings"
36
+ VERSION_FILE=".version"
37
+ SETTINGS_FILE=".settings"
37
38
  REPO_CACHE_DIRECTORY="$CACHE_DIRECTORY/$ROOT_COMMIT"
38
- LAST_THEME_USED=""
39
- BACK_PORTING=0
40
-
41
- if [ -n "$ROOT_COMMIT" ] && [ -f "$REPO_CACHE_DIRECTORY/$NEW_SETTINGS_FILE" ]; then
42
- BACK_PORTING=1
43
- cd "$REPO_CACHE_DIRECTORY"
44
- read -r LAST_THEME_USED < "$NEW_SETTINGS_FILE"
45
- rm "$NEW_SETTINGS_FILE"
46
- cd
47
- fi
48
39
 
49
- if [ ! -f "$CACHE_FILE" ]; then
50
- touch "$CACHE_FILE"
51
- elif [ "$BACK_PORTING" == 0 ]; then
52
- read -r LAST_VERSION_USED < "$CACHE_FILE"
53
- if [ "$LAST_VERSION_USED" == "$CURRENT_VERSION" ]; then
54
- exit 0
40
+ CACHED_THEME=""
41
+
42
+ if [ -f "$OLD_CACHE_FILE" ] && [ -n "$ROOT_COMMIT" ] && [ ! -f "$REPO_CACHE_DIRECTORY/$SETTINGS_FILE" ]; then
43
+ {
44
+ read -r
45
+ read -r CACHED_THEME
46
+ } < "$OLD_CACHE_FILE"
47
+ echo "CACHED THEME $CACHED_THEME"
48
+ fi
49
+
50
+ if [ ! -d "$CACHE_DIRECTORY" ]; then
51
+ mkdir "$CACHE_DIRECTORY"
52
+ fi
53
+
54
+ cd "$CACHE_DIRECTORY"
55
+
56
+ if [ -n "$ROOT_COMMIT" ]; then
57
+ if [ ! -d "$ROOT_COMMIT" ]; then
58
+ mkdir "$ROOT_COMMIT"
55
59
  fi
60
+ cd $ROOT_COMMIT;
61
+ if [ -n "$CACHED_THEME" ] && [ ! -f "$SETTINGS_FILE" ]; then
62
+ touch "$SETTINGS_FILE"
63
+ echo "$CACHED_THEME\n" > "$SETTINGS_FILE"
64
+ fi
65
+ cd "../"
56
66
  fi
57
67
 
58
- if [ -n "$LAST_THEME_USED" ]; then
59
- echo "$CURRENT_VERSION\n$LAST_THEME_USED\n" > "$CACHE_FILE"
60
- else
61
- TEMP_FILE=".repokit_tmp";
62
- printf "$CURRENT_VERSION\n" > "$TEMP_FILE"
63
- tail +2 "$CACHE_FILE" >> "$TEMP_FILE"
64
- mv "$TEMP_FILE" "$CACHE_FILE"
65
- fi
68
+ if [ -f $VERSION_FILE ]; then
69
+ read -r CACHED_VERSION < "$VERSION_FILE"
70
+ if [ "$CACHED_VERSION" == "$CURRENT_VERSION" ]; then
71
+ exit 0;
72
+ fi
73
+ else
74
+ touch "$VERSION_FILE"
75
+ fi
66
76
 
77
+ echo "$CURRENT_VERSION\n" > "$VERSION_FILE"
67
78
 
68
79
  cd $CWD
69
80
 
@@ -0,0 +1,124 @@
1
+ use std::{
2
+ collections::HashSet,
3
+ path::{Path, PathBuf},
4
+ };
5
+
6
+ use regex::Regex;
7
+
8
+ use crate::{
9
+ caches::file_cache::FileCache, context::git_scope::GitScope, executor::executor::Executor,
10
+ logger::logger::Logger, post_processing::post_processor::PostProcessor,
11
+ };
12
+
13
+ #[derive(Clone)]
14
+ pub struct CrawlCache {
15
+ pub cache_directory: Option<PathBuf>,
16
+ pub files_to_crawl: Option<Vec<String>>,
17
+ }
18
+
19
+ impl CrawlCache {
20
+ pub fn new(cache_directory: &Option<PathBuf>) -> Self {
21
+ CrawlCache {
22
+ files_to_crawl: None,
23
+ cache_directory: cache_directory.clone(),
24
+ }
25
+ }
26
+
27
+ pub async fn initialize(&mut self, git_scope: &GitScope) {
28
+ let head_commit = git_scope
29
+ .head_commit_hash
30
+ .to_owned()
31
+ .unwrap_or("".to_string());
32
+ if let Some((mut lines, path)) = self.read() {
33
+ let commit_hash = self.unwrap_line(lines.nth(0), "non_existent_hash");
34
+ if commit_hash != head_commit {
35
+ return;
36
+ }
37
+ let mut lines = self.line_buffer_to_vec(lines);
38
+ if lines.is_empty() {
39
+ return;
40
+ }
41
+ let (git_ignore_changed, mut changed_files) = self.get_changed_files(&git_scope.root);
42
+ if git_ignore_changed {
43
+ CrawlCache::clear_cache_file(path.to_owned(), false);
44
+ return;
45
+ }
46
+ for line in &lines {
47
+ if changed_files.contains(line) {
48
+ changed_files.remove(line);
49
+ }
50
+ }
51
+ for line in changed_files {
52
+ lines.push(line);
53
+ }
54
+ self.files_to_crawl = Some(lines);
55
+ }
56
+ }
57
+
58
+ pub fn crawl_cache_enabled(&self) -> bool {
59
+ self.files_to_crawl.is_some()
60
+ }
61
+
62
+ pub fn cache_crawl_results(&self, results: String) {
63
+ self.write(&results, |_| {
64
+ self.on_crawl_cache_storage_error();
65
+ });
66
+ }
67
+
68
+ fn on_crawl_cache_storage_error(&self) {
69
+ if let Some(storage_path) = self.storage_path() {
70
+ PostProcessor::get().register_task(move || {
71
+ Logger::info(
72
+ "I attempted to cache the results of a file crawl, but couldn't write to disk",
73
+ );
74
+ CrawlCache::log_cache_write_error();
75
+ Logger::info(
76
+ "To avoid issues with stale caches I'm going to delete what's currently on disk",
77
+ );
78
+ CrawlCache::clear_cache_file(storage_path.clone(), true);
79
+ });
80
+ }
81
+ }
82
+
83
+ fn get_changed_files(&self, git_root: &str) -> (bool, HashSet<String>) {
84
+ let mut contains_git_ignore = false;
85
+ let file_path_matcher = Regex::new(r#"^.*\s(.*\.ts)$"#).unwrap();
86
+ let stdout = Executor::exec("git status --porcelain -uall", |cmd| cmd);
87
+ let git_root_path = Path::new(git_root);
88
+ let files: HashSet<String> = stdout
89
+ .split("\n")
90
+ .filter_map(|file| {
91
+ if !contains_git_ignore && file.ends_with(".gitignore") {
92
+ contains_git_ignore = true;
93
+ return None;
94
+ }
95
+ let matches: Vec<&str> = file_path_matcher
96
+ .captures_iter(file)
97
+ .filter_map(|entry| {
98
+ if let Some(match_result) = entry.get(1) {
99
+ return Some(match_result.as_str());
100
+ }
101
+ None
102
+ })
103
+ .collect();
104
+ if let Some(file_path) = matches.first()
105
+ && git_root_path.join(file_path).exists()
106
+ {
107
+ return Some(file_path.to_string());
108
+ }
109
+ None
110
+ })
111
+ .collect();
112
+ (contains_git_ignore, files)
113
+ }
114
+ }
115
+
116
+ impl FileCache for CrawlCache {
117
+ fn cache_file(&self) -> &str {
118
+ ".crawl_cache"
119
+ }
120
+
121
+ fn cache_directory(&self) -> &Option<PathBuf> {
122
+ &self.cache_directory
123
+ }
124
+ }
@@ -0,0 +1,104 @@
1
+ use std::{
2
+ fs::{File, write},
3
+ io::{BufRead, BufReader, Error, Lines},
4
+ path::PathBuf,
5
+ };
6
+
7
+ use normalize_path::NormalizePath;
8
+
9
+ use crate::{logger::logger::Logger, post_processing::post_processor::PostProcessor};
10
+
11
+ pub trait FileCache {
12
+ fn cache_file(&self) -> &str;
13
+
14
+ fn cache_directory(&self) -> &Option<PathBuf>;
15
+
16
+ fn storage_path(&self) -> Option<PathBuf> {
17
+ if let Some(storage_path) = self.perspective_path()
18
+ && storage_path.exists()
19
+ {
20
+ return Some(storage_path);
21
+ }
22
+ None
23
+ }
24
+
25
+ fn perspective_path(&self) -> Option<PathBuf> {
26
+ if let Some(cache_dir) = &self.cache_directory() {
27
+ return Some(cache_dir.join(self.cache_file()).normalize());
28
+ }
29
+ None
30
+ }
31
+
32
+ async fn create_cache_file_if_not_exists(&self) -> Option<PathBuf> {
33
+ if let Some(storage_path) = self.perspective_path()
34
+ && !&storage_path.exists()
35
+ && write(&storage_path, "").is_ok()
36
+ {
37
+ return Some(storage_path);
38
+ }
39
+ None
40
+ }
41
+
42
+ fn read(&self) -> Option<(Lines<BufReader<File>>, PathBuf)> {
43
+ if let Some(path) = self.storage_path()
44
+ && let Ok(file) = File::open(&path)
45
+ {
46
+ return Some((BufReader::new(file).lines(), path));
47
+ }
48
+ None
49
+ }
50
+
51
+ fn write(&self, content: &str, on_error: impl Fn(Error)) {
52
+ if let Some(path) = self.storage_path()
53
+ && let Err(error) = write(path, content)
54
+ {
55
+ on_error(error);
56
+ }
57
+ }
58
+
59
+ fn line_buffer_to_vec(&self, lines: Lines<BufReader<File>>) -> Vec<String> {
60
+ lines.filter_map(Result::ok).collect()
61
+ }
62
+
63
+ fn insert_as_first_line(&self, lines: Lines<BufReader<File>>, value: String) -> Vec<String> {
64
+ let mut lines: Vec<String> = self.line_buffer_to_vec(lines);
65
+ if !lines.is_empty() {
66
+ lines[0] = value;
67
+ } else {
68
+ lines.push(value);
69
+ }
70
+ lines
71
+ }
72
+
73
+ fn unwrap_line(&self, line_result: Option<Result<String, Error>>, fallback: &str) -> String {
74
+ line_result
75
+ .and_then(|r| r.ok())
76
+ .unwrap_or(fallback.to_string())
77
+ }
78
+
79
+ fn clear_cache_file(path: PathBuf, notify: bool) {
80
+ // This is post-processed so it doesn't block the command the user is executing
81
+ PostProcessor::get().register_task(move || {
82
+ if write(&path, "").is_err() {
83
+ Logger::error("I was unable to remove a cache on disk");
84
+ Logger::error("To correct this, please run");
85
+ Logger::log_file_path(format!("rm {}", path.to_string_lossy()).as_str())
86
+ } else if notify {
87
+ Logger::info("Cache deleted!");
88
+ }
89
+ });
90
+ }
91
+
92
+ fn log_cache_write_error() {
93
+ Logger::info("This is typically a permission-related issue on the operating system");
94
+ Logger::info(
95
+ format!(
96
+ "If you believe this to be a bug within {}",
97
+ Logger::with_theme(|theme| theme.highlight("Repokit"))
98
+ )
99
+ .as_str(),
100
+ );
101
+ Logger::info("Please file an issue here");
102
+ Logger::log_issue_link();
103
+ }
104
+ }
@@ -0,0 +1,5 @@
1
+ pub mod crawl_cache;
2
+ pub mod file_cache;
3
+ pub mod repokit_version_resolver;
4
+ pub mod settings_cache;
5
+ pub mod version_cache;
@@ -0,0 +1,50 @@
1
+ use std::env::args;
2
+
3
+ use terminal_spinners::{BOUNCING_BALL, SpinnerBuilder};
4
+
5
+ use crate::{
6
+ context::file_system::FileSystem, executor::executor::Executor, logger::logger::Logger,
7
+ };
8
+
9
+ pub struct RepoKitVersionResolver;
10
+
11
+ impl RepoKitVersionResolver {
12
+ pub fn hop_to_installed_version(files: &FileSystem) {
13
+ if files.install_script_path.is_absolute() && files.install_script_path.exists() {
14
+ if let Some(errors) = RepoKitVersionResolver::run_post_install(files) {
15
+ println!("{errors}");
16
+ Logger::error("My installer failed");
17
+ RepoKitVersionResolver::on_error();
18
+ } else {
19
+ RepoKitVersionResolver::re_run_command();
20
+ }
21
+ } else {
22
+ Logger::error("I couldn't find my installer");
23
+ RepoKitVersionResolver::on_error();
24
+ }
25
+ panic!();
26
+ }
27
+
28
+ fn run_post_install(files: &FileSystem) -> Option<String> {
29
+ let handle = SpinnerBuilder::new()
30
+ .spinner(&BOUNCING_BALL)
31
+ .text(" Installing")
32
+ .start();
33
+ let result =
34
+ Executor::exec_with_errors(format!("./{}", files.install_script_location), |cmd| {
35
+ cmd.current_dir(&files.package_directory)
36
+ });
37
+ handle.done();
38
+ result
39
+ }
40
+
41
+ fn re_run_command() {
42
+ let args: Vec<String> = args().collect();
43
+ Executor::with_stdio(args.join(" "), |cmd| cmd);
44
+ }
45
+
46
+ fn on_error() {
47
+ Logger::info("Please file a bug here");
48
+ Logger::log_issue_link();
49
+ }
50
+ }
@@ -0,0 +1,73 @@
1
+ use std::path::PathBuf;
2
+
3
+ use crate::{
4
+ caches::file_cache::FileCache, logger::logger::Logger,
5
+ post_processing::post_processor::PostProcessor,
6
+ };
7
+
8
+ #[derive(Clone)]
9
+ pub struct SettingsCache {
10
+ pub cache_directory: Option<PathBuf>,
11
+ pub theme_preference: String,
12
+ }
13
+
14
+ impl SettingsCache {
15
+ pub fn new(cache_directory: &Option<PathBuf>) -> Self {
16
+ SettingsCache {
17
+ cache_directory: cache_directory.clone(),
18
+ theme_preference: Logger::with_registry(|registry| registry.default_theme.to_owned()),
19
+ }
20
+ }
21
+
22
+ pub async fn initialize(&mut self) {
23
+ if let Some((mut lines, _)) = self.read()
24
+ && let Some(result) = lines.nth(0)
25
+ && let Ok(theme) = result
26
+ {
27
+ self.theme_preference = theme;
28
+ }
29
+ }
30
+
31
+ pub fn store_theme_preference(&self, theme: &str) {
32
+ self.write(format!("{theme}\n").as_str(), |_| {
33
+ self.on_theme_storage_error(theme);
34
+ });
35
+ }
36
+
37
+ fn on_theme_storage_error(&self, theme: &str) {
38
+ if let Some(storage_path) = self.storage_path() {
39
+ let theme_clone = theme.to_string();
40
+ PostProcessor::get().register_task(move || {
41
+ Logger::info("I failed to write your theme preference to the file system");
42
+ Logger::info(
43
+ format!(
44
+ "This usually indicates a bug within {}",
45
+ Logger::with_theme(|theme| theme.highlight("Repokit"))
46
+ )
47
+ .as_str(),
48
+ );
49
+ Logger::info("Please file an issue here");
50
+ Logger::log_issue_link();
51
+ Logger::info("To repair this manually you can run");
52
+ Logger::log_file_path(
53
+ format!(
54
+ "printf \"{}\n\" > {}",
55
+ theme_clone,
56
+ storage_path.to_string_lossy(),
57
+ )
58
+ .as_str(),
59
+ );
60
+ });
61
+ }
62
+ }
63
+ }
64
+
65
+ impl FileCache for SettingsCache {
66
+ fn cache_file(&self) -> &str {
67
+ ".settings"
68
+ }
69
+
70
+ fn cache_directory(&self) -> &Option<PathBuf> {
71
+ &self.cache_directory
72
+ }
73
+ }