This is an automated email from the ASF dual-hosted git repository. tison pushed a commit to branch generate-java-configs in repository https://gitbox.apache.org/repos/asf/opendal.git
commit 166e5fe2db928c7a4ff630fa485d66c33fdabb5c Author: tison <[email protected]> AuthorDate: Fri Jan 3 17:29:06 2025 +0800 feat: generate java configs Signed-off-by: tison <[email protected]> --- dev/src/generate/java.j2 | 46 +++++++++++++++++++++++++++++++++++++ dev/src/generate/java.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++ dev/src/generate/mod.rs | 2 ++ dev/src/generate/parser.rs | 15 +++++++++++++ dev/src/generate/python.j2 | 2 +- dev/src/generate/python.rs | 21 ++++------------- 6 files changed, 124 insertions(+), 18 deletions(-) diff --git a/dev/src/generate/java.j2 b/dev/src/generate/java.j2 new file mode 100644 index 000000000..4eda6c496 --- /dev/null +++ b/dev/src/generate/java.j2 @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// DO NOT EDIT IT MANUALLY. This file is generated by opendal/dev/generate/java.rs. + +package org.apache.opendal; + +import java.time.Duration; +import lombok.Data; + +/** + * Service configurations that are mapped from + * <a href="https://docs.rs/opendal/*/opendal/services/index.html>OpenDAL's services</a>. + */ +@SuppressWarnings("unused") // intended to be used by users +public interface ServiceConfig { + {% for srv in srvs %} + @Data + class {{srv}} { + {%- for field in srvs[srv].config %} + {%- if field.deprecated %} + /** + * @deprecated {{field.deprecated["note"]}} + */ + {%- endif %} + public final {{make_java_type(field.value)}} {{field.name}}; + {%- endfor %} + } + {% endfor %} +} diff --git a/dev/src/generate/java.rs b/dev/src/generate/java.rs new file mode 100644 index 000000000..6de6e153c --- /dev/null +++ b/dev/src/generate/java.rs @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use crate::generate::parser::{sorted_services, ConfigType, Services}; +use anyhow::Result; +use minijinja::value::ViaDeserialize; +use minijinja::{context, Environment}; +use std::fs; +use std::path::PathBuf; + +fn enabled_service(srv: &str) -> bool { + match srv { + // not enabled in bindings/java/Cargo.toml + "foundationdb" | "ftp" | "hdfs" | "rocksdb" | "tikv" => false, + _ => true, + } +} + +pub fn generate(workspace_dir: PathBuf, services: Services) -> Result<()> { + let srvs = sorted_services(services, enabled_service); + let mut env = Environment::new(); + env.add_template("java", include_str!("java.j2"))?; + env.add_function("make_java_type", make_java_type); + let tmpl = env.get_template("java")?; + + let output = + workspace_dir.join("bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java"); + fs::write(output, tmpl.render(context! { srvs => srvs })?)?; + Ok(()) +} + +fn make_java_type(ty: ViaDeserialize<ConfigType>) -> Result<String, minijinja::Error> { + Ok(match ty.0 { + ConfigType::Bool => "boolean", + ConfigType::Duration => "Duration", + ConfigType::I64 | ConfigType::U64 | ConfigType::Usize => "long", + ConfigType::U32 | ConfigType::U16 => "int", + ConfigType::Vec => "List<String>", + ConfigType::String => "String", + } + .to_string()) +} diff --git a/dev/src/generate/mod.rs b/dev/src/generate/mod.rs index 780f19a74..2a36ce765 100644 --- a/dev/src/generate/mod.rs +++ b/dev/src/generate/mod.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +mod java; mod parser; mod python; @@ -27,6 +28,7 @@ pub fn run(language: &str) -> Result<()> { let services = parser::parse(&services_path.to_string_lossy())?; match language { + "java" => java::generate(workspace_dir, services), "python" | "py" => python::generate(workspace_dir, services), _ => anyhow::bail!("unsupported language: {}", language), } diff --git a/dev/src/generate/parser.rs b/dev/src/generate/parser.rs index 086d7be5a..ee4bc4d4c 100644 --- a/dev/src/generate/parser.rs +++ b/dev/src/generate/parser.rs @@ -29,6 +29,21 @@ use syn::{ pub type Services = HashMap<String, Service>; +pub fn sorted_services(services: Services, test: fn(&str) -> bool) -> Services { + let mut srvs = Services::new(); + for (k, srv) in services.into_iter() { + if !test(k.as_str()) { + continue; + } + + let mut sorted = srv.config.into_iter().enumerate().collect::<Vec<_>>(); + sorted.sort_by_key(|(i, v)| (v.optional, *i)); + let config = sorted.into_iter().map(|(_, v)| v).collect(); + srvs.insert(k, Service { config }); + } + srvs +} + /// Service represents a service supported by opendal core, like `s3` and `fs` #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] pub struct Service { diff --git a/dev/src/generate/python.j2 b/dev/src/generate/python.j2 index 772407d52..49036d278 100644 --- a/dev/src/generate/python.j2 +++ b/dev/src/generate/python.j2 @@ -54,7 +54,7 @@ class _Base: {% if field.deprecated %} # deprecated: {{field.deprecated["note"]}} {%- endif %} - {{field.name}}: {{make_pytype(field.value)}}{% if field.optional %} = ...{% endif %}, + {{field.name}}: {{make_python_type(field.value)}}{% if field.optional %} = ...{% endif %}, {%- endfor %} ) -> None: ... {% endfor %} diff --git a/dev/src/generate/python.rs b/dev/src/generate/python.rs index 268a6e89d..0e852ed0c 100644 --- a/dev/src/generate/python.rs +++ b/dev/src/generate/python.rs @@ -15,14 +15,13 @@ // specific language governing permissions and limitations // under the License. -use crate::generate::parser::{ConfigType, Service, Services}; +use crate::generate::parser::{sorted_services, ConfigType, Services}; use anyhow::Result; use minijinja::value::ViaDeserialize; use minijinja::{context, Environment}; use std::fs; use std::path::PathBuf; -/// TODO: add a common utils to parse enabled features from cargo.toml fn enabled_service(srv: &str) -> bool { match srv { // not enabled in bindings/python/Cargo.toml @@ -32,30 +31,18 @@ fn enabled_service(srv: &str) -> bool { } pub fn generate(workspace_dir: PathBuf, services: Services) -> Result<()> { - let mut srvs = Services::new(); - for (k, srv) in services.into_iter() { - if !enabled_service(k.as_str()) { - continue; - } - - let mut sorted = srv.config.into_iter().enumerate().collect::<Vec<_>>(); - sorted.sort_by_key(|(i, v)| (v.optional, *i)); - let config = sorted.into_iter().map(|(_, v)| v).collect(); - srvs.insert(k, Service { config }); - } - + let srvs = sorted_services(services, enabled_service); let mut env = Environment::new(); env.add_template("python", include_str!("python.j2"))?; - env.add_function("make_pytype", make_pytype); + env.add_function("make_python_type", make_python_type); let tmpl = env.get_template("python")?; let output = workspace_dir.join("bindings/python/python/opendal/__base.pyi"); fs::write(output, tmpl.render(context! { srvs => srvs })?)?; - Ok(()) } -fn make_pytype(ty: ViaDeserialize<ConfigType>) -> Result<String, minijinja::Error> { +fn make_python_type(ty: ViaDeserialize<ConfigType>) -> Result<String, minijinja::Error> { Ok(match ty.0 { ConfigType::Bool => "_bool", ConfigType::Duration => "_duration",
