java_runtimes/detector.rs
1//! This module provides functions for detecting available Java runtimes from given path(s).
2//!
3//! The detected java runtimes are represented by the [`JavaRuntime`] struct.
4//!
5//! # Examples
6//!
7//! Detect Java runtime from environment variables
8//!
9//! ```rust
10//! use java_runtimes::detector;
11//!
12//! let runtimes = detector::detect_java_in_environments();
13//! println!("Detected Java runtimes: {:?}", runtimes);
14//! ```
15//!
16//! Detect Java runtimes recursively within a path
17//!
18//! ```rust
19//! use java_runtimes::detector;
20//!
21//! let runtimes = detector::detect_java("/usr".as_ref(), 2);
22//! println!("Detected Java runtimes: {:?}", runtimes);
23//! ```
24//!
25//! Detect Java runtimes recursively within multiple paths
26//!
27//! ```rust
28//! use java_runtimes::detector;
29//!
30//! let runtimes = detector::detect_java_in_paths(&[
31//! "/usr".as_ref(),
32//! "/opt".as_ref(),
33//! ], 2);
34//! println!("Detected Java runtimes in multiple paths: {:?}", runtimes);
35//! ```
36
37use crate::JavaRuntime;
38use std::path::Path;
39use walkdir::WalkDir;
40
41/// Detects available Java runtimes within the specified path up to a maximum depth.
42///
43/// # Parameters
44///
45/// * `max_depth`: Maximum depth to search for Java runtimes (see [`WalkDir::max_depth`]).
46///
47/// # Returns
48///
49/// A vector containing all detected Java runtimes.
50pub fn detect_java(path: &Path, max_depth: usize) -> Vec<JavaRuntime> {
51 let mut runtimes: Vec<JavaRuntime> = vec![];
52 gather_java(&mut runtimes, path, max_depth);
53 runtimes
54}
55
56/// Detects available Java runtimes within the specified path and appends them to the given vector.
57///
58/// # Parameters
59///
60/// * `runtimes`: Vector to contain detected Java runtimes.
61/// * `path`: The path to search for Java runtimes.
62/// * `max_depth`: Maximum depth to search for Java runtimes (see [`WalkDir::max_depth`]).
63///
64/// # Returns
65///
66/// The number of new Java runtimes added to the vector.
67pub fn gather_java(runtimes: &mut Vec<JavaRuntime>, path: &Path, max_depth: usize) -> usize {
68 if path.is_file() {
69 if let Some(runtime) = detect_java_bin_dir(path) {
70 runtimes.push(runtime);
71 return 1;
72 }
73 }
74
75 let entries = WalkDir::new(path)
76 .max_depth(max_depth)
77 .follow_links(false)
78 .into_iter()
79 .filter_map(Result::ok);
80
81 let begin_count = runtimes.len();
82
83 for entry in entries {
84 let path = entry.path();
85 if let Some(runtime) = detect_java_bin_dir(path) {
86 runtimes.push(runtime);
87 }
88 }
89 runtimes.len() - begin_count
90}
91
92/// Detects available Java runtimes from environment variables.
93///
94/// It searches java runtime in paths below:
95///
96/// * `JAVA_HOME`
97/// * `JAVA_ROOT`
98/// * `JDK_HOME`
99/// * `JRE_HOME`
100/// * `PATH`
101pub fn detect_java_in_environments() -> Vec<JavaRuntime> {
102 let mut runtimes: Vec<JavaRuntime> = vec![];
103
104 let mut gather_env = |var_name: &str| {
105 if let Ok(env_java_home) = std::env::var(var_name) {
106 gather_java(&mut runtimes, env_java_home.as_ref(), 1);
107 }
108 };
109
110 gather_env("JAVA_HOME");
111 gather_env("JAVA_ROOT");
112 gather_env("JDK_HOME");
113 gather_env("JRE_HOME");
114
115 if let Ok(env_path) = std::env::var("PATH") {
116 let paths = env_path
117 .split(r":|;")
118 .map(Path::new)
119 .collect::<Vec<&Path>>();
120 gather_java_in_paths(&mut runtimes, &paths, 1);
121 }
122 runtimes
123}
124
125/// Detects available Java runtimes within multiple paths up to a maximum depth.
126///
127/// # Parameters
128///
129/// * `paths`: The paths to search for Java runtimes.
130/// * `max_depth`: Maximum depth to search for Java runtimes (see [`WalkDir::max_depth`]).
131///
132/// # Returns
133///
134/// A vector containing all detected Java runtimes.
135pub fn detect_java_in_paths<'a>(paths: &[&Path], max_depth: usize) -> Vec<JavaRuntime> {
136 let mut runtimes: Vec<JavaRuntime> = vec![];
137 for &path in paths {
138 gather_java(&mut runtimes, path, max_depth);
139 }
140 runtimes
141}
142
143/// Detects available Java runtimes within multiple paths up to a maximum depth and appends them to the given vector.
144///
145/// # Parameters
146///
147/// * `runtimes`: Vector to contain detected Java runtimes.
148/// * `paths`: The paths to search for Java runtimes.
149/// * `max_depth`: Maximum depth to search for Java runtimes (see [`WalkDir::max_depth`]).
150///
151/// # Returns
152///
153/// The number of new Java runtimes added to the vector.
154pub fn gather_java_in_paths<'a>(
155 runtimes: &mut Vec<JavaRuntime>,
156 paths: &[&Path],
157 max_depth: usize,
158) -> usize {
159 paths
160 .iter()
161 .map(|&path| gather_java(runtimes, path, max_depth))
162 .sum::<usize>()
163}
164
165/// Attempts to detect a Java runtime from the given path.
166///
167/// # Returns
168///
169/// * `Some(JavaRuntime)` if the given path points to an available Java executable file.
170/// * `None` if the given path is not an available Java executable file.
171pub fn detect_java_exe(path: &Path) -> Option<JavaRuntime> {
172 JavaRuntime::from_executable(path).map_or(None, |r| Some(r))
173}
174
175/// Attempts to detect a Java runtime from the given directory path.
176///
177/// # Returns
178///
179/// * `Some(JavaRuntime)` if the given path is a directory containing the Java executable file.
180/// * `None` if the given path is not a directory containing the Java executable file.
181pub fn detect_java_bin_dir(bin_dir: &Path) -> Option<JavaRuntime> {
182 detect_java_exe(&bin_dir.join(JavaRuntime::get_java_executable_name()))
183}
184
185/// Attempts to detect a Java runtime from the given Java home directory path.
186///
187/// # Returns
188///
189/// * `Some(JavaRuntime)` if the given path is a directory containing the `bin` subdirectory with the Java executable file.
190/// * `None` if the given path is not a directory containing the `bin` subdirectory with the Java executable file.
191pub fn detect_java_home_dir(java_home: &Path) -> Option<JavaRuntime> {
192 detect_java_bin_dir(&java_home.join("bin"))
193}