Skip to content

Commit c333bf4

Browse files
committed
Simplify config.
1 parent ad791ea commit c333bf4

File tree

8 files changed

+225
-524
lines changed

8 files changed

+225
-524
lines changed

java-spaghetti-gen/src/config.rs

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
//! java-spaghetti.toml configuration file structures and parsing APIs.
2+
3+
use std::collections::HashSet;
4+
use std::path::{Path, PathBuf};
5+
use std::{fs, io};
6+
7+
use serde_derive::Deserialize;
8+
9+
fn default_proxy_path_prefix() -> String {
10+
"java_spaghetti/proxy".to_string()
11+
}
12+
13+
fn default_empty() -> String {
14+
String::new()
15+
}
16+
fn default_slash() -> String {
17+
String::from("/")
18+
}
19+
fn default_period() -> String {
20+
String::from(".")
21+
}
22+
fn default_comma() -> String {
23+
String::from(",")
24+
}
25+
26+
/// A \[\[documentation.pattern\]\] section.
27+
#[derive(Debug, Clone, Deserialize)]
28+
pub struct DocPattern {
29+
/// The URL to use for documenting a given class. `{CLASS}` will be replaced with everything *after* the JNI prefix.
30+
///
31+
/// | Given: | Use this if you want android documentation: |
32+
/// | --------------------- | --------------------------------------------- |
33+
/// | jni_prefix = "java/" | class_url_pattern = "https://developer.android.com/reference/java/{CLASS}.html"
34+
/// | jni_prefix = "" | class_url_pattern = "https://developer.android.com/reference/{CLASS}.html"
35+
pub class_url_pattern: String,
36+
37+
/// The URL to use for documenting a given class method.
38+
///
39+
/// * `{CLASS}` will be replaced with everything *after* the JNI prefix.
40+
/// * `{METHOD}` will be replaced with the method name.
41+
/// * `{ARGUMENTS}` will be replaced with the method arguments.
42+
///
43+
/// | Given: | Use this if you want android documentation: |
44+
/// | --------------------- | --------------------------------------------- |
45+
/// | jni_prefix = "java/" | method_url_pattern = "https://developer.android.com/reference/java/{CLASS}.html#{METHOD}({ARGUMENTS})"
46+
/// | jni_prefix = "" | method_url_pattern = "https://developer.android.com/reference/{CLASS}.html#{METHOD}({ARGUMENTS})"
47+
pub method_url_pattern: Option<String>,
48+
49+
/// The URL to use for documenting a given class constructor.
50+
///
51+
/// * `{CLASS}` will be replaced with everything *after* the JNI prefix.
52+
/// * `{CLASS.OUTER}` will be replaced with just the class name, including the outer class(es)
53+
/// * `{CLASS.INNER}` will be replaced with just the class name, excluding the outer class(es)
54+
/// * `{METHOD}` aliases `{CLASS.INNER}`
55+
/// * `{ARGUMENTS}` will be replaced with the method arguments.
56+
///
57+
/// Defaults to method_url_pattern
58+
///
59+
/// | Given: | Use this if you want android documentation: |
60+
/// | --------------------- | --------------------------------------------- |
61+
/// | jni_prefix = "java/" | constructor_url_pattern = "https://developer.android.com/reference/java/{CLASS}.html#{CLASS.INNER}({ARGUMENTS})"
62+
/// | jni_prefix = "" | constructor_url_pattern = "https://developer.android.com/reference/{CLASS}.html#{CLASS.INNER}({ARGUMENTS})"
63+
pub constructor_url_pattern: Option<String>,
64+
65+
/// The URL to use for documenting a given class field.
66+
///
67+
/// * `{CLASS}` will be replaced with everything *after* the JNI prefix.
68+
/// * `{FIELD}` will be replaced with the field name.
69+
///
70+
/// | Given: | Use this if you want android documentation: |
71+
/// | --------------------- | --------------------------------------------- |
72+
/// | jni_prefix = "java/" | field_url_pattern = "https://developer.android.com/reference/java/{CLASS}.html#{FIELD}"
73+
/// | jni_prefix = "" | field_url_pattern = "https://developer.android.com/reference/{CLASS}.html#{FIELD}"
74+
pub field_url_pattern: Option<String>,
75+
76+
/// What java class(es) to match against. This takes the form of a simple prefix to a JNI path with no wildcards.
77+
///
78+
/// | To Match: | Use a JNI Prefix: |
79+
/// | ------------------------- | ------------------------------------- |
80+
/// | * | jni_prefix = ""
81+
/// | java.lang.* | jni_prefix = "java/lang/"
82+
/// | name.spaces.OuterClass.* | jni_prefix = "name/spaces/OuterClass$"
83+
#[serde(default = "default_empty")]
84+
pub jni_prefix: String,
85+
86+
/// What to use in the {CLASS} portion of URLs to separate namespaces. Defaults to "/".
87+
#[serde(default = "default_slash")]
88+
pub class_namespace_separator: String,
89+
90+
/// What to use in the {CLASS} portion of URLs to separate inner classes from outer classes. Defaults to ".".
91+
#[serde(default = "default_period")]
92+
pub class_inner_class_seperator: String,
93+
94+
/// What to use in the {ARGUMENTS} portion of URLs to separate namespaces. Defaults to ".".
95+
#[serde(default = "default_period")]
96+
pub argument_namespace_separator: String,
97+
98+
/// What to use in the {ARGUMENTS} portion of URLs to separate inner classes from outer classes. Defaults to ".".
99+
#[serde(default = "default_period")]
100+
pub argument_inner_class_seperator: String,
101+
102+
/// What to use in the {ARGUMENTS} portion of URLs to separate inner classes from outer classes. Defaults to ",".
103+
#[serde(default = "default_comma")]
104+
pub argument_seperator: String,
105+
}
106+
107+
#[derive(Debug, Clone, Deserialize)]
108+
pub struct Config {
109+
#[serde(default = "default_proxy_path_prefix")]
110+
pub proxy_path_prefix: String,
111+
112+
pub(crate) input: Vec<PathBuf>,
113+
pub(crate) output: PathBuf,
114+
115+
#[serde(default)]
116+
pub(crate) doc_patterns: Vec<DocPattern>,
117+
#[serde(default)]
118+
pub(crate) logging_verbose: bool,
119+
120+
#[serde(rename = "include")]
121+
#[serde(default)]
122+
pub(crate) include_classes: HashSet<String>,
123+
124+
#[serde(rename = "include_proxy")]
125+
#[serde(default = "HashSet::new")]
126+
pub(crate) include_proxies: HashSet<String>,
127+
}
128+
129+
impl Config {
130+
/// Read from I/O, under the assumption that it's in the "java-spaghetti.toml" file format.
131+
/// `directory` is the directory that contained the `java-spaghetti.toml` file, against which paths should be resolved.
132+
pub fn read(file: &mut impl io::Read, dir: &Path) -> io::Result<Self> {
133+
let mut buffer = String::new();
134+
file.read_to_string(&mut buffer)?; // Apparently toml can't stream.
135+
Self::read_str(&buffer[..], dir)
136+
}
137+
138+
/// Read from a memory buffer, under the assumption that it's in the "java-spaghetti.toml" file format.
139+
/// `directory` is the directory that contained the `java-spaghetti.toml` file, against which paths should be resolved.
140+
pub fn read_str(buffer: &str, dir: &Path) -> io::Result<Self> {
141+
let mut config: Config = toml::from_str(buffer).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
142+
143+
if config.include_classes.is_empty() {
144+
config.include_classes.insert("*".to_string());
145+
}
146+
147+
config.output = resolve_file(&config.output, dir);
148+
for f in &mut config.input {
149+
*f = resolve_file(f, dir);
150+
}
151+
152+
Ok(config)
153+
}
154+
155+
/// Search the current directory - or failing that, it's ancestors - until we find "java-spaghetti.toml" or reach the
156+
/// root of the filesystem and cannot continue.
157+
#[allow(dead_code)]
158+
pub fn from_current_directory() -> io::Result<Self> {
159+
Self::from_directory(std::env::current_dir()?.as_path())
160+
}
161+
162+
/// Search the specified directory - or failing that, it's ancestors - until we find "java-spaghetti.toml" or reach the
163+
/// root of the filesystem and cannot continue.
164+
pub fn from_directory(path: &Path) -> io::Result<Self> {
165+
let original = path;
166+
let mut path = path.to_owned();
167+
loop {
168+
path.push("java-spaghetti.toml");
169+
println!("cargo:rerun-if-changed={}", path.display());
170+
if path.exists() {
171+
return Config::read(&mut fs::File::open(&path)?, path.parent().unwrap());
172+
}
173+
if !path.pop() || !path.pop() {
174+
Err(io::Error::new(
175+
io::ErrorKind::NotFound,
176+
format!(
177+
"Failed to find java-spaghetti.toml in \"{}\" or any of it's parent directories.",
178+
original.display()
179+
),
180+
))?;
181+
}
182+
}
183+
}
184+
}
185+
186+
fn resolve_file(path: &Path, dir: &Path) -> PathBuf {
187+
let path = expand_vars(&path.to_string_lossy());
188+
let path: PathBuf = path.into();
189+
if path.is_relative() { dir.join(path) } else { path }
190+
}
191+
192+
fn expand_vars(string: &str) -> String {
193+
let mut buf = String::new();
194+
195+
let mut expanding = false;
196+
for segment in string.split('%') {
197+
if expanding {
198+
if let Ok(replacement) = std::env::var(segment) {
199+
buf.push_str(&replacement[..]);
200+
} else {
201+
println!("cargo:rerun-if-env-changed={segment}");
202+
buf.push('%');
203+
buf.push_str(segment);
204+
buf.push('%');
205+
}
206+
} else {
207+
buf.push_str(segment);
208+
}
209+
expanding = !expanding;
210+
}
211+
assert!(
212+
expanding,
213+
"Uneven number of %s in path: {:?}, would mis-expand into: {:?}",
214+
&string, &buf
215+
);
216+
buf
217+
}

java-spaghetti-gen/src/config/mod.rs

Lines changed: 0 additions & 4 deletions
This file was deleted.

java-spaghetti-gen/src/config/runtime.rs

Lines changed: 0 additions & 127 deletions
This file was deleted.

0 commit comments

Comments
 (0)