@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
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
fs::File,
|
|
3
|
+
io::{BufRead, BufReader},
|
|
4
|
+
path::PathBuf,
|
|
5
|
+
sync::LazyLock,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
use futures::{executor::block_on, join};
|
|
9
|
+
use regex::Regex;
|
|
10
|
+
|
|
11
|
+
use crate::{
|
|
12
|
+
caches::{file_cache::FileCache, repokit_version_resolver::RepoKitVersionResolver},
|
|
13
|
+
context::file_system::FileSystem,
|
|
14
|
+
logger::logger::Logger,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
#[derive(Clone)]
|
|
18
|
+
pub struct VersionCache {
|
|
19
|
+
pub runtime_version: String,
|
|
20
|
+
pub installed_version: String,
|
|
21
|
+
pub cache_directory: Option<PathBuf>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static UNKNOWN: &str = "UNKNOWN";
|
|
25
|
+
|
|
26
|
+
pub static VERSION_REGEX: LazyLock<Regex> =
|
|
27
|
+
LazyLock::new(|| Regex::new(r#"\d*\.\d*.\d*"#).unwrap());
|
|
28
|
+
|
|
29
|
+
impl VersionCache {
|
|
30
|
+
pub fn new(cache_directory: &Option<PathBuf>) -> Self {
|
|
31
|
+
VersionCache {
|
|
32
|
+
runtime_version: UNKNOWN.to_string(),
|
|
33
|
+
installed_version: UNKNOWN.to_string(),
|
|
34
|
+
cache_directory: cache_directory.clone(),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn refresh_installed_version(&self, files: &FileSystem) -> Option<String> {
|
|
39
|
+
let installed_version = block_on(self.installed_repokit_version(files));
|
|
40
|
+
if let Some(version) = &installed_version
|
|
41
|
+
&& *version != self.installed_version
|
|
42
|
+
{
|
|
43
|
+
return Some(version.to_string());
|
|
44
|
+
}
|
|
45
|
+
None
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pub async fn initialize(&mut self, files: &FileSystem) {
|
|
49
|
+
let (runtime_result, install_result) = join!(
|
|
50
|
+
self.runtime_version(),
|
|
51
|
+
self.installed_repokit_version(files)
|
|
52
|
+
);
|
|
53
|
+
if let Some(installed_version) = install_result {
|
|
54
|
+
self.installed_version = installed_version;
|
|
55
|
+
}
|
|
56
|
+
if let Some(runtime_version) = runtime_result {
|
|
57
|
+
self.runtime_version = runtime_version;
|
|
58
|
+
}
|
|
59
|
+
if self.installed_version != self.runtime_version
|
|
60
|
+
&& VERSION_REGEX.is_match(&self.installed_version)
|
|
61
|
+
{
|
|
62
|
+
self.hop_to_installed_version(files);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fn hop_to_installed_version(&self, files: &FileSystem) {
|
|
67
|
+
Logger::info(
|
|
68
|
+
format!(
|
|
69
|
+
"Switching to version {}",
|
|
70
|
+
Logger::with_theme(|theme| theme.highlight(&self.installed_version))
|
|
71
|
+
)
|
|
72
|
+
.as_str(),
|
|
73
|
+
);
|
|
74
|
+
RepoKitVersionResolver::hop_to_installed_version(files);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async fn runtime_version(&self) -> Option<String> {
|
|
78
|
+
if let Some((mut lines, _)) = self.read() {
|
|
79
|
+
let last_known_version = self.unwrap_line(lines.nth(0), "");
|
|
80
|
+
if VERSION_REGEX.is_match(&last_known_version) {
|
|
81
|
+
return Some(last_known_version);
|
|
82
|
+
}
|
|
83
|
+
return None;
|
|
84
|
+
}
|
|
85
|
+
None
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async fn installed_repokit_version(&self, files: &FileSystem) -> Option<String> {
|
|
89
|
+
let package_path = FileSystem::join_with(&files.package_directory, "package.json");
|
|
90
|
+
if !package_path.exists() || !package_path.is_file() {
|
|
91
|
+
return None;
|
|
92
|
+
}
|
|
93
|
+
let file = File::open(package_path);
|
|
94
|
+
if file.is_err() {
|
|
95
|
+
return None;
|
|
96
|
+
}
|
|
97
|
+
let lines = BufReader::new(file.unwrap()).lines();
|
|
98
|
+
let version_matcher = Regex::new(r#""([^"]*)""#).unwrap();
|
|
99
|
+
for line in lines.map_while(Result::ok) {
|
|
100
|
+
if line.contains("\"version\": ") {
|
|
101
|
+
let captures: Vec<String> = version_matcher
|
|
102
|
+
.captures_iter(&line)
|
|
103
|
+
.filter_map(|item| {
|
|
104
|
+
item.get(1)
|
|
105
|
+
.map(|match_text| match_text.as_str().to_string())
|
|
106
|
+
})
|
|
107
|
+
.collect();
|
|
108
|
+
if let Some(version) = captures.get(1)
|
|
109
|
+
&& VERSION_REGEX.is_match(version)
|
|
110
|
+
{
|
|
111
|
+
return Some(version.to_string());
|
|
112
|
+
}
|
|
113
|
+
return None;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
None
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
impl FileCache for VersionCache {
|
|
121
|
+
fn cache_file(&self) -> &str {
|
|
122
|
+
"../.version"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fn cache_directory(&self) -> &Option<PathBuf> {
|
|
126
|
+
&self.cache_directory
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
use futures::{executor::block_on, join};
|
|
2
|
+
use normalize_path::NormalizePath;
|
|
3
|
+
use shellexpand::tilde;
|
|
4
|
+
use std::{
|
|
5
|
+
fs::create_dir_all,
|
|
6
|
+
path::{Path, PathBuf},
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
use crate::{
|
|
10
|
+
caches::{
|
|
11
|
+
crawl_cache::CrawlCache, file_cache::FileCache, settings_cache::SettingsCache,
|
|
12
|
+
version_cache::VersionCache,
|
|
13
|
+
},
|
|
14
|
+
context::{file_system::FileSystem, git_scope::GitScope},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
#[derive(Clone)]
|
|
18
|
+
pub struct CacheScope {
|
|
19
|
+
pub version_cache: VersionCache,
|
|
20
|
+
pub settings_cache: SettingsCache,
|
|
21
|
+
pub crawl_cache: CrawlCache,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static CACHE_DIRECTORY: &str = ".repokit_cache";
|
|
25
|
+
|
|
26
|
+
impl CacheScope {
|
|
27
|
+
pub fn new(git_scope: &GitScope, file_system: &FileSystem) -> CacheScope {
|
|
28
|
+
let cache_directory = CacheScope::resolve_cache_directory(&git_scope.root_commit_hash);
|
|
29
|
+
let mut instance = CacheScope {
|
|
30
|
+
crawl_cache: CrawlCache::new(&cache_directory),
|
|
31
|
+
version_cache: VersionCache::new(&cache_directory),
|
|
32
|
+
settings_cache: SettingsCache::new(&cache_directory),
|
|
33
|
+
};
|
|
34
|
+
block_on(instance.initialize_all(git_scope, file_system));
|
|
35
|
+
instance
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async fn initialize_all(&mut self, git_scope: &GitScope, file_system: &FileSystem) {
|
|
39
|
+
self.create_cache_files().await;
|
|
40
|
+
join!(
|
|
41
|
+
self.version_cache.initialize(file_system),
|
|
42
|
+
self.settings_cache.initialize(),
|
|
43
|
+
self.crawl_cache.initialize(git_scope),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async fn create_cache_files(&self) {
|
|
48
|
+
join!(
|
|
49
|
+
self.version_cache.create_cache_file_if_not_exists(),
|
|
50
|
+
self.settings_cache.create_cache_file_if_not_exists(),
|
|
51
|
+
self.crawl_cache.create_cache_file_if_not_exists(),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn home() -> Option<PathBuf> {
|
|
56
|
+
let expanded_path_str = tilde("~/");
|
|
57
|
+
let path = Path::new(expanded_path_str.as_ref()).normalize();
|
|
58
|
+
if path.is_absolute() && path.exists() {
|
|
59
|
+
return Some(path);
|
|
60
|
+
}
|
|
61
|
+
None
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fn resolve_cache_directory(root_commit: &Option<String>) -> Option<PathBuf> {
|
|
65
|
+
if let Some(home) = CacheScope::home()
|
|
66
|
+
&& let Some(commit_hash) = root_commit
|
|
67
|
+
{
|
|
68
|
+
let cache_dir = home.join(CACHE_DIRECTORY).join(commit_hash);
|
|
69
|
+
if !cache_dir.exists() && create_dir_all(&cache_dir).is_err() {
|
|
70
|
+
return None;
|
|
71
|
+
}
|
|
72
|
+
return Some(cache_dir);
|
|
73
|
+
}
|
|
74
|
+
None
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
use normalize_path::NormalizePath;
|
|
2
|
+
|
|
3
|
+
use std::{
|
|
4
|
+
fs::File,
|
|
5
|
+
path::{Path, PathBuf},
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
use crate::{internal_filesystem::file_builder::FileBuilder, logger::logger::Logger};
|
|
9
|
+
|
|
10
|
+
#[derive(Clone)]
|
|
11
|
+
pub struct FileSystem {
|
|
12
|
+
pub git_root: String,
|
|
13
|
+
pub git_root_path: PathBuf,
|
|
14
|
+
pub package_directory: PathBuf,
|
|
15
|
+
pub commands_directory: PathBuf,
|
|
16
|
+
pub templates_directory: PathBuf,
|
|
17
|
+
pub install_script_path: PathBuf,
|
|
18
|
+
pub install_script_location: &'static str,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static INSTALL_SCRIPT_LOCATION: &str = "installation/install.sh";
|
|
22
|
+
static INSTALLED_PACKAGE_PATH: &str = "node_modules/@repokit/core";
|
|
23
|
+
static TYPESCRIPT_COMMANDS: &str = "dist/commands";
|
|
24
|
+
static TYPESCRIPT_TEMPLATES: &str = "externals/templates";
|
|
25
|
+
|
|
26
|
+
impl FileSystem {
|
|
27
|
+
pub fn new(git_root: &str) -> FileSystem {
|
|
28
|
+
let git_root_path = Path::new(&git_root).normalize();
|
|
29
|
+
let package_directory = FileSystem::join_with(&git_root_path, INSTALLED_PACKAGE_PATH);
|
|
30
|
+
FileSystem {
|
|
31
|
+
git_root_path,
|
|
32
|
+
git_root: git_root.to_owned(),
|
|
33
|
+
install_script_path: FileSystem::join_with(&package_directory, INSTALL_SCRIPT_LOCATION),
|
|
34
|
+
commands_directory: FileSystem::join_with(&package_directory, TYPESCRIPT_COMMANDS),
|
|
35
|
+
templates_directory: FileSystem::join_with(&package_directory, TYPESCRIPT_TEMPLATES),
|
|
36
|
+
package_directory,
|
|
37
|
+
install_script_location: INSTALL_SCRIPT_LOCATION,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn join_with(root: &PathBuf, segment: &str) -> PathBuf {
|
|
42
|
+
root.join(segment).normalize()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub fn resolve_command(&self, command_name: &str) -> String {
|
|
46
|
+
FileSystem::path_buf_to_str(&FileSystem::join_with(
|
|
47
|
+
&self.commands_directory,
|
|
48
|
+
format!("{command_name}.mjs").as_str(),
|
|
49
|
+
))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn resolve_template(&self, file_name: &str) -> File {
|
|
53
|
+
FileBuilder::open(
|
|
54
|
+
FileSystem::join_with(&self.templates_directory, file_name),
|
|
55
|
+
|_| {
|
|
56
|
+
Logger::error(format!("Unable to locate internal {file_name}").as_str());
|
|
57
|
+
Logger::error("Please file a bug here");
|
|
58
|
+
Logger::log_issue_link();
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn path_buf_to_str(path: &PathBuf) -> String {
|
|
64
|
+
path.to_string_lossy().to_string()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
use std::path::Path;
|
|
2
|
+
|
|
3
|
+
use futures::{executor::block_on, join};
|
|
4
|
+
|
|
5
|
+
use crate::{executor::executor::Executor, logger::logger::Logger};
|
|
6
|
+
|
|
7
|
+
#[derive(Clone)]
|
|
8
|
+
pub struct GitScope {
|
|
9
|
+
pub root: String,
|
|
10
|
+
pub root_commit_hash: Option<String>,
|
|
11
|
+
pub head_commit_hash: Option<String>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl GitScope {
|
|
15
|
+
pub fn new() -> GitScope {
|
|
16
|
+
let mut instance = GitScope {
|
|
17
|
+
root: "".to_string(),
|
|
18
|
+
root_commit_hash: None,
|
|
19
|
+
head_commit_hash: None,
|
|
20
|
+
};
|
|
21
|
+
block_on(instance.resolve());
|
|
22
|
+
instance
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async fn resolve(&mut self) {
|
|
26
|
+
let (root, root_commit, head_commit) = join!(
|
|
27
|
+
GitScope::find_root(),
|
|
28
|
+
GitScope::get_root_commit(),
|
|
29
|
+
GitScope::get_head_commit()
|
|
30
|
+
);
|
|
31
|
+
self.root = root;
|
|
32
|
+
self.root_commit_hash = root_commit;
|
|
33
|
+
self.head_commit_hash = head_commit;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async fn find_root() -> String {
|
|
37
|
+
if let Some(root) = Executor::exec_with_stdout("git rev-parse --show-toplevel", |cmd| cmd)
|
|
38
|
+
&& !root.is_empty()
|
|
39
|
+
&& Path::new(&root).exists()
|
|
40
|
+
{
|
|
41
|
+
return root;
|
|
42
|
+
}
|
|
43
|
+
Logger::info("Please initialize your repository by running");
|
|
44
|
+
Logger::log_file_path("git init");
|
|
45
|
+
panic!();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async fn get_head_commit() -> Option<String> {
|
|
49
|
+
Executor::exec_with_stdout("git rev-parse HEAD", |cmd| cmd)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async fn get_root_commit() -> Option<String> {
|
|
53
|
+
Executor::exec_with_stdout("git rev-list --parents HEAD | tail -1", |cmd| cmd)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
use std::{collections::HashMap, path::Path};
|
|
2
|
+
|
|
3
|
+
use normalize_path::NormalizePath;
|
|
4
|
+
|
|
5
|
+
use crate::{
|
|
6
|
+
caches::version_cache::VERSION_REGEX, executor::executor::Executor, logger::logger::Logger,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
#[derive(Clone)]
|
|
10
|
+
pub struct NodeScope {
|
|
11
|
+
pub install_command: String,
|
|
12
|
+
pub command_executor: String,
|
|
13
|
+
pub package_manager: String,
|
|
14
|
+
pub resolved_typescript_version: Option<u32>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl NodeScope {
|
|
18
|
+
pub fn new(git_root: &str) -> NodeScope {
|
|
19
|
+
let package_manager = NodeScope::get_package_manager(git_root).to_string();
|
|
20
|
+
NodeScope {
|
|
21
|
+
resolved_typescript_version: None,
|
|
22
|
+
command_executor: NodeScope::get_node_executor(&package_manager).to_string(),
|
|
23
|
+
install_command: NodeScope::get_install_command(&package_manager).to_string(),
|
|
24
|
+
package_manager,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn type_check_file(&mut self, file_path: &str) {
|
|
29
|
+
let command = self.get_typecheck_command(file_path);
|
|
30
|
+
Executor::with_stdio(command, |cmd| cmd);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn get_typecheck_command(&mut self, file_path: &str) -> String {
|
|
34
|
+
let typescript_version = self.get_typescript_version();
|
|
35
|
+
let ignore_config = if typescript_version >= 6 {
|
|
36
|
+
" --ignoreConfig".to_string()
|
|
37
|
+
} else {
|
|
38
|
+
"".to_string()
|
|
39
|
+
};
|
|
40
|
+
let tsc_command = format!(
|
|
41
|
+
"{} tsc {} --noEmit{}",
|
|
42
|
+
self.command_executor, file_path, ignore_config
|
|
43
|
+
);
|
|
44
|
+
tsc_command
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn prompt_to_fix_errors(config_path: &str) {
|
|
48
|
+
Logger::info(
|
|
49
|
+
"Please fix the above type-errors and rerun your command"
|
|
50
|
+
.to_string()
|
|
51
|
+
.as_str(),
|
|
52
|
+
);
|
|
53
|
+
Logger::log_file_path(config_path);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fn get_typescript_version(&mut self) -> u32 {
|
|
57
|
+
if let Some(resolved_version) = self.resolved_typescript_version {
|
|
58
|
+
return resolved_version;
|
|
59
|
+
}
|
|
60
|
+
let stdout = Executor::exec(format!("{} tsc --version", self.command_executor), |cmd| {
|
|
61
|
+
cmd
|
|
62
|
+
});
|
|
63
|
+
let lines: Vec<&str> = stdout
|
|
64
|
+
.split("\n")
|
|
65
|
+
.filter_map(|s| {
|
|
66
|
+
let trimmed = s.trim();
|
|
67
|
+
if trimmed.is_empty() {
|
|
68
|
+
return None;
|
|
69
|
+
}
|
|
70
|
+
Some(trimmed)
|
|
71
|
+
})
|
|
72
|
+
.collect();
|
|
73
|
+
let fallback_version = "5.0.0";
|
|
74
|
+
let version = lines.last().unwrap_or(&fallback_version);
|
|
75
|
+
let captures: Vec<String> = VERSION_REGEX
|
|
76
|
+
.captures_iter(version)
|
|
77
|
+
.filter_map(|item| {
|
|
78
|
+
item.get(0)
|
|
79
|
+
.map(|match_text| match_text.as_str().to_string())
|
|
80
|
+
})
|
|
81
|
+
.collect();
|
|
82
|
+
let fallback_version_str = fallback_version.to_string();
|
|
83
|
+
let semver = captures.first().unwrap_or(&fallback_version_str);
|
|
84
|
+
let major = semver
|
|
85
|
+
.chars()
|
|
86
|
+
.next()
|
|
87
|
+
.unwrap_or('5')
|
|
88
|
+
.to_digit(10)
|
|
89
|
+
.unwrap_or(5);
|
|
90
|
+
self.resolved_typescript_version = Some(major);
|
|
91
|
+
major
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fn get_install_command(package_manager: &str) -> &str {
|
|
95
|
+
let npm_install = "npm i -D";
|
|
96
|
+
let manager_map = HashMap::from([
|
|
97
|
+
("npm", npm_install),
|
|
98
|
+
("yarn", "yarn add -D"),
|
|
99
|
+
("pnpm", "pnpm i -D"),
|
|
100
|
+
("bun", "bun add -D"),
|
|
101
|
+
]);
|
|
102
|
+
manager_map.get(package_manager).unwrap_or(&npm_install)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fn get_node_executor(package_manager: &str) -> &str {
|
|
106
|
+
let npx = "npx";
|
|
107
|
+
let manager_map = HashMap::from([
|
|
108
|
+
("npm", "npx"),
|
|
109
|
+
("yarn", "yarn run -T"),
|
|
110
|
+
("pnpm", "pnpm run"),
|
|
111
|
+
("bun", "bunx"),
|
|
112
|
+
]);
|
|
113
|
+
manager_map.get(package_manager).unwrap_or(&npx)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fn get_package_manager(root: &str) -> &str {
|
|
117
|
+
let manager_map = HashMap::from([
|
|
118
|
+
("npm", ["package-lock.json"].to_vec()),
|
|
119
|
+
("yarn", ["yarn.lock"].to_vec()),
|
|
120
|
+
("pnpm", ["pnpm-lock.yaml"].to_vec()),
|
|
121
|
+
("bun", ["bun.lockb", "bun.lock"].to_vec()),
|
|
122
|
+
]);
|
|
123
|
+
for (manager, lock_files) in manager_map {
|
|
124
|
+
for lock_file in lock_files {
|
|
125
|
+
let path = Path::new(root).join(lock_file).normalize();
|
|
126
|
+
if path.exists() && path.is_file() {
|
|
127
|
+
return manager;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
"npm"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
use core::panic;
|
|
2
|
+
use std::{
|
|
3
|
+
path::{Path, PathBuf},
|
|
4
|
+
sync::MutexGuard,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
use serde_json::{Value, from_str};
|
|
8
|
+
|
|
9
|
+
use crate::{
|
|
10
|
+
context::{file_system::FileSystem, node_scope::NodeScope},
|
|
11
|
+
executor::executor::Executor,
|
|
12
|
+
repokit::{
|
|
13
|
+
repokit_command::RepoKitCommand, repokit_config::RepoKitConfig,
|
|
14
|
+
repokit_runtime::RepoKitRuntime,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
pub struct TypeScriptBridge;
|
|
19
|
+
|
|
20
|
+
impl TypeScriptBridge {
|
|
21
|
+
pub fn parse_configuration(files: &FileSystem, node: &mut NodeScope) -> RepoKitConfig {
|
|
22
|
+
let executable = files.resolve_command("parse_configuration");
|
|
23
|
+
let stdout = TypeScriptBridge::execute_with_node(
|
|
24
|
+
&files.git_root_path,
|
|
25
|
+
format!("{executable} --root {}", &files.git_root).as_str(),
|
|
26
|
+
);
|
|
27
|
+
if stdout.is_empty() {
|
|
28
|
+
RepoKitConfig::create(files);
|
|
29
|
+
}
|
|
30
|
+
let result: Result<Value, serde_json::Error> = from_str(stdout.as_str());
|
|
31
|
+
match result {
|
|
32
|
+
Ok(config) => RepoKitConfig::from_input(&files.git_root, node, config),
|
|
33
|
+
Err(_) => {
|
|
34
|
+
RepoKitConfig::on_parsing_error(&files.git_root, node, Value::Null);
|
|
35
|
+
panic!();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn parse_commands(path_list: &MutexGuard<Vec<String>>) -> Vec<RepoKitCommand> {
|
|
41
|
+
let paths = path_list.join(",");
|
|
42
|
+
let stdout = RepoKitRuntime::with_runtime(|runtime| {
|
|
43
|
+
let executable = runtime.files.resolve_command("parse_commands");
|
|
44
|
+
TypeScriptBridge::execute_with_node(
|
|
45
|
+
&runtime.files.git_root_path,
|
|
46
|
+
format!(
|
|
47
|
+
"{executable} --paths {paths} --root {}",
|
|
48
|
+
runtime.files.git_root
|
|
49
|
+
)
|
|
50
|
+
.as_str(),
|
|
51
|
+
)
|
|
52
|
+
});
|
|
53
|
+
let result: Result<Vec<Value>, serde_json::Error> = serde_json::from_str(&stdout);
|
|
54
|
+
match result {
|
|
55
|
+
Ok(commands) => RepoKitCommand::from_input(commands),
|
|
56
|
+
Err(_) => {
|
|
57
|
+
RepoKitCommand::full_blown_crash();
|
|
58
|
+
panic!();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn execute_with_node(root: &PathBuf, args: &str) -> String {
|
|
64
|
+
Executor::exec(format!("node {args}"), |cmd| {
|
|
65
|
+
cmd.current_dir(Path::new(root))
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
-
use crate::
|
|
3
|
+
use crate::{
|
|
4
|
+
executables::internal_executable_definition::InternalExecutableDefinition,
|
|
5
|
+
internal_commands::help::Help,
|
|
6
|
+
};
|
|
4
7
|
|
|
5
8
|
pub trait InternalExecutable {
|
|
6
9
|
fn run(&self, args: Vec<String>, internals: &HashMap<String, Box<dyn InternalExecutable>>);
|
|
7
|
-
fn help(&self);
|
|
8
10
|
fn get_definition(&self) -> &InternalExecutableDefinition;
|
|
11
|
+
|
|
12
|
+
fn help(&self) {
|
|
13
|
+
Help::log_internal_command(self.get_definition());
|
|
14
|
+
}
|
|
9
15
|
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
-
use crate::repokit::repokit_config::RepoKitConfig;
|
|
4
|
-
|
|
5
|
-
#[derive(Clone)]
|
|
6
|
-
pub struct RepoKitScope {
|
|
7
|
-
pub root: String,
|
|
8
|
-
pub configuration: RepoKitConfig,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
3
|
#[derive(Clone)]
|
|
12
4
|
pub struct InternalExecutableDefinition {
|
|
13
5
|
pub name: String,
|
|
@@ -31,6 +31,19 @@ impl Executor {
|
|
|
31
31
|
Some(Executor::unwrap(&output.stderr))
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
pub fn exec_with_stdout<T: AsRef<OsStr>>(
|
|
35
|
+
command: T,
|
|
36
|
+
composer: impl Fn(&mut Command) -> &mut Command,
|
|
37
|
+
) -> Option<String> {
|
|
38
|
+
let output = composer(&mut Executor::spawn(command))
|
|
39
|
+
.output()
|
|
40
|
+
.expect("command failed to execute");
|
|
41
|
+
if output.status.success() {
|
|
42
|
+
return Some(Executor::unwrap(&output.stdout));
|
|
43
|
+
}
|
|
44
|
+
None
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
pub fn with_stdio<T: AsRef<OsStr>>(
|
|
35
48
|
command: T,
|
|
36
49
|
composer: impl Fn(&mut Command) -> &mut Command,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
use std::sync::{Arc, Mutex, MutexGuard};
|
|
2
|
+
|
|
3
|
+
use ignore::WalkBuilder;
|
|
4
|
+
|
|
5
|
+
use crate::{file_walker::walker::TSFileVisitorBuilder, repokit::repokit_runtime::RepoKitRuntime};
|
|
6
|
+
|
|
7
|
+
pub struct FileWalker {
|
|
8
|
+
pub command_paths: Arc<Mutex<Vec<String>>>,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
impl FileWalker {
|
|
12
|
+
pub fn new() -> Self {
|
|
13
|
+
let instance = FileWalker {
|
|
14
|
+
command_paths: Arc::new(Mutex::new(Vec::new())),
|
|
15
|
+
};
|
|
16
|
+
instance.resolve();
|
|
17
|
+
instance
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub fn get(&self) -> MutexGuard<'_, Vec<String>> {
|
|
21
|
+
self.command_paths.lock().unwrap()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fn resolve(&self) {
|
|
25
|
+
if RepoKitRuntime::with_runtime(|runtime| runtime.caches.crawl_cache.crawl_cache_enabled())
|
|
26
|
+
{
|
|
27
|
+
self.from_cache();
|
|
28
|
+
} else {
|
|
29
|
+
self.crawl_file_system();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fn crawl_file_system(&self) {
|
|
34
|
+
RepoKitRuntime::with_runtime(|runtime| {
|
|
35
|
+
let mut visitor = TSFileVisitorBuilder::new(&runtime.git.root, &self.command_paths);
|
|
36
|
+
WalkBuilder::new(&runtime.files.git_root_path)
|
|
37
|
+
.build_parallel()
|
|
38
|
+
.visit(&mut visitor);
|
|
39
|
+
if let Some(head_commit) = &runtime.git.head_commit_hash {
|
|
40
|
+
let files = self.command_paths.lock().unwrap();
|
|
41
|
+
runtime
|
|
42
|
+
.caches
|
|
43
|
+
.crawl_cache
|
|
44
|
+
.cache_crawl_results([head_commit.to_owned(), files.join("\n")].join("\n"));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fn from_cache(&self) {
|
|
50
|
+
let mut paths_to_search = self.command_paths.lock().unwrap();
|
|
51
|
+
RepoKitRuntime::with_runtime(|runtime| {
|
|
52
|
+
if let Some(files_to_crawl) = &runtime.caches.crawl_cache.files_to_crawl {
|
|
53
|
+
for file in files_to_crawl {
|
|
54
|
+
paths_to_search.push(file.to_owned());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -10,7 +10,7 @@ use crate::{
|
|
|
10
10
|
logger::logger::Logger,
|
|
11
11
|
repokit::{
|
|
12
12
|
command_definition::CommandDefinition, repokit_command::RepoKitCommand,
|
|
13
|
-
repokit_config::RootCommand,
|
|
13
|
+
repokit_config::RootCommand, repokit_runtime::RepoKitRuntime,
|
|
14
14
|
},
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -18,12 +18,13 @@ pub struct Help;
|
|
|
18
18
|
|
|
19
19
|
impl Help {
|
|
20
20
|
pub fn list_all(
|
|
21
|
-
root_commands: &HashMap<String, CommandDefinition>,
|
|
22
21
|
internals: &HashMap<String, Box<dyn InternalExecutable>>,
|
|
23
22
|
externals: &HashMap<String, RepoKitCommand>,
|
|
24
23
|
) {
|
|
25
24
|
Help::log_internal_commands(internals);
|
|
26
|
-
|
|
25
|
+
RepoKitRuntime::with_runtime(|runtime| {
|
|
26
|
+
Help::log_root_commands(&runtime.configuration.commands);
|
|
27
|
+
});
|
|
27
28
|
Help::log_external_commands(externals);
|
|
28
29
|
}
|
|
29
30
|
|