@repokit/core 0.0.1
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/.vscode/settings.json +11 -0
- package/Cargo.lock +517 -0
- package/Cargo.toml +26 -0
- package/README.md +204 -0
- package/dist/cjs/CommandParser.js +68 -0
- package/dist/cjs/ConfigurationParser.js +46 -0
- package/dist/cjs/RepoKitCommand.js +16 -0
- package/dist/cjs/RepoKitConfig.js +10 -0
- package/dist/cjs/TaskPooler.js +42 -0
- package/dist/cjs/commands/parse_commands.js +15 -0
- package/dist/cjs/commands/parse_configuration.js +15 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/types.js +2 -0
- package/dist/mjs/CommandParser.js +51 -0
- package/dist/mjs/ConfigurationParser.js +31 -0
- package/dist/mjs/RepoKitCommand.js +16 -0
- package/dist/mjs/RepoKitConfig.js +8 -0
- package/dist/mjs/TaskPooler.js +28 -0
- package/dist/mjs/commands/parse_commands.js +4 -0
- package/dist/mjs/commands/parse_configuration.js +4 -0
- package/dist/mjs/index.js +3 -0
- package/dist/mjs/package.json +4 -0
- package/dist/mjs/types.js +1 -0
- package/dist/types/CommandParser.d.ts +5 -0
- package/dist/types/ConfigurationParser.d.ts +4 -0
- package/dist/types/RepoKitCommand.d.ts +14 -0
- package/dist/types/RepoKitConfig.d.ts +6 -0
- package/dist/types/TaskPooler.d.ts +10 -0
- package/dist/types/commands/parse_commands.d.ts +1 -0
- package/dist/types/commands/parse_configuration.d.ts +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/types.d.ts +18 -0
- package/install.sh +43 -0
- package/package.json +40 -0
- package/repokit.ts +36 -0
- package/src/CommandParser.ts +59 -0
- package/src/ConfigurationParser.ts +34 -0
- package/src/RepoKitCommand.ts +24 -0
- package/src/RepoKitConfig.ts +10 -0
- package/src/TaskPooler.ts +31 -0
- package/src/commands/parse_commands.ts +5 -0
- package/src/commands/parse_configuration.ts +5 -0
- package/src/index.ts +3 -0
- package/src/types.ts +22 -0
- package/tsconfig.json +24 -0
- package/workspaces/concurrency/mod.rs +1 -0
- package/workspaces/concurrency/thread_pool.rs +32 -0
- package/workspaces/configuration/configuration.rs +47 -0
- package/workspaces/configuration/configuration_template.ts +23 -0
- package/workspaces/configuration/mod.rs +1 -0
- package/workspaces/executables/external_executable.rs +4 -0
- package/workspaces/executables/intenal_executable.rs +9 -0
- package/workspaces/executables/internal_executable_definition.rs +8 -0
- package/workspaces/executables/mod.rs +3 -0
- package/workspaces/executor/executor.rs +62 -0
- package/workspaces/executor/mod.rs +1 -0
- package/workspaces/external_commands/external_commands.rs +125 -0
- package/workspaces/external_commands/mod.rs +1 -0
- package/workspaces/internal_commands/command_template.ts +24 -0
- package/workspaces/internal_commands/help.rs +146 -0
- package/workspaces/internal_commands/internal_registry.rs +59 -0
- package/workspaces/internal_commands/list_commands.rs +106 -0
- package/workspaces/internal_commands/list_owners.rs +74 -0
- package/workspaces/internal_commands/locate_command.rs +78 -0
- package/workspaces/internal_commands/mod.rs +10 -0
- package/workspaces/internal_commands/onboarder.rs +66 -0
- package/workspaces/internal_commands/register_command.rs +117 -0
- package/workspaces/internal_commands/search_commands.rs +189 -0
- package/workspaces/internal_commands/typescript_command.rs +63 -0
- package/workspaces/internal_commands/upgrade_repokit.rs +76 -0
- package/workspaces/logger/logger.rs +98 -0
- package/workspaces/logger/mod.rs +1 -0
- package/workspaces/main.rs +21 -0
- package/workspaces/repokit/interfaces.rs +41 -0
- package/workspaces/repokit/mod.rs +2 -0
- package/workspaces/repokit/repokit.rs +141 -0
- package/workspaces/validations/command_validations.rs +140 -0
- package/workspaces/validations/mod.rs +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
fs::File,
|
|
3
|
+
io::{BufRead, BufReader},
|
|
4
|
+
path::Path,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
use jwalk::WalkDir;
|
|
8
|
+
|
|
9
|
+
use crate::{
|
|
10
|
+
concurrency::thread_pool::ThreadPool, internal_commands::typescript_command::TypescriptCommand,
|
|
11
|
+
repokit::interfaces::RepoKitCommand,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
pub struct ExternalCommands {
|
|
15
|
+
pub root: String,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl ExternalCommands {
|
|
19
|
+
pub fn new(root: String) -> ExternalCommands {
|
|
20
|
+
ExternalCommands { root }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub async fn find_all(&self) -> Vec<RepoKitCommand> {
|
|
24
|
+
let mut paths: Vec<String> = vec![];
|
|
25
|
+
let mut pool = ThreadPool::new(None, None);
|
|
26
|
+
for entry in WalkDir::new(&self.root).into_iter().filter_map(|e| {
|
|
27
|
+
if e.is_err() {
|
|
28
|
+
return None;
|
|
29
|
+
}
|
|
30
|
+
let option = e.ok();
|
|
31
|
+
match option {
|
|
32
|
+
Some(file) => {
|
|
33
|
+
let path = file.path();
|
|
34
|
+
if file.file_type().is_file()
|
|
35
|
+
&& path.extension().is_some_and(|ext| ext == "ts")
|
|
36
|
+
&& self.allowed(path.to_str().expect("exists"))
|
|
37
|
+
{
|
|
38
|
+
return Some(file);
|
|
39
|
+
}
|
|
40
|
+
None
|
|
41
|
+
}
|
|
42
|
+
None => None,
|
|
43
|
+
}
|
|
44
|
+
}) {
|
|
45
|
+
let path = entry.path();
|
|
46
|
+
let clone = path.clone();
|
|
47
|
+
let async_task = pool.spawn(move || ExternalCommands::read(&path));
|
|
48
|
+
if async_task.await.unwrap() {
|
|
49
|
+
paths.push(
|
|
50
|
+
(clone)
|
|
51
|
+
.into_os_string()
|
|
52
|
+
.into_string()
|
|
53
|
+
.expect("stringify")
|
|
54
|
+
.replace(&self.root, ""),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
pool.pool.shutdown_background();
|
|
59
|
+
TypescriptCommand::new(self.root.clone()).parse_commands(paths)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn read(path: &Path) -> bool {
|
|
63
|
+
let file: File = File::open(path).expect("file");
|
|
64
|
+
let reader: BufReader<File> = BufReader::new(file);
|
|
65
|
+
for line_result in reader.lines() {
|
|
66
|
+
let line: String = line_result.expect("line");
|
|
67
|
+
if line.contains("new RepoKitCommand(") {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn allowed(&self, path: &str) -> bool {
|
|
75
|
+
let restricted_paths = ["node_modules", "target", "dist"];
|
|
76
|
+
let restricted_extensions = ["internal_commands/command_template.ts"];
|
|
77
|
+
let relative_path = path.replace(format!("{}/", &self.root).as_str(), "");
|
|
78
|
+
if ExternalCommands::restrict(
|
|
79
|
+
&relative_path,
|
|
80
|
+
&restricted_paths,
|
|
81
|
+
RestrictDirection::Forwards,
|
|
82
|
+
) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if ExternalCommands::restrict(
|
|
86
|
+
&relative_path,
|
|
87
|
+
&restricted_extensions,
|
|
88
|
+
RestrictDirection::Backwards,
|
|
89
|
+
) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
let components = relative_path.split('/');
|
|
93
|
+
for token in components {
|
|
94
|
+
for restricted_path in restricted_paths {
|
|
95
|
+
if token == restricted_path {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fn restrict(path: &str, tokens: &[&str], direction: RestrictDirection) -> bool {
|
|
104
|
+
for restricted in tokens {
|
|
105
|
+
match direction {
|
|
106
|
+
RestrictDirection::Forwards => {
|
|
107
|
+
if path.starts_with(restricted) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
RestrictDirection::Backwards => {
|
|
112
|
+
if path.ends_with(restricted) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
enum RestrictDirection {
|
|
123
|
+
Forwards,
|
|
124
|
+
Backwards,
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pub mod external_commands;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RepoKitCommand } from "@repokit/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Please fill out this command file with your desired settings
|
|
5
|
+
*/
|
|
6
|
+
export const Commands = new RepoKitCommand({
|
|
7
|
+
name: "<Your Package Name>",
|
|
8
|
+
owner: "<Optional Team or Individual>",
|
|
9
|
+
description: "<Your Package Description>",
|
|
10
|
+
commands: {
|
|
11
|
+
"<your-first-command>": {
|
|
12
|
+
command: "<insert shell command here>",
|
|
13
|
+
description: "A description for using your command",
|
|
14
|
+
},
|
|
15
|
+
"<your-second-command>": {
|
|
16
|
+
command: "<insert shell command here>",
|
|
17
|
+
description: "A description for using your command",
|
|
18
|
+
},
|
|
19
|
+
"<your-third-command>": {
|
|
20
|
+
command: "<insert shell command here>",
|
|
21
|
+
description: "A description for using your command",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use alphanumeric_sort::{sort_slice_by_str_key, sort_str_slice};
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
repokit::interfaces::{Command, RepoKitCommand, ParsedCommand},
|
|
7
|
+
executables::{
|
|
8
|
+
intenal_executable::InternalExecutable,
|
|
9
|
+
internal_executable_definition::InternalExecutableDefinition,
|
|
10
|
+
},
|
|
11
|
+
logger::logger::Logger,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
pub struct Help;
|
|
15
|
+
|
|
16
|
+
impl Help {
|
|
17
|
+
pub fn list_all(
|
|
18
|
+
root_commands: &HashMap<String, Command>,
|
|
19
|
+
internals: &HashMap<String, Box<dyn InternalExecutable>>,
|
|
20
|
+
externals: &HashMap<String, RepoKitCommand>,
|
|
21
|
+
) {
|
|
22
|
+
Help::log_internal_commands(internals);
|
|
23
|
+
Help::log_root_commands(root_commands);
|
|
24
|
+
Help::log_external_commands(externals);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn log_internal_command(command: &InternalExecutableDefinition) {
|
|
28
|
+
println!(
|
|
29
|
+
"{}{} {}",
|
|
30
|
+
Logger::indent(Some(3)),
|
|
31
|
+
Logger::blue_bright(command.name),
|
|
32
|
+
Logger::gray(command.description),
|
|
33
|
+
);
|
|
34
|
+
Help::print_args(&command.args);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub fn log_root_command(command: &ParsedCommand) {
|
|
38
|
+
println!(
|
|
39
|
+
"{}{} {}",
|
|
40
|
+
Logger::indent(Some(3)),
|
|
41
|
+
Logger::blue(&command.name),
|
|
42
|
+
Logger::gray(&command.description),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub fn log_external_command(command: &RepoKitCommand) {
|
|
47
|
+
println!(
|
|
48
|
+
"{}{} {}",
|
|
49
|
+
Logger::indent(Some(3)),
|
|
50
|
+
Logger::blue_bright(&command.name),
|
|
51
|
+
Logger::gray(&command.description),
|
|
52
|
+
);
|
|
53
|
+
Help::print_commands(&command.commands, Some(6));
|
|
54
|
+
if !command.owner.is_empty() {
|
|
55
|
+
println!(
|
|
56
|
+
"\n{}{}{}",
|
|
57
|
+
Logger::indent(Some(9)),
|
|
58
|
+
Logger::gray("Owned by: "),
|
|
59
|
+
Logger::cyan(&command.owner),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
pub fn print_commands(map: &HashMap<String, Command>, indentation: Option<i32>) {
|
|
65
|
+
for (name, command) in map {
|
|
66
|
+
println!(
|
|
67
|
+
"{}{}{}",
|
|
68
|
+
Logger::indent(indentation),
|
|
69
|
+
Logger::green(format!("{}: ", name).as_str()),
|
|
70
|
+
Logger::gray(&command.description),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub fn log_internal_commands(internals: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
76
|
+
if internals.is_empty() {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let sorted_internals = Help::sort_internal(internals);
|
|
80
|
+
Logger::space_around("Internal Commands:");
|
|
81
|
+
for internal in sorted_internals {
|
|
82
|
+
Help::log_internal_command(internal.get_definition());
|
|
83
|
+
println!();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub fn log_root_commands(root_commands: &HashMap<String, Command>) {
|
|
88
|
+
if root_commands.is_empty() {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let sorted_commands = Help::sort_root_commands(root_commands);
|
|
92
|
+
Logger::info("Project Level Commands:");
|
|
93
|
+
println!();
|
|
94
|
+
for command in sorted_commands {
|
|
95
|
+
Help::log_root_command(&command);
|
|
96
|
+
}
|
|
97
|
+
println!();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
pub fn log_external_commands(externals: &HashMap<String, RepoKitCommand>) {
|
|
101
|
+
if externals.is_empty() {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let sorted_externals = Help::sort_external(externals);
|
|
105
|
+
Logger::info("Registered Commands:");
|
|
106
|
+
println!();
|
|
107
|
+
for external in sorted_externals {
|
|
108
|
+
Help::log_external_command(external);
|
|
109
|
+
println!();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fn print_args(map: &HashMap<&'static str, &'static str>) {
|
|
114
|
+
for (name, description) in map {
|
|
115
|
+
println!(
|
|
116
|
+
"{}{}{}",
|
|
117
|
+
Logger::indent(Some(6)),
|
|
118
|
+
Logger::green(format!("{}: ", name).as_str()),
|
|
119
|
+
Logger::gray(description),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fn sort_internal(
|
|
125
|
+
commands: &HashMap<String, Box<dyn InternalExecutable>>,
|
|
126
|
+
) -> Vec<&Box<dyn InternalExecutable>> {
|
|
127
|
+
let mut vector: Vec<&Box<dyn InternalExecutable>> = commands.values().collect();
|
|
128
|
+
sort_slice_by_str_key(&mut vector, |x| &x.get_definition().name);
|
|
129
|
+
vector
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fn sort_external(commands: &HashMap<String, RepoKitCommand>) -> Vec<&RepoKitCommand> {
|
|
133
|
+
let mut vector: Vec<&RepoKitCommand> = (commands).values().collect();
|
|
134
|
+
sort_slice_by_str_key(&mut vector, |x| &x.name);
|
|
135
|
+
vector
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fn sort_root_commands(commands: &HashMap<String, Command>) -> Vec<ParsedCommand> {
|
|
139
|
+
let mut vector: Vec<&String> = (commands).keys().collect();
|
|
140
|
+
sort_str_slice(&mut vector);
|
|
141
|
+
vector
|
|
142
|
+
.iter()
|
|
143
|
+
.map(|&name| ParsedCommand::from(name, commands.get(name).expect("known keys only")))
|
|
144
|
+
.collect()
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
executables::intenal_executable::InternalExecutable,
|
|
5
|
+
internal_commands::{
|
|
6
|
+
list_commands::ListCommands, list_owners::ListOwners, locate_command::LocateCommand,
|
|
7
|
+
onboarder::Onboarder, register_command::RegisterCommand, search_commands::SearchCommands,
|
|
8
|
+
upgrade_repokit::UpgradeRepoKit,
|
|
9
|
+
},
|
|
10
|
+
repokit::interfaces::RepoKitConfig,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
pub struct InternalRegistry {
|
|
14
|
+
root: String,
|
|
15
|
+
configuration: RepoKitConfig,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl InternalRegistry {
|
|
19
|
+
pub fn new(root: String, configuration: RepoKitConfig) -> InternalRegistry {
|
|
20
|
+
InternalRegistry {
|
|
21
|
+
root,
|
|
22
|
+
configuration,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn get_all(&self) -> HashMap<String, Box<dyn InternalExecutable>> {
|
|
27
|
+
let internals: [Box<dyn InternalExecutable>; 7] = [
|
|
28
|
+
Box::new(Onboarder::new(
|
|
29
|
+
self.root.clone(),
|
|
30
|
+
self.configuration.clone(),
|
|
31
|
+
)),
|
|
32
|
+
Box::new(ListCommands::new(
|
|
33
|
+
self.root.clone(),
|
|
34
|
+
self.configuration.clone(),
|
|
35
|
+
)),
|
|
36
|
+
Box::new(SearchCommands::new(
|
|
37
|
+
self.root.clone(),
|
|
38
|
+
self.configuration.clone(),
|
|
39
|
+
)),
|
|
40
|
+
Box::new(ListOwners::new(
|
|
41
|
+
self.root.clone(),
|
|
42
|
+
self.configuration.clone(),
|
|
43
|
+
)),
|
|
44
|
+
Box::new(LocateCommand::new(
|
|
45
|
+
self.root.clone(),
|
|
46
|
+
self.configuration.clone(),
|
|
47
|
+
)),
|
|
48
|
+
Box::new(RegisterCommand::new(
|
|
49
|
+
self.root.clone(),
|
|
50
|
+
self.configuration.clone(),
|
|
51
|
+
)),
|
|
52
|
+
Box::new(UpgradeRepoKit::new(
|
|
53
|
+
self.root.clone(),
|
|
54
|
+
self.configuration.clone(),
|
|
55
|
+
)),
|
|
56
|
+
];
|
|
57
|
+
HashMap::from(internals.map(|x| (x.get_definition().name.to_string(), x)))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
repokit::interfaces::{RepoKitCommand, RepoKitConfig},
|
|
5
|
+
executables::{
|
|
6
|
+
intenal_executable::InternalExecutable,
|
|
7
|
+
internal_executable_definition::InternalExecutableDefinition,
|
|
8
|
+
},
|
|
9
|
+
internal_commands::help::Help,
|
|
10
|
+
logger::logger::Logger,
|
|
11
|
+
validations::command_validations::CommandValidations,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
pub struct ListCommands {
|
|
15
|
+
pub root: String,
|
|
16
|
+
pub configuration: RepoKitConfig,
|
|
17
|
+
pub definition: InternalExecutableDefinition,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static SCOPES: [&str; 4] = ["internal", "registered", "root", "<owner>"];
|
|
21
|
+
|
|
22
|
+
impl ListCommands {
|
|
23
|
+
pub fn new(root: String, configuration: RepoKitConfig) -> ListCommands {
|
|
24
|
+
ListCommands {
|
|
25
|
+
root,
|
|
26
|
+
configuration,
|
|
27
|
+
definition: InternalExecutableDefinition {
|
|
28
|
+
name: "list",
|
|
29
|
+
description: "List commands based on their scope of definition",
|
|
30
|
+
args: HashMap::from([(
|
|
31
|
+
"<scope>",
|
|
32
|
+
format!(
|
|
33
|
+
"The scope of the commands you wish to list. Specify one of {}",
|
|
34
|
+
Logger::blue(SCOPES.join(" | ").as_str())
|
|
35
|
+
)
|
|
36
|
+
.leak() as &'static str,
|
|
37
|
+
)]),
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fn collect_registered_commands(&self) -> HashMap<String, RepoKitCommand> {
|
|
43
|
+
let validators = CommandValidations::new(self.root.clone(), self.configuration.clone());
|
|
44
|
+
validators.collect_and_validate_externals()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fn exit_on_invalid_scope(&self) {
|
|
48
|
+
Logger::exit_with_info(
|
|
49
|
+
format!(
|
|
50
|
+
"Please specify a scope to list the commands of. Select one of {}",
|
|
51
|
+
Logger::blue_bright(SCOPES.join(" | ").as_str())
|
|
52
|
+
)
|
|
53
|
+
.as_str(),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
impl InternalExecutable for ListCommands {
|
|
59
|
+
fn run(&self, args: Vec<String>, internals: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
60
|
+
if args.is_empty() {
|
|
61
|
+
return self.exit_on_invalid_scope();
|
|
62
|
+
}
|
|
63
|
+
let query = args[0].as_str();
|
|
64
|
+
let scope = &query.to_lowercase();
|
|
65
|
+
if scope == SCOPES[0] {
|
|
66
|
+
return Help::log_internal_commands(internals);
|
|
67
|
+
}
|
|
68
|
+
if scope == SCOPES[2] {
|
|
69
|
+
return Help::log_root_commands(&self.configuration.commands);
|
|
70
|
+
}
|
|
71
|
+
let registered_commands = self.collect_registered_commands();
|
|
72
|
+
if scope == SCOPES[1] {
|
|
73
|
+
return Help::log_external_commands(®istered_commands);
|
|
74
|
+
}
|
|
75
|
+
let full_query = args.join(" ");
|
|
76
|
+
let full_scope = &full_query.to_lowercase();
|
|
77
|
+
Logger::info("Searching registered commands");
|
|
78
|
+
let matches: HashMap<String, RepoKitCommand> = registered_commands
|
|
79
|
+
.iter()
|
|
80
|
+
.filter_map(|(name, x)| {
|
|
81
|
+
if x.owner.to_lowercase().contains(full_scope) {
|
|
82
|
+
return Some((name.clone(), x.clone()));
|
|
83
|
+
}
|
|
84
|
+
None
|
|
85
|
+
})
|
|
86
|
+
.collect();
|
|
87
|
+
if matches.is_empty() {
|
|
88
|
+
Logger::exit_with_info(
|
|
89
|
+
format!(
|
|
90
|
+
"I could not find any commands matching {}",
|
|
91
|
+
Logger::blue_bright(&full_query)
|
|
92
|
+
)
|
|
93
|
+
.as_str(),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
Help::log_external_commands(&matches);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn help(&self) {
|
|
100
|
+
Help::log_internal_command(&self.definition);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fn get_definition(&self) -> &InternalExecutableDefinition {
|
|
104
|
+
&self.definition
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
use std::collections::{HashMap, HashSet};
|
|
2
|
+
|
|
3
|
+
use alphanumeric_sort::sort_str_slice;
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
executables::{
|
|
7
|
+
intenal_executable::InternalExecutable,
|
|
8
|
+
internal_executable_definition::InternalExecutableDefinition,
|
|
9
|
+
},
|
|
10
|
+
internal_commands::help::Help,
|
|
11
|
+
logger::logger::Logger,
|
|
12
|
+
repokit::interfaces::{RepoKitCommand, RepoKitConfig},
|
|
13
|
+
validations::command_validations::CommandValidations,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
pub struct ListOwners {
|
|
17
|
+
pub root: String,
|
|
18
|
+
pub configuration: RepoKitConfig,
|
|
19
|
+
pub definition: InternalExecutableDefinition,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
impl ListOwners {
|
|
23
|
+
pub fn new(root: String, configuration: RepoKitConfig) -> ListOwners {
|
|
24
|
+
ListOwners {
|
|
25
|
+
root,
|
|
26
|
+
configuration,
|
|
27
|
+
definition: InternalExecutableDefinition {
|
|
28
|
+
name: "owners",
|
|
29
|
+
description: "Lists all registered command owners",
|
|
30
|
+
args: HashMap::from([]),
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn collect_registered_commands(&self) -> HashMap<String, RepoKitCommand> {
|
|
36
|
+
let validators = CommandValidations::new(self.root.clone(), self.configuration.clone());
|
|
37
|
+
validators.collect_and_validate_externals()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
impl InternalExecutable for ListOwners {
|
|
42
|
+
fn run(&self, _: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
43
|
+
let registered_commands = self.collect_registered_commands();
|
|
44
|
+
Logger::info("Listing all command owners");
|
|
45
|
+
let mut owners: HashSet<String> = HashSet::new();
|
|
46
|
+
for (_, command) in registered_commands {
|
|
47
|
+
if !command.owner.is_empty() {
|
|
48
|
+
owners.insert(command.owner);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if owners.is_empty() {
|
|
52
|
+
return Logger::exit_with_info("No owners found");
|
|
53
|
+
}
|
|
54
|
+
println!();
|
|
55
|
+
let mut list: Vec<String> = owners.into_iter().collect();
|
|
56
|
+
sort_str_slice(&mut list);
|
|
57
|
+
for (index, owner) in list.iter().enumerate() {
|
|
58
|
+
println!(
|
|
59
|
+
"{}{}",
|
|
60
|
+
Logger::indent(None),
|
|
61
|
+
Logger::cyan(format!("{}. {}", index + 1, &owner).as_str()),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
println!();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn help(&self) {
|
|
68
|
+
Help::log_internal_command(&self.definition);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn get_definition(&self) -> &InternalExecutableDefinition {
|
|
72
|
+
&self.definition
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
use ::futures::executor;
|
|
2
|
+
use std::{collections::HashMap, process::exit};
|
|
3
|
+
|
|
4
|
+
use crate::{
|
|
5
|
+
repokit::interfaces::RepoKitConfig,
|
|
6
|
+
executables::{
|
|
7
|
+
intenal_executable::InternalExecutable,
|
|
8
|
+
internal_executable_definition::InternalExecutableDefinition,
|
|
9
|
+
},
|
|
10
|
+
external_commands::external_commands::ExternalCommands,
|
|
11
|
+
internal_commands::help::Help,
|
|
12
|
+
logger::logger::Logger,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
pub struct LocateCommand {
|
|
16
|
+
pub root: String,
|
|
17
|
+
pub configuration: RepoKitConfig,
|
|
18
|
+
pub definition: InternalExecutableDefinition,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl LocateCommand {
|
|
22
|
+
pub fn new(root: String, configuration: RepoKitConfig) -> LocateCommand {
|
|
23
|
+
LocateCommand {
|
|
24
|
+
root,
|
|
25
|
+
configuration,
|
|
26
|
+
definition: InternalExecutableDefinition {
|
|
27
|
+
name: "locate",
|
|
28
|
+
description: "Locates command definitions",
|
|
29
|
+
args: HashMap::from([("<name>", "The name of a registered command")]),
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn search_externals(&self, query: &str) {
|
|
35
|
+
let finder = ExternalCommands::new(self.root.clone());
|
|
36
|
+
let commands = executor::block_on(finder.find_all());
|
|
37
|
+
for command in commands {
|
|
38
|
+
if command.name == query {
|
|
39
|
+
Logger::log_file_path(&command.location);
|
|
40
|
+
exit(0);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fn search_root(&self, command: &str) {
|
|
46
|
+
if self.configuration.commands.contains_key(command) {
|
|
47
|
+
Logger::log_file_path(format!("{}/repokit.ts", &self.root).as_str());
|
|
48
|
+
exit(0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl InternalExecutable for LocateCommand {
|
|
54
|
+
fn run(&self, args: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
55
|
+
if args.is_empty() {
|
|
56
|
+
Logger::exit_with_info("Please specify a command to locate");
|
|
57
|
+
}
|
|
58
|
+
let command = &args[0];
|
|
59
|
+
Logger::info(format!("Locating a command named {}", Logger::blue_bright(command)).as_str());
|
|
60
|
+
self.search_externals(command);
|
|
61
|
+
self.search_root(command);
|
|
62
|
+
Logger::exit_with_error(
|
|
63
|
+
format!(
|
|
64
|
+
"I could not find a command named {}",
|
|
65
|
+
Logger::blue_bright(command)
|
|
66
|
+
)
|
|
67
|
+
.as_str(),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn help(&self) {
|
|
72
|
+
Help::log_internal_command(&self.definition);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fn get_definition(&self) -> &InternalExecutableDefinition {
|
|
76
|
+
&self.definition
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
executables::{
|
|
5
|
+
intenal_executable::InternalExecutable,
|
|
6
|
+
internal_executable_definition::InternalExecutableDefinition,
|
|
7
|
+
},
|
|
8
|
+
internal_commands::help::Help,
|
|
9
|
+
logger::logger::Logger,
|
|
10
|
+
repokit::interfaces::RepoKitConfig,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
pub struct Onboarder {
|
|
14
|
+
pub root: String,
|
|
15
|
+
pub configuration: RepoKitConfig,
|
|
16
|
+
pub definition: InternalExecutableDefinition,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
impl Onboarder {
|
|
20
|
+
pub fn new(root: String, configuration: RepoKitConfig) -> Onboarder {
|
|
21
|
+
Onboarder {
|
|
22
|
+
root,
|
|
23
|
+
configuration,
|
|
24
|
+
definition: InternalExecutableDefinition {
|
|
25
|
+
name: "onboard",
|
|
26
|
+
description: "Onboarding instructions for first time users",
|
|
27
|
+
args: HashMap::from([]),
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
impl InternalExecutable for Onboarder {
|
|
34
|
+
fn run(&self, _: Vec<String>, _: &HashMap<String, Box<dyn InternalExecutable>>) {
|
|
35
|
+
Logger::info(format!("Welcome to {}", Logger::blue_bright("Repokit")).as_str());
|
|
36
|
+
Logger::info(
|
|
37
|
+
"Repokit is a tool designed to self-document and publish developer facing workflows in a single CLI",
|
|
38
|
+
);
|
|
39
|
+
Logger::info(
|
|
40
|
+
format!("As you develop new features in your codebase, you can publish commands, API's, and tools to the {} CLI by running", Logger::blue_bright("Repokit")).as_str()
|
|
41
|
+
);
|
|
42
|
+
Logger::log_file_path("repokit register ./path/to/your-feature");
|
|
43
|
+
Logger::info(
|
|
44
|
+
"This command creates a tooling definition for your feature in a file collocated to your code",
|
|
45
|
+
);
|
|
46
|
+
Logger::info(
|
|
47
|
+
format!(
|
|
48
|
+
"The {} CLI will automatically detect these files and add them to its toolchain",
|
|
49
|
+
Logger::blue_bright("Repokit")
|
|
50
|
+
)
|
|
51
|
+
.as_str(),
|
|
52
|
+
);
|
|
53
|
+
Logger::info(
|
|
54
|
+
format!("As your codebase grows, your {} CLI will continue to track all of the published workflows created by your team", Logger::blue_bright("Repokit")).as_str()
|
|
55
|
+
);
|
|
56
|
+
Logger::space_around("It's your living source of knowledge and documentation");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn help(&self) {
|
|
60
|
+
Help::log_internal_command(&self.definition);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn get_definition(&self) -> &InternalExecutableDefinition {
|
|
64
|
+
&self.definition
|
|
65
|
+
}
|
|
66
|
+
}
|