@repokit/core 1.3.5 → 1.3.7
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 +98 -63
- package/Cargo.toml +2 -2
- package/internals/configuration/configuration.rs +10 -9
- package/internals/file_walker/mod.rs +1 -0
- package/internals/file_walker/walker.rs +83 -0
- package/internals/internal_commands/help.rs +8 -1
- package/internals/internal_commands/register_command.rs +5 -9
- package/internals/internal_commands/typescript_command.rs +15 -4
- package/internals/internal_filesystem/file_builder.rs +57 -0
- package/internals/internal_filesystem/internal_filesystem.rs +15 -4
- package/internals/internal_filesystem/mod.rs +1 -0
- package/internals/logger/logger.rs +31 -3
- package/internals/main.rs +1 -1
- package/internals/repokit/repokit.rs +7 -5
- package/internals/validations/command_validations.rs +17 -7
- package/package.json +3 -3
- package/internals/external_commands/external_commands.rs +0 -135
- package/internals/external_commands/mod.rs +0 -1
package/Cargo.lock
CHANGED
|
@@ -3,40 +3,37 @@
|
|
|
3
3
|
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
|
-
name = "
|
|
7
|
-
version = "1.
|
|
6
|
+
name = "aho-corasick"
|
|
7
|
+
version = "1.1.4"
|
|
8
8
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
-
checksum = "
|
|
9
|
+
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"memchr",
|
|
12
|
+
]
|
|
10
13
|
|
|
11
14
|
[[package]]
|
|
12
|
-
name = "
|
|
13
|
-
version = "
|
|
15
|
+
name = "alphanumeric-sort"
|
|
16
|
+
version = "1.5.5"
|
|
14
17
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
-
checksum = "
|
|
16
|
-
dependencies = [
|
|
17
|
-
"windows-sys",
|
|
18
|
-
]
|
|
18
|
+
checksum = "774ffdfeac16e9b4d75e41225dc2545d9c2082a0634b5d7f6f70e168546eecb1"
|
|
19
19
|
|
|
20
20
|
[[package]]
|
|
21
|
-
name = "
|
|
22
|
-
version = "
|
|
21
|
+
name = "bstr"
|
|
22
|
+
version = "1.12.1"
|
|
23
23
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
24
|
-
checksum = "
|
|
24
|
+
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
|
25
25
|
dependencies = [
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"crossbeam-epoch",
|
|
29
|
-
"crossbeam-queue",
|
|
30
|
-
"crossbeam-utils",
|
|
26
|
+
"memchr",
|
|
27
|
+
"serde",
|
|
31
28
|
]
|
|
32
29
|
|
|
33
30
|
[[package]]
|
|
34
|
-
name = "
|
|
35
|
-
version = "
|
|
31
|
+
name = "colored"
|
|
32
|
+
version = "3.1.1"
|
|
36
33
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
37
|
-
checksum = "
|
|
34
|
+
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
|
38
35
|
dependencies = [
|
|
39
|
-
"
|
|
36
|
+
"windows-sys",
|
|
40
37
|
]
|
|
41
38
|
|
|
42
39
|
[[package]]
|
|
@@ -58,27 +55,12 @@ dependencies = [
|
|
|
58
55
|
"crossbeam-utils",
|
|
59
56
|
]
|
|
60
57
|
|
|
61
|
-
[[package]]
|
|
62
|
-
name = "crossbeam-queue"
|
|
63
|
-
version = "0.3.12"
|
|
64
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
65
|
-
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
|
|
66
|
-
dependencies = [
|
|
67
|
-
"crossbeam-utils",
|
|
68
|
-
]
|
|
69
|
-
|
|
70
58
|
[[package]]
|
|
71
59
|
name = "crossbeam-utils"
|
|
72
60
|
version = "0.8.21"
|
|
73
61
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
74
62
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
75
63
|
|
|
76
|
-
[[package]]
|
|
77
|
-
name = "either"
|
|
78
|
-
version = "1.15.0"
|
|
79
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
80
|
-
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
81
|
-
|
|
82
64
|
[[package]]
|
|
83
65
|
name = "futures"
|
|
84
66
|
version = "0.3.31"
|
|
@@ -169,27 +151,52 @@ dependencies = [
|
|
|
169
151
|
]
|
|
170
152
|
|
|
171
153
|
[[package]]
|
|
172
|
-
name = "
|
|
173
|
-
version = "
|
|
154
|
+
name = "globset"
|
|
155
|
+
version = "0.4.18"
|
|
174
156
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
175
|
-
checksum = "
|
|
157
|
+
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
|
158
|
+
dependencies = [
|
|
159
|
+
"aho-corasick",
|
|
160
|
+
"bstr",
|
|
161
|
+
"log",
|
|
162
|
+
"regex-automata",
|
|
163
|
+
"regex-syntax",
|
|
164
|
+
]
|
|
176
165
|
|
|
177
166
|
[[package]]
|
|
178
|
-
name = "
|
|
179
|
-
version = "0.
|
|
167
|
+
name = "ignore"
|
|
168
|
+
version = "0.4.25"
|
|
180
169
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
181
|
-
checksum = "
|
|
170
|
+
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
|
|
182
171
|
dependencies = [
|
|
183
|
-
"crossbeam",
|
|
184
|
-
"
|
|
172
|
+
"crossbeam-deque",
|
|
173
|
+
"globset",
|
|
174
|
+
"log",
|
|
175
|
+
"memchr",
|
|
176
|
+
"regex-automata",
|
|
177
|
+
"same-file",
|
|
178
|
+
"walkdir",
|
|
179
|
+
"winapi-util",
|
|
185
180
|
]
|
|
186
181
|
|
|
182
|
+
[[package]]
|
|
183
|
+
name = "itoa"
|
|
184
|
+
version = "1.0.17"
|
|
185
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
|
+
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
|
187
|
+
|
|
187
188
|
[[package]]
|
|
188
189
|
name = "lexopt"
|
|
189
190
|
version = "0.3.1"
|
|
190
191
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
191
192
|
checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7"
|
|
192
193
|
|
|
194
|
+
[[package]]
|
|
195
|
+
name = "log"
|
|
196
|
+
version = "0.4.29"
|
|
197
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
198
|
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|
199
|
+
|
|
193
200
|
[[package]]
|
|
194
201
|
name = "memchr"
|
|
195
202
|
version = "2.7.6"
|
|
@@ -233,25 +240,34 @@ dependencies = [
|
|
|
233
240
|
]
|
|
234
241
|
|
|
235
242
|
[[package]]
|
|
236
|
-
name = "
|
|
237
|
-
version = "1.
|
|
243
|
+
name = "regex"
|
|
244
|
+
version = "1.12.3"
|
|
238
245
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
239
|
-
checksum = "
|
|
246
|
+
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
|
240
247
|
dependencies = [
|
|
241
|
-
"
|
|
242
|
-
"
|
|
248
|
+
"aho-corasick",
|
|
249
|
+
"memchr",
|
|
250
|
+
"regex-automata",
|
|
251
|
+
"regex-syntax",
|
|
243
252
|
]
|
|
244
253
|
|
|
245
254
|
[[package]]
|
|
246
|
-
name = "
|
|
247
|
-
version = "
|
|
255
|
+
name = "regex-automata"
|
|
256
|
+
version = "0.4.14"
|
|
248
257
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
249
|
-
checksum = "
|
|
258
|
+
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
|
250
259
|
dependencies = [
|
|
251
|
-
"
|
|
252
|
-
"
|
|
260
|
+
"aho-corasick",
|
|
261
|
+
"memchr",
|
|
262
|
+
"regex-syntax",
|
|
253
263
|
]
|
|
254
264
|
|
|
265
|
+
[[package]]
|
|
266
|
+
name = "regex-syntax"
|
|
267
|
+
version = "0.8.9"
|
|
268
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
269
|
+
checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
|
|
270
|
+
|
|
255
271
|
[[package]]
|
|
256
272
|
name = "repokit"
|
|
257
273
|
version = "0.1.0"
|
|
@@ -259,13 +275,22 @@ dependencies = [
|
|
|
259
275
|
"alphanumeric-sort",
|
|
260
276
|
"colored",
|
|
261
277
|
"futures",
|
|
262
|
-
"
|
|
278
|
+
"ignore",
|
|
263
279
|
"lexopt",
|
|
264
280
|
"normalize-path",
|
|
281
|
+
"regex",
|
|
265
282
|
"serde",
|
|
266
283
|
"serde_json",
|
|
267
284
|
"tokio",
|
|
268
|
-
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
[[package]]
|
|
288
|
+
name = "same-file"
|
|
289
|
+
version = "1.0.6"
|
|
290
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
291
|
+
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
292
|
+
dependencies = [
|
|
293
|
+
"winapi-util",
|
|
269
294
|
]
|
|
270
295
|
|
|
271
296
|
[[package]]
|
|
@@ -338,19 +363,29 @@ dependencies = [
|
|
|
338
363
|
]
|
|
339
364
|
|
|
340
365
|
[[package]]
|
|
341
|
-
name = "
|
|
342
|
-
version = "1.0.
|
|
366
|
+
name = "unicode-ident"
|
|
367
|
+
version = "1.0.22"
|
|
368
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
369
|
+
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
|
370
|
+
|
|
371
|
+
[[package]]
|
|
372
|
+
name = "walkdir"
|
|
373
|
+
version = "2.5.0"
|
|
343
374
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
344
|
-
checksum = "
|
|
375
|
+
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
|
345
376
|
dependencies = [
|
|
346
|
-
"
|
|
377
|
+
"same-file",
|
|
378
|
+
"winapi-util",
|
|
347
379
|
]
|
|
348
380
|
|
|
349
381
|
[[package]]
|
|
350
|
-
name = "
|
|
351
|
-
version = "1.
|
|
382
|
+
name = "winapi-util"
|
|
383
|
+
version = "0.1.11"
|
|
352
384
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
353
|
-
checksum = "
|
|
385
|
+
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
|
386
|
+
dependencies = [
|
|
387
|
+
"windows-sys",
|
|
388
|
+
]
|
|
354
389
|
|
|
355
390
|
[[package]]
|
|
356
391
|
name = "windows-link"
|
package/Cargo.toml
CHANGED
|
@@ -14,9 +14,9 @@ colored = "3"
|
|
|
14
14
|
lexopt = "0.3.1"
|
|
15
15
|
normalize-path = "0.2.1"
|
|
16
16
|
futures = "0.3.31"
|
|
17
|
-
jwalk = "0.8.1"
|
|
18
17
|
alphanumeric-sort = "1.5.5"
|
|
19
|
-
tokio-thread-pool = "1.0.0"
|
|
20
18
|
tokio = "1.49.0"
|
|
19
|
+
ignore = "0.4.25"
|
|
20
|
+
regex = { version = "1.12.3", features = ["std", "unicode"] }
|
|
21
21
|
|
|
22
22
|
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
use std::{
|
|
1
|
+
use std::{path::Path, process::exit};
|
|
2
2
|
|
|
3
|
-
use crate::{
|
|
3
|
+
use crate::{
|
|
4
|
+
internal_filesystem::{file_builder::FileBuilder, internal_filesystem::InternalFileSystem},
|
|
5
|
+
logger::logger::Logger,
|
|
6
|
+
};
|
|
4
7
|
|
|
5
8
|
pub struct Configuration;
|
|
6
9
|
|
|
7
10
|
impl Configuration {
|
|
8
11
|
pub fn create(root: &str) {
|
|
9
12
|
let file_path = format!("{root}/repokit.ts");
|
|
10
|
-
let
|
|
11
|
-
if
|
|
13
|
+
let path = Path::new(&file_path);
|
|
14
|
+
if path.exists() {
|
|
12
15
|
return;
|
|
13
16
|
}
|
|
14
17
|
Configuration::welcome();
|
|
15
|
-
let
|
|
18
|
+
let mut source =
|
|
16
19
|
InternalFileSystem::new(root).resolve_template("configuration_template.ts");
|
|
17
|
-
let mut
|
|
18
|
-
|
|
19
|
-
io::copy(&mut source, &mut target).expect("writing");
|
|
20
|
-
target.sync_all().expect("Flushing");
|
|
20
|
+
let mut target = FileBuilder::create(path, |_| Logger::file_create_error());
|
|
21
|
+
FileBuilder::copy_to(&mut source, &mut target, |_| Logger::file_write_error());
|
|
21
22
|
Logger::info(
|
|
22
23
|
format!(
|
|
23
24
|
"Please fill out this file with your desired settings. Then run {}",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pub mod walker;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
fs::File,
|
|
3
|
+
io::{BufRead, BufReader},
|
|
4
|
+
sync::{Arc, Mutex},
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
use ignore::{DirEntry, Error, ParallelVisitor, ParallelVisitorBuilder, WalkState};
|
|
8
|
+
use regex::Regex;
|
|
9
|
+
|
|
10
|
+
use crate::{internal_filesystem::file_builder::FileBuilder, logger::logger::Logger};
|
|
11
|
+
|
|
12
|
+
pub struct TSFileVisitor {
|
|
13
|
+
root: String,
|
|
14
|
+
paths: Arc<Mutex<Vec<String>>>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl ParallelVisitor for TSFileVisitor {
|
|
18
|
+
fn visit(&mut self, entry: Result<DirEntry, Error>) -> WalkState {
|
|
19
|
+
let root_replacer = format!("{}/", self.root);
|
|
20
|
+
let repokit_import_matcher =
|
|
21
|
+
Regex::new(r#"(require\(|from[\s*]?)['"]@repokit/core["'][\)]?[;]?$"#).unwrap();
|
|
22
|
+
let template_matcher = Regex::new(r"externals\/templates\/[^\s]*?_template\.ts$").unwrap();
|
|
23
|
+
if let Ok(entry) = entry {
|
|
24
|
+
let path = entry.path();
|
|
25
|
+
let path_string = path.to_str().map_or("", |f| f);
|
|
26
|
+
if entry.file_type().is_some_and(|ft| ft.is_file())
|
|
27
|
+
&& path_string.ends_with(".ts")
|
|
28
|
+
&& !template_matcher.is_match(path_string)
|
|
29
|
+
{
|
|
30
|
+
let mut open_comment = false;
|
|
31
|
+
let file: File = FileBuilder::open(path_string, |_| Logger::open_file_error());
|
|
32
|
+
let reader: BufReader<File> = BufReader::new(file);
|
|
33
|
+
for line_result in reader.lines() {
|
|
34
|
+
let unwrapped = line_result.unwrap();
|
|
35
|
+
let line = unwrapped.trim();
|
|
36
|
+
if !open_comment && line.starts_with("/**") {
|
|
37
|
+
open_comment = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if open_comment {
|
|
41
|
+
if line == "*/" {
|
|
42
|
+
open_comment = false;
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if repokit_import_matcher.is_match(line) {
|
|
47
|
+
let mut vector = self.paths.lock().unwrap();
|
|
48
|
+
vector.push(path_string.to_string().replace(&root_replacer, ""));
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
if !line.is_empty()
|
|
52
|
+
&& !line.starts_with("import ")
|
|
53
|
+
&& !line.contains("require(")
|
|
54
|
+
&& !(line.starts_with("//") || line.starts_with("/*"))
|
|
55
|
+
{
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
WalkState::Continue
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
pub struct TSFileVisitorBuilder<'a> {
|
|
66
|
+
pub root: &'a str,
|
|
67
|
+
pub paths: &'a Arc<Mutex<Vec<String>>>,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
impl<'a> TSFileVisitorBuilder<'a> {
|
|
71
|
+
pub fn new(root: &'a str, paths: &'a Arc<Mutex<Vec<String>>>) -> TSFileVisitorBuilder<'a> {
|
|
72
|
+
TSFileVisitorBuilder { paths, root }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
impl<'s> ParallelVisitorBuilder<'s> for TSFileVisitorBuilder<'s> {
|
|
77
|
+
fn build(&mut self) -> Box<dyn ParallelVisitor + 's> {
|
|
78
|
+
Box::new(TSFileVisitor {
|
|
79
|
+
paths: self.paths.clone(),
|
|
80
|
+
root: self.root.to_string(),
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -145,7 +145,14 @@ impl Help {
|
|
|
145
145
|
sort_str_slice(&mut vector);
|
|
146
146
|
vector
|
|
147
147
|
.iter()
|
|
148
|
-
.map(|&name|
|
|
148
|
+
.map(|&name| {
|
|
149
|
+
RootCommand::from(
|
|
150
|
+
name,
|
|
151
|
+
commands
|
|
152
|
+
.get(name)
|
|
153
|
+
.expect("iteration is over known keys only"),
|
|
154
|
+
)
|
|
155
|
+
})
|
|
149
156
|
.collect()
|
|
150
157
|
}
|
|
151
158
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
use normalize_path::NormalizePath;
|
|
2
2
|
use std::{
|
|
3
3
|
collections::HashMap,
|
|
4
|
-
fs::{File, create_dir_all},
|
|
5
|
-
io,
|
|
6
4
|
path::{Path, PathBuf},
|
|
7
5
|
process,
|
|
8
6
|
};
|
|
@@ -15,7 +13,7 @@ use crate::{
|
|
|
15
13
|
},
|
|
16
14
|
},
|
|
17
15
|
internal_commands::help::Help,
|
|
18
|
-
internal_filesystem::internal_filesystem::InternalFileSystem,
|
|
16
|
+
internal_filesystem::{file_builder::FileBuilder, internal_filesystem::InternalFileSystem},
|
|
19
17
|
logger::logger::Logger,
|
|
20
18
|
};
|
|
21
19
|
|
|
@@ -56,7 +54,7 @@ impl RegisterCommand {
|
|
|
56
54
|
)
|
|
57
55
|
.as_str(),
|
|
58
56
|
);
|
|
59
|
-
create_dir_all(&path
|
|
57
|
+
FileBuilder::create_dir_all(&path, |_| Logger::file_directory_error());
|
|
60
58
|
}
|
|
61
59
|
if !path.is_dir() {
|
|
62
60
|
RegisterCommand::exit_on_missing_path();
|
|
@@ -90,12 +88,10 @@ impl InternalExecutable for RegisterCommand {
|
|
|
90
88
|
fn run(&self, args: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
91
89
|
Logger::info("Registering a new command");
|
|
92
90
|
let command_path = self.validate_path(args);
|
|
93
|
-
let
|
|
91
|
+
let mut source =
|
|
94
92
|
InternalFileSystem::new(&self.scope.root).resolve_template("command_template.ts");
|
|
95
|
-
let mut
|
|
96
|
-
|
|
97
|
-
io::copy(&mut source, &mut target).expect("writing");
|
|
98
|
-
target.sync_all().expect("Flushing");
|
|
93
|
+
let mut target = FileBuilder::create(&command_path, |_| Logger::file_create_error());
|
|
94
|
+
FileBuilder::copy_to(&mut source, &mut target, |_| Logger::file_write_error());
|
|
99
95
|
Logger::info("Creating command file");
|
|
100
96
|
Logger::info("Please fill out your command file located at:");
|
|
101
97
|
Logger::log_file_path(command_path.to_str().expect("path"));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use std::path::Path;
|
|
1
|
+
use std::{path::Path, process::exit, sync::MutexGuard};
|
|
2
2
|
|
|
3
3
|
use serde_json::from_str;
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ use crate::{
|
|
|
6
6
|
configuration::configuration::Configuration,
|
|
7
7
|
executor::executor::Executor,
|
|
8
8
|
internal_filesystem::internal_filesystem::InternalFileSystem,
|
|
9
|
+
logger::logger::Logger,
|
|
9
10
|
repokit::interfaces::{RepoKitCommand, RepoKitConfig},
|
|
10
11
|
};
|
|
11
12
|
|
|
@@ -31,13 +32,23 @@ impl TypescriptCommand {
|
|
|
31
32
|
config
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
pub fn parse_commands(&self, path_list: Vec<String
|
|
35
|
+
pub fn parse_commands(&self, path_list: &MutexGuard<Vec<String>>) -> Vec<RepoKitCommand> {
|
|
35
36
|
let paths = path_list.join(",");
|
|
36
37
|
let executable = InternalFileSystem::new(&self.root).resolve_command("parse_commands.ts");
|
|
37
38
|
let stdout =
|
|
38
39
|
self.execute(format!("{executable} --paths {paths} --root {}", self.root).as_str());
|
|
39
|
-
let
|
|
40
|
-
|
|
40
|
+
let result: Result<Vec<RepoKitCommand>, serde_json::Error> = serde_json::from_str(&stdout);
|
|
41
|
+
match result {
|
|
42
|
+
Ok(commands) => commands,
|
|
43
|
+
Err(_) => {
|
|
44
|
+
Logger::info("There was an error parsing one of your commands");
|
|
45
|
+
Logger::info(
|
|
46
|
+
"You can validate a command file's syntactical correctness by running",
|
|
47
|
+
);
|
|
48
|
+
Logger::log_file_path("tsc --noEmit");
|
|
49
|
+
exit(0);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
41
52
|
}
|
|
42
53
|
|
|
43
54
|
fn execute(&self, args: &str) -> String {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
fs::{File, create_dir_all},
|
|
3
|
+
io::{Error, copy},
|
|
4
|
+
path::Path,
|
|
5
|
+
process::exit,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub struct FileBuilder;
|
|
9
|
+
|
|
10
|
+
impl FileBuilder {
|
|
11
|
+
pub fn open(source: &str, on_error: impl Fn(Error)) -> File {
|
|
12
|
+
let source = File::open(source);
|
|
13
|
+
match source {
|
|
14
|
+
Ok(file) => file,
|
|
15
|
+
Err(error) => {
|
|
16
|
+
on_error(error);
|
|
17
|
+
exit(0);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub fn create(destination: &Path, on_error: impl Fn(Error)) -> File {
|
|
23
|
+
let source = File::create(destination);
|
|
24
|
+
match source {
|
|
25
|
+
Ok(file) => file,
|
|
26
|
+
Err(error) => {
|
|
27
|
+
on_error(error);
|
|
28
|
+
exit(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn copy_to(source: &mut File, target: &mut File, on_error: impl Fn(Error)) {
|
|
34
|
+
let result = copy(source, target);
|
|
35
|
+
match result {
|
|
36
|
+
Ok(_) => {
|
|
37
|
+
let sync = target.sync_all();
|
|
38
|
+
match sync {
|
|
39
|
+
Ok(_) => {}
|
|
40
|
+
Err(err) => on_error(err),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
Err(err) => on_error(err),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn create_dir_all(path: &Path, on_error: impl Fn(Error)) {
|
|
48
|
+
let source = create_dir_all(path);
|
|
49
|
+
match source {
|
|
50
|
+
Ok(result) => result,
|
|
51
|
+
Err(error) => {
|
|
52
|
+
on_error(error);
|
|
53
|
+
exit(0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
use normalize_path::NormalizePath;
|
|
2
|
-
use std::
|
|
2
|
+
use std::{
|
|
3
|
+
fs::File,
|
|
4
|
+
path::{Path, PathBuf},
|
|
5
|
+
};
|
|
3
6
|
|
|
4
|
-
use crate::{
|
|
7
|
+
use crate::{
|
|
8
|
+
executor::executor::Executor, internal_filesystem::file_builder::FileBuilder,
|
|
9
|
+
logger::logger::Logger,
|
|
10
|
+
};
|
|
5
11
|
|
|
6
12
|
pub struct InternalFileSystem {
|
|
7
13
|
root: String,
|
|
@@ -23,8 +29,13 @@ impl InternalFileSystem {
|
|
|
23
29
|
self.path_buf_to_str(self.commands_directory().join(file_name))
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
pub fn resolve_template(&self, file_name: &str) ->
|
|
27
|
-
self.path_buf_to_str(self.templates_directory().join(file_name))
|
|
32
|
+
pub fn resolve_template(&self, file_name: &str) -> File {
|
|
33
|
+
let path = self.path_buf_to_str(self.templates_directory().join(file_name));
|
|
34
|
+
FileBuilder::open(&path, |_| {
|
|
35
|
+
Logger::error(format!("Unable to locate internal {file_name}").as_str());
|
|
36
|
+
Logger::error("Please file a bug here");
|
|
37
|
+
Logger::log_issue_link();
|
|
38
|
+
})
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
pub fn find_root() -> String {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
use std::process::exit;
|
|
2
|
+
use std::sync::LazyLock;
|
|
1
3
|
use std::sync::Mutex;
|
|
2
|
-
use std::{process, sync::LazyLock};
|
|
3
4
|
|
|
4
5
|
use colored::{ColoredString, Colorize, CustomColor};
|
|
5
6
|
|
|
@@ -23,12 +24,12 @@ impl Logger {
|
|
|
23
24
|
|
|
24
25
|
pub fn exit_with_info(message: &str) {
|
|
25
26
|
Logger::info(message);
|
|
26
|
-
|
|
27
|
+
exit(0);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
pub fn exit_with_error(message: &str) {
|
|
30
31
|
Logger::error(message);
|
|
31
|
-
|
|
32
|
+
exit(0);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
pub fn space_around(message: &str) {
|
|
@@ -92,6 +93,33 @@ impl Logger {
|
|
|
92
93
|
})
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
pub fn file_create_error() {
|
|
97
|
+
Logger::file_error("create a file");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
pub fn file_directory_error() {
|
|
101
|
+
Logger::file_error("create a directory");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
pub fn open_file_error() {
|
|
105
|
+
Logger::file_error("read a file");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub fn file_write_error() {
|
|
109
|
+
Logger::file_error("write to a file");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub fn log_issue_link() {
|
|
113
|
+
Logger::log_file_path("https://github.com/alexfigliolia/repokit/issues");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fn file_error(operation: &str) {
|
|
117
|
+
Logger::info(format!("I was unable to {operation} in your repository").as_str());
|
|
118
|
+
Logger::error("Please verify the permissions on your working directory or file a bug here");
|
|
119
|
+
Logger::log_issue_link();
|
|
120
|
+
exit(0);
|
|
121
|
+
}
|
|
122
|
+
|
|
95
123
|
fn info_prefix() -> ColoredString {
|
|
96
124
|
format!("{}: ", *REGISTERED_NAME.lock().unwrap())
|
|
97
125
|
.bright_magenta()
|
package/internals/main.rs
CHANGED
|
@@ -36,7 +36,7 @@ impl RepoKit {
|
|
|
36
36
|
let validator = CommandValidations::from(self);
|
|
37
37
|
let internals = validator.collect_and_validate_internals();
|
|
38
38
|
if internals.contains_key(&command) {
|
|
39
|
-
let interface = internals.get(&command).expect("
|
|
39
|
+
let interface = internals.get(&command).expect("Unknown command");
|
|
40
40
|
return interface.run(args, &internals);
|
|
41
41
|
}
|
|
42
42
|
if self.scope.configuration.commands.contains_key(&command) {
|
|
@@ -45,7 +45,7 @@ impl RepoKit {
|
|
|
45
45
|
.configuration
|
|
46
46
|
.commands
|
|
47
47
|
.get(&command)
|
|
48
|
-
.expect("
|
|
48
|
+
.expect("Unknown command");
|
|
49
49
|
return Executor::with_stdio(
|
|
50
50
|
format!("{} {}", root_script.command, &args.join(" ")),
|
|
51
51
|
|cmd| cmd.current_dir(Path::new(&self.scope.root)),
|
|
@@ -56,14 +56,16 @@ impl RepoKit {
|
|
|
56
56
|
&internals, &externals,
|
|
57
57
|
);
|
|
58
58
|
if externals.contains_key(&command) {
|
|
59
|
-
let interface = externals.get(&command).expect("
|
|
59
|
+
let interface = externals.get(&command).expect("Unknown command");
|
|
60
60
|
if args.is_empty() {
|
|
61
61
|
return self.log_external_command(interface);
|
|
62
62
|
}
|
|
63
63
|
let sub_command = &args[0];
|
|
64
64
|
if interface.commands.contains_key(sub_command) {
|
|
65
|
-
let script = interface.commands.get(sub_command).expect("
|
|
66
|
-
let working_dir = Path::new(&interface.location)
|
|
65
|
+
let script = interface.commands.get(sub_command).expect("Unknown script");
|
|
66
|
+
let working_dir = Path::new(&interface.location)
|
|
67
|
+
.parent()
|
|
68
|
+
.expect("Working directory not found");
|
|
67
69
|
return Executor::with_stdio(
|
|
68
70
|
format!("{} {}", &script.command, &args[1..].join(" ")),
|
|
69
71
|
|cmd| cmd.current_dir(working_dir),
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
use std::
|
|
1
|
+
use std::{
|
|
2
|
+
collections::HashMap,
|
|
3
|
+
sync::{Arc, Mutex},
|
|
4
|
+
};
|
|
2
5
|
|
|
3
|
-
use
|
|
6
|
+
use ignore::WalkBuilder;
|
|
4
7
|
|
|
5
8
|
use crate::{
|
|
6
9
|
executables::{
|
|
7
10
|
intenal_executable::InternalExecutable, internal_executable_definition::RepoKitScope,
|
|
8
11
|
},
|
|
9
|
-
|
|
10
|
-
internal_commands::
|
|
12
|
+
file_walker::walker::TSFileVisitorBuilder,
|
|
13
|
+
internal_commands::{
|
|
14
|
+
internal_registry::InternalRegistry, typescript_command::TypescriptCommand,
|
|
15
|
+
},
|
|
11
16
|
logger::logger::Logger,
|
|
12
17
|
repokit::{interfaces::RepoKitCommand, repokit::RepoKit},
|
|
13
18
|
};
|
|
@@ -36,8 +41,13 @@ impl CommandValidations {
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
pub fn collect_and_validate_externals(&self) -> HashMap<String, RepoKitCommand> {
|
|
39
|
-
let
|
|
40
|
-
let
|
|
44
|
+
let paths: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
|
|
45
|
+
let mut visitor = TSFileVisitorBuilder::new(&self.scope.root, &paths);
|
|
46
|
+
WalkBuilder::new(&self.scope.root)
|
|
47
|
+
.build_parallel()
|
|
48
|
+
.visit(&mut visitor);
|
|
49
|
+
let result = paths.lock().unwrap();
|
|
50
|
+
let externals = TypescriptCommand::new(&self.scope.root).parse_commands(&result);
|
|
41
51
|
let all = [&externals[..], &self.scope.configuration.thirdParty[..]].concat();
|
|
42
52
|
self.detect_collisions_between_root_commands_and_externals(&all)
|
|
43
53
|
}
|
|
@@ -88,7 +98,7 @@ impl CommandValidations {
|
|
|
88
98
|
let mut map: HashMap<String, RepoKitCommand> = HashMap::new();
|
|
89
99
|
for command in externals {
|
|
90
100
|
if map.contains_key(&command.name) {
|
|
91
|
-
let original = map.get(&command.name).expect("
|
|
101
|
+
let original = map.get(&command.name).expect("Unknown command");
|
|
92
102
|
self.on_external_duplicate_collision(command, &original.location);
|
|
93
103
|
}
|
|
94
104
|
map.insert(command.name.clone(), command.clone());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repokit/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "A knowledgebase for your repository - wrapped in a CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^25.2.1",
|
|
40
|
-
"oxfmt": "^0.
|
|
40
|
+
"oxfmt": "^0.33.0",
|
|
41
41
|
"oxlint": "^1.42.0",
|
|
42
|
-
"oxlint-tsgolint": "^0.
|
|
42
|
+
"oxlint-tsgolint": "^0.14.0",
|
|
43
43
|
"typescript": "^5.9.3"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
use std::{
|
|
2
|
-
fs::File,
|
|
3
|
-
io::{BufRead, BufReader},
|
|
4
|
-
path::Path,
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
use futures::{TryStreamExt, stream::FuturesUnordered};
|
|
8
|
-
use jwalk::WalkDir;
|
|
9
|
-
use tokio_thread_pool::ThreadPool;
|
|
10
|
-
|
|
11
|
-
use crate::{
|
|
12
|
-
internal_commands::typescript_command::TypescriptCommand, repokit::interfaces::RepoKitCommand,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
pub struct ExternalCommands {
|
|
16
|
-
pub root: String,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
impl ExternalCommands {
|
|
20
|
-
pub fn new(root: &str) -> ExternalCommands {
|
|
21
|
-
ExternalCommands {
|
|
22
|
-
root: root.to_string(),
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
pub async fn find_all(&self) -> Vec<RepoKitCommand> {
|
|
27
|
-
let mut futures = FuturesUnordered::new();
|
|
28
|
-
let mut pool = ThreadPool::new(None, None, None);
|
|
29
|
-
for entry in WalkDir::new(&self.root).into_iter().filter_map(|e| {
|
|
30
|
-
if e.is_err() {
|
|
31
|
-
return None;
|
|
32
|
-
}
|
|
33
|
-
let option = e.ok();
|
|
34
|
-
match option {
|
|
35
|
-
Some(file) => {
|
|
36
|
-
let path = file.path();
|
|
37
|
-
if file.file_type().is_file()
|
|
38
|
-
&& path.extension().is_some_and(|ext| ext == "ts")
|
|
39
|
-
&& self.allowed(path.to_str().expect("exists"))
|
|
40
|
-
{
|
|
41
|
-
return Some(file);
|
|
42
|
-
}
|
|
43
|
-
None
|
|
44
|
-
}
|
|
45
|
-
None => None,
|
|
46
|
-
}
|
|
47
|
-
}) {
|
|
48
|
-
let path = entry.path();
|
|
49
|
-
futures.push(pool.spawn(move || {
|
|
50
|
-
if ExternalCommands::read(&path) {
|
|
51
|
-
return Some(path.clone());
|
|
52
|
-
}
|
|
53
|
-
None
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
let mut paths: Vec<String> = Vec::new();
|
|
57
|
-
while let Ok(Some(buffer)) = futures.try_next().await {
|
|
58
|
-
if let Some(path) = buffer {
|
|
59
|
-
paths.push(
|
|
60
|
-
(path)
|
|
61
|
-
.into_os_string()
|
|
62
|
-
.into_string()
|
|
63
|
-
.expect("stringify")
|
|
64
|
-
.replace(&self.root, ""),
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
pool.pool.shutdown_background();
|
|
69
|
-
TypescriptCommand::new(&self.root).parse_commands(paths)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
fn read(path: &Path) -> bool {
|
|
73
|
-
let file: File = File::open(path).expect("file");
|
|
74
|
-
let reader: BufReader<File> = BufReader::new(file);
|
|
75
|
-
for line_result in reader.lines() {
|
|
76
|
-
let line: String = line_result.expect("line");
|
|
77
|
-
if line.ends_with("\"@repokit/core\";") || line.ends_with("'@repokit/core';") {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
false
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
fn allowed(&self, path: &str) -> bool {
|
|
85
|
-
let restricted_paths = ["node_modules", "target", "dist"];
|
|
86
|
-
let restricted_extensions = ["templates/command_template.ts"];
|
|
87
|
-
let relative_path = path.replace(format!("{}/", &self.root).as_str(), "");
|
|
88
|
-
if ExternalCommands::restrict(
|
|
89
|
-
&relative_path,
|
|
90
|
-
&restricted_paths,
|
|
91
|
-
RestrictDirection::Forwards,
|
|
92
|
-
) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
if ExternalCommands::restrict(
|
|
96
|
-
&relative_path,
|
|
97
|
-
&restricted_extensions,
|
|
98
|
-
RestrictDirection::Backwards,
|
|
99
|
-
) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
let components = relative_path.split('/');
|
|
103
|
-
for token in components {
|
|
104
|
-
for restricted_path in restricted_paths {
|
|
105
|
-
if token == restricted_path {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
true
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
fn restrict(path: &str, tokens: &[&str], direction: RestrictDirection) -> bool {
|
|
114
|
-
for restricted in tokens {
|
|
115
|
-
match direction {
|
|
116
|
-
RestrictDirection::Forwards => {
|
|
117
|
-
if path.starts_with(restricted) {
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
RestrictDirection::Backwards => {
|
|
122
|
-
if path.ends_with(restricted) {
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
false
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
enum RestrictDirection {
|
|
133
|
-
Forwards,
|
|
134
|
-
Backwards,
|
|
135
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
pub mod external_commands;
|