@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.
- package/Cargo.lock +96 -11
- package/Cargo.toml +2 -2
- package/installation/install.sh +37 -25
- package/internals/caches/crawl_cache.rs +124 -0
- package/internals/caches/file_cache.rs +104 -0
- package/internals/caches/mod.rs +5 -0
- package/internals/caches/repokit_version_resolver.rs +50 -0
- package/internals/caches/settings_cache.rs +73 -0
- package/internals/caches/version_cache.rs +128 -0
- package/internals/context/cache_scope.rs +76 -0
- package/internals/context/file_system.rs +66 -0
- package/internals/context/git_scope.rs +55 -0
- package/internals/context/mod.rs +5 -0
- package/internals/context/node_scope.rs +133 -0
- package/internals/context/typescript_bridge.rs +68 -0
- package/internals/executables/internal_executable.rs +8 -2
- package/internals/executables/internal_executable_definition.rs +0 -8
- package/internals/executor/executor.rs +13 -0
- package/internals/file_walker/file_walker.rs +59 -0
- package/internals/file_walker/mod.rs +1 -0
- package/internals/internal_commands/help.rs +4 -3
- package/internals/internal_commands/internal_registry.rs +14 -20
- package/internals/internal_commands/list_commands.rs +7 -16
- package/internals/internal_commands/list_owners.rs +3 -16
- package/internals/internal_commands/list_themes.rs +11 -10
- package/internals/internal_commands/list_version.rs +17 -18
- package/internals/internal_commands/locate_command.rs +11 -17
- package/internals/internal_commands/onboarder.rs +5 -16
- package/internals/internal_commands/register_command.rs +12 -20
- package/internals/internal_commands/search_commands.rs +29 -20
- package/internals/internal_commands/upgrade_repokit.rs +19 -30
- package/internals/internal_filesystem/file_builder.rs +4 -9
- package/internals/internal_filesystem/mod.rs +0 -1
- package/internals/logger/logger.rs +19 -6
- package/internals/main.rs +8 -11
- package/internals/repokit/mod.rs +1 -1
- package/internals/repokit/repokit.rs +49 -57
- package/internals/repokit/repokit_command.rs +69 -38
- package/internals/repokit/repokit_config.rs +42 -18
- package/internals/repokit/repokit_construct_validator.rs +1 -4
- package/internals/repokit/repokit_runtime.rs +43 -0
- package/internals/themes/theme_registry.rs +5 -7
- package/internals/validations/command_validations.rs +39 -62
- package/package.json +3 -3
- package/internals/configuration/configuration.rs +0 -45
- package/internals/configuration/mod.rs +0 -3
- package/internals/configuration/recovery.rs +0 -42
- package/internals/configuration/typescript_command.rs +0 -65
- package/internals/internal_filesystem/internal_filesystem.rs +0 -308
- package/internals/repokit/runtime_compiler.rs +0 -62
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
use normalize_path::NormalizePath;
|
|
2
|
-
|
|
3
|
-
use regex::Regex;
|
|
4
|
-
use shellexpand::tilde;
|
|
5
|
-
use std::{
|
|
6
|
-
collections::HashMap,
|
|
7
|
-
fs::{self, File},
|
|
8
|
-
io::{BufRead, BufReader, Lines},
|
|
9
|
-
path::{Path, PathBuf},
|
|
10
|
-
sync::LazyLock,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
use crate::{
|
|
14
|
-
executor::executor::Executor, internal_filesystem::file_builder::FileBuilder,
|
|
15
|
-
logger::logger::Logger,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
pub static VERSION_REGEX: LazyLock<Regex> =
|
|
19
|
-
LazyLock::new(|| Regex::new(r#"\d*\.\d*.\d*"#).unwrap());
|
|
20
|
-
|
|
21
|
-
pub struct InternalFileSystem {
|
|
22
|
-
root: String,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
impl InternalFileSystem {
|
|
26
|
-
pub fn new(root: &str) -> InternalFileSystem {
|
|
27
|
-
InternalFileSystem {
|
|
28
|
-
root: root.to_string(),
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
pub fn absolute(&self, segment: &str) -> PathBuf {
|
|
33
|
-
let path = Path::new(&self.root);
|
|
34
|
-
path.join(segment).normalize()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
pub fn resolve_command(&self, command_name: &str) -> String {
|
|
38
|
-
self.path_buf_to_str(
|
|
39
|
-
self.commands_directory()
|
|
40
|
-
.join(format!("{command_name}.mjs")),
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
pub fn resolve_template(&self, file_name: &str) -> File {
|
|
45
|
-
let path = self.path_buf_to_str(self.templates_directory().join(file_name));
|
|
46
|
-
FileBuilder::open(&path, |_| {
|
|
47
|
-
Logger::error(format!("Unable to locate internal {file_name}").as_str());
|
|
48
|
-
Logger::error("Please file a bug here");
|
|
49
|
-
Logger::log_issue_link();
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
pub fn find_root() -> String {
|
|
54
|
-
let root = Executor::exec("echo $(git rev-parse --show-toplevel 2>/dev/null)", |cmd| {
|
|
55
|
-
cmd
|
|
56
|
-
});
|
|
57
|
-
if root.is_empty() {
|
|
58
|
-
Logger::exit_with_info(
|
|
59
|
-
format!(
|
|
60
|
-
"To start using {}, please initialize your git repository by running {}",
|
|
61
|
-
Logger::with_theme(|theme| theme.highlight("Repokit")),
|
|
62
|
-
Logger::with_theme(|theme| theme.highlight("git init"))
|
|
63
|
-
)
|
|
64
|
-
.as_str(),
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
root
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pub fn read_theme_preference(&self) -> String {
|
|
71
|
-
let default = Logger::with_registry(|registry| registry.default_theme.clone());
|
|
72
|
-
let theme = self.read_dot_file(&mut |mut lines, _| {
|
|
73
|
-
if let Some(theme_preference) = lines.nth(1)
|
|
74
|
-
&& let Ok(preference) = theme_preference
|
|
75
|
-
{
|
|
76
|
-
return preference;
|
|
77
|
-
}
|
|
78
|
-
default.to_string()
|
|
79
|
-
});
|
|
80
|
-
theme.unwrap_or(default)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
pub fn store_theme_preference(&self, theme: &str) {
|
|
84
|
-
self.read_dot_file(&mut |lines, path| {
|
|
85
|
-
let mut content: Vec<String> = lines.map(|line| line.unwrap()).collect();
|
|
86
|
-
let theme_text = theme.to_string();
|
|
87
|
-
if content.len() >= 2 {
|
|
88
|
-
content[1] = theme_text;
|
|
89
|
-
} else {
|
|
90
|
-
content.push(theme_text);
|
|
91
|
-
}
|
|
92
|
-
fs::write(path, content.join("\n"))
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
pub fn store_current_version(&self, version: &str) {
|
|
97
|
-
self.read_dot_file(&mut |lines, path| {
|
|
98
|
-
let mut content: Vec<String> = lines.map(|line| line.unwrap()).collect();
|
|
99
|
-
if !content.is_empty() {
|
|
100
|
-
content[0] = version.to_owned();
|
|
101
|
-
} else {
|
|
102
|
-
content.push(version.to_owned());
|
|
103
|
-
}
|
|
104
|
-
fs::write(path, content.join("\n"))
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
pub fn read_dot_file<R>(
|
|
109
|
-
&self,
|
|
110
|
-
func: &mut impl FnMut(Lines<BufReader<File>>, PathBuf) -> R,
|
|
111
|
-
) -> Option<R> {
|
|
112
|
-
let file_path = self.create_dot_file_if_not_exists();
|
|
113
|
-
match file_path {
|
|
114
|
-
Some(path) => {
|
|
115
|
-
if let Ok(file) = File::open(&path) {
|
|
116
|
-
let lines = BufReader::new(file).lines();
|
|
117
|
-
return Some(func(lines, path));
|
|
118
|
-
}
|
|
119
|
-
None
|
|
120
|
-
}
|
|
121
|
-
None => None,
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
pub fn home() -> Option<PathBuf> {
|
|
126
|
-
let expanded_path_str = tilde("~/");
|
|
127
|
-
let path = Path::new(expanded_path_str.as_ref()).normalize();
|
|
128
|
-
if path.is_absolute() && path.exists() {
|
|
129
|
-
return Some(path);
|
|
130
|
-
}
|
|
131
|
-
None
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
pub fn get_package_manager(root: &str) -> &str {
|
|
135
|
-
let manager_map = HashMap::from([
|
|
136
|
-
("npm", "package-lock.json"),
|
|
137
|
-
("yarn", "yarn.lock"),
|
|
138
|
-
("pnpm", "pnpm-lock.yaml"),
|
|
139
|
-
("bun", "bun.lockb"),
|
|
140
|
-
]);
|
|
141
|
-
for (manager, lock_file) in manager_map {
|
|
142
|
-
let path = Path::new(&root).join(lock_file).normalize();
|
|
143
|
-
if path.exists() && path.is_file() {
|
|
144
|
-
return manager;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
"npm"
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
pub fn get_install_command(root: &str) -> &str {
|
|
151
|
-
let npm_install = "npm i -D";
|
|
152
|
-
let package_manager = InternalFileSystem::get_package_manager(root);
|
|
153
|
-
let manager_map = HashMap::from([
|
|
154
|
-
("npm", npm_install),
|
|
155
|
-
("yarn", "yarn add -D"),
|
|
156
|
-
("pnpm", "pnpm i -D"),
|
|
157
|
-
("bun", "bun add -D"),
|
|
158
|
-
]);
|
|
159
|
-
manager_map.get(package_manager).unwrap_or(&npm_install)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
pub fn get_node_executor(root: &str) -> &str {
|
|
163
|
-
let npx = "npx";
|
|
164
|
-
let package_manager = InternalFileSystem::get_package_manager(root);
|
|
165
|
-
let manager_map = HashMap::from([
|
|
166
|
-
("npm", "npx"),
|
|
167
|
-
("yarn", "yarn run -T"),
|
|
168
|
-
("pnpm", "pnpm run"),
|
|
169
|
-
("bun", "bunx"),
|
|
170
|
-
]);
|
|
171
|
-
manager_map.get(package_manager).unwrap_or(&npx)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
pub fn get_typescript_version(node_executor: &str) -> u32 {
|
|
175
|
-
let stdout = Executor::exec(format!("{} tsc --version", node_executor), |cmd| cmd);
|
|
176
|
-
let lines: Vec<&str> = stdout
|
|
177
|
-
.split("\n")
|
|
178
|
-
.filter_map(|s| {
|
|
179
|
-
let trimmed = s.trim();
|
|
180
|
-
if trimmed.is_empty() {
|
|
181
|
-
return None;
|
|
182
|
-
}
|
|
183
|
-
Some(trimmed)
|
|
184
|
-
})
|
|
185
|
-
.collect();
|
|
186
|
-
let fallback_version = "5.0.0";
|
|
187
|
-
let version = lines.last().unwrap_or(&fallback_version);
|
|
188
|
-
let captures: Vec<String> = VERSION_REGEX
|
|
189
|
-
.captures_iter(version)
|
|
190
|
-
.filter_map(|item| {
|
|
191
|
-
item.get(0)
|
|
192
|
-
.map(|match_text| match_text.as_str().to_string())
|
|
193
|
-
})
|
|
194
|
-
.collect();
|
|
195
|
-
let fallback_version_str = fallback_version.to_string();
|
|
196
|
-
let semver = captures.first().unwrap_or(&fallback_version_str);
|
|
197
|
-
semver
|
|
198
|
-
.chars()
|
|
199
|
-
.next()
|
|
200
|
-
.unwrap_or('5')
|
|
201
|
-
.to_digit(10)
|
|
202
|
-
.unwrap_or(5)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
fn commands_directory(&self) -> PathBuf {
|
|
206
|
-
self.absolute(format!("{}/dist/commands", self.package_directory()).as_str())
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
fn templates_directory(&self) -> PathBuf {
|
|
210
|
-
self.absolute(format!("{}/externals/templates", self.package_directory()).as_str())
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
pub fn package_directory(&self) -> String {
|
|
214
|
-
format!("./node_modules/{}", self.package_name())
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
fn package_name(&self) -> String {
|
|
218
|
-
"@repokit/core".to_string()
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
fn path_buf_to_str(&self, buffer: PathBuf) -> String {
|
|
222
|
-
buffer
|
|
223
|
-
.into_os_string()
|
|
224
|
-
.into_string()
|
|
225
|
-
.expect("Cannot construct path")
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
fn create_dot_file_if_not_exists(&self) -> Option<PathBuf> {
|
|
229
|
-
match InternalFileSystem::home() {
|
|
230
|
-
Some(home) => {
|
|
231
|
-
let dot_file_path = home.join(".repokit");
|
|
232
|
-
if !&dot_file_path.exists() {
|
|
233
|
-
let found_version = self.installed_repokit_version();
|
|
234
|
-
found_version.as_ref()?;
|
|
235
|
-
let version_string = found_version.unwrap();
|
|
236
|
-
let result = fs::write(&dot_file_path, format!("{version_string}\n"));
|
|
237
|
-
if result.is_err() {
|
|
238
|
-
return None;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
Some(dot_file_path)
|
|
242
|
-
}
|
|
243
|
-
None => {
|
|
244
|
-
Logger::error(
|
|
245
|
-
"I encountered an issue when attempting to create a cache file on your machine",
|
|
246
|
-
);
|
|
247
|
-
Logger::error(
|
|
248
|
-
format!(
|
|
249
|
-
"Please create a file called {} in your home directory",
|
|
250
|
-
Logger::with_theme(|theme| theme.highlight(".repokit"))
|
|
251
|
-
)
|
|
252
|
-
.as_str(),
|
|
253
|
-
);
|
|
254
|
-
Logger::error(
|
|
255
|
-
"This file will be used to store settings and indicators that optimize how repokit runs in your repository",
|
|
256
|
-
);
|
|
257
|
-
None
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
pub fn installed_repokit_version(&self) -> Option<String> {
|
|
263
|
-
let package_path = Path::new(&self.root)
|
|
264
|
-
.join(InternalFileSystem::package_directory(self))
|
|
265
|
-
.normalize();
|
|
266
|
-
let package_json_path = package_path.join("package.json");
|
|
267
|
-
let file = File::open(package_json_path);
|
|
268
|
-
if file.is_err() {
|
|
269
|
-
return None;
|
|
270
|
-
}
|
|
271
|
-
let lines = BufReader::new(file.unwrap()).lines();
|
|
272
|
-
let version_matcher = Regex::new(r#""([^"]*)""#).unwrap();
|
|
273
|
-
for line in lines.map_while(Result::ok) {
|
|
274
|
-
if line.contains("\"version\": ") {
|
|
275
|
-
let captures: Vec<String> = version_matcher
|
|
276
|
-
.captures_iter(&line)
|
|
277
|
-
.filter_map(|item| {
|
|
278
|
-
item.get(1)
|
|
279
|
-
.map(|match_text| match_text.as_str().to_string())
|
|
280
|
-
})
|
|
281
|
-
.collect();
|
|
282
|
-
if let Some(version) = captures.get(1)
|
|
283
|
-
&& VERSION_REGEX.is_match(version)
|
|
284
|
-
{
|
|
285
|
-
return Some(version.to_string());
|
|
286
|
-
}
|
|
287
|
-
return None;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
None
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
pub fn runtime_repokit_version() -> Option<String> {
|
|
294
|
-
if let Some(home) = InternalFileSystem::home() {
|
|
295
|
-
let version = Executor::exec(
|
|
296
|
-
format!(
|
|
297
|
-
"head -n 1 {}",
|
|
298
|
-
home.join(".repokit").normalize().to_str().unwrap()
|
|
299
|
-
),
|
|
300
|
-
|cmd| cmd,
|
|
301
|
-
);
|
|
302
|
-
if VERSION_REGEX.is_match(&version) {
|
|
303
|
-
return Some(version);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
None
|
|
307
|
-
}
|
|
308
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
use std::{env::args, path::PathBuf, process::exit};
|
|
2
|
-
|
|
3
|
-
use normalize_path::NormalizePath;
|
|
4
|
-
use terminal_spinners::{BOUNCING_BALL, SpinnerBuilder};
|
|
5
|
-
|
|
6
|
-
use crate::{
|
|
7
|
-
executor::executor::Executor, internal_filesystem::internal_filesystem::InternalFileSystem,
|
|
8
|
-
logger::logger::Logger,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
pub struct RuntimeCompiler;
|
|
12
|
-
|
|
13
|
-
impl RuntimeCompiler {
|
|
14
|
-
pub fn hop_to_runtime_version(root: &str) {
|
|
15
|
-
RuntimeCompiler::with_version_mismatch(root, |installed_version, fs| {
|
|
16
|
-
let package_path = fs.absolute(&fs.package_directory());
|
|
17
|
-
let install_path = package_path.join("installation/install.sh").normalize();
|
|
18
|
-
if install_path.is_absolute() && install_path.exists() {
|
|
19
|
-
Logger::info(
|
|
20
|
-
format!(
|
|
21
|
-
"Switching to version {}",
|
|
22
|
-
Logger::with_theme(|theme| theme.highlight(installed_version))
|
|
23
|
-
)
|
|
24
|
-
.as_str(),
|
|
25
|
-
);
|
|
26
|
-
if let Some(errors) = RuntimeCompiler::run_post_install(&package_path) {
|
|
27
|
-
println!("{errors}");
|
|
28
|
-
} else {
|
|
29
|
-
InternalFileSystem::new(root).store_current_version(installed_version);
|
|
30
|
-
RuntimeCompiler::re_run_command();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn with_version_mismatch(root: &str, func: impl Fn(&str, InternalFileSystem)) {
|
|
37
|
-
let scoped_fs = InternalFileSystem::new(root);
|
|
38
|
-
if let Some(installed_version) = scoped_fs.installed_repokit_version()
|
|
39
|
-
&& let Some(runtime_version) = InternalFileSystem::runtime_repokit_version()
|
|
40
|
-
&& runtime_version != installed_version
|
|
41
|
-
{
|
|
42
|
-
func(&installed_version, scoped_fs);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
fn run_post_install(cwd: &PathBuf) -> Option<String> {
|
|
47
|
-
let handle = SpinnerBuilder::new()
|
|
48
|
-
.spinner(&BOUNCING_BALL)
|
|
49
|
-
.text(" Installing")
|
|
50
|
-
.start();
|
|
51
|
-
let result =
|
|
52
|
-
Executor::exec_with_errors("./installation/install.sh", |cmd| cmd.current_dir(cwd));
|
|
53
|
-
handle.done();
|
|
54
|
-
result
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
fn re_run_command() {
|
|
58
|
-
let args: Vec<String> = args().collect();
|
|
59
|
-
Executor::with_stdio(args.join(" "), |cmd| cmd);
|
|
60
|
-
exit(0);
|
|
61
|
-
}
|
|
62
|
-
}
|