diff --git a/bin/oli/Cargo.lock b/bin/oli/Cargo.lock index fc969b527892..672cc75e590e 100644 --- a/bin/oli/Cargo.lock +++ b/bin/oli/Cargo.lock @@ -671,6 +671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -685,6 +686,18 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clap_lex" version = "0.7.2" @@ -1663,7 +1676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] diff --git a/bin/oli/Cargo.toml b/bin/oli/Cargo.toml index 924250ded3db..4030cffee2e3 100644 --- a/bin/oli/Cargo.toml +++ b/bin/oli/Cargo.toml @@ -55,7 +55,7 @@ services-sled = ["opendal/services-sled"] [dependencies] anyhow = "1" -clap = { version = "4", features = ["cargo", "string"] } +clap = { version = "4", features = ["cargo", "string", "derive", "deprecated"] } dirs = "5.0.1" futures = "0.3" opendal = { version = "0.50.0", path = "../../core", features = [ diff --git a/bin/oli/src/bin/oli.rs b/bin/oli/src/bin/oli.rs index 56e281e314a2..99ba3d276307 100644 --- a/bin/oli/src/bin/oli.rs +++ b/bin/oli/src/bin/oli.rs @@ -28,28 +28,13 @@ use std::path::PathBuf; use anyhow::anyhow; use anyhow::Result; -use clap::value_parser; -use clap::Arg; -use clap::Command; -use dirs::config_dir; +use oli::commands::OliSubcommand; -fn new_cmd(name: &'static str) -> Result { - let d = config_dir().ok_or_else(|| anyhow!("unknown config dir"))?; - let default_config_path = d.join("oli/config.toml").as_os_str().to_owned(); - - Ok(Command::new(name) - .version(env!("CARGO_PKG_VERSION")) - .arg( - Arg::new("config") - .long("config") - .help("Path to the config file") - .global(true) - .default_value(default_config_path) - .value_parser(value_parser!(PathBuf)) - .required(false), - ) - .subcommand_required(true) - .arg_required_else_help(true)) +#[derive(Debug, clap::Parser)] +#[command(about, version)] +pub struct Oli { + #[command(subcommand)] + subcommand: OliSubcommand, } #[tokio::main] @@ -66,28 +51,28 @@ async fn main() -> Result<()> { .and_then(OsStr::to_str) { Some("oli") => { - let cmd = oli::commands::cli::cli(new_cmd("oli")?); - oli::commands::cli::main(&cmd.get_matches()).await?; + let cmd: Oli = clap::Parser::parse(); + cmd.subcommand.run().await?; } Some("ocat") => { - let cmd = oli::commands::cat::cli(new_cmd("ocat")?); - oli::commands::cat::main(&cmd.get_matches()).await?; + let cmd: oli::commands::cat::CatCmd = clap::Parser::parse(); + cmd.run().await?; } Some("ocp") => { - let cmd = oli::commands::cp::cli(new_cmd("ocp")?); - oli::commands::cp::main(&cmd.get_matches()).await?; + let cmd: oli::commands::cp::CopyCmd = clap::Parser::parse(); + cmd.run().await?; } Some("ols") => { - let cmd = oli::commands::ls::cli(new_cmd("ols")?); - oli::commands::ls::main(&cmd.get_matches()).await?; + let cmd: oli::commands::ls::LsCmd = clap::Parser::parse(); + cmd.run().await?; } Some("orm") => { - let cmd = oli::commands::rm::cli(new_cmd("orm")?); - oli::commands::rm::main(&cmd.get_matches()).await?; + let cmd: oli::commands::rm::RmCmd = clap::Parser::parse(); + cmd.run().await?; } Some("ostat") => { - let cmd = oli::commands::stat::cli(new_cmd("ostat")?); - oli::commands::stat::main(&cmd.get_matches()).await?; + let cmd: oli::commands::stat::StatCmd = clap::Parser::parse(); + cmd.run().await?; } Some(v) => { println!("{v} is not supported") diff --git a/bin/oli/src/commands/cat.rs b/bin/oli/src/commands/cat.rs index 4bfe8190f7f0..fa892be6680e 100644 --- a/bin/oli/src/commands/cat.rs +++ b/bin/oli/src/commands/cat.rs @@ -15,39 +15,38 @@ // specific language governing permissions and limitations // under the License. -use std::path::PathBuf; - -use anyhow::anyhow; use anyhow::Result; -use clap::Arg; -use clap::ArgMatches; -use clap::Command; use futures::io; use crate::config::Config; +use crate::params::config::ConfigParams; -pub async fn main(args: &ArgMatches) -> Result<()> { - let config_path = args - .get_one::("config") - .ok_or_else(|| anyhow!("missing config path"))?; - let cfg = Config::load(config_path)?; +#[derive(Debug, clap::Parser)] +#[command( + name = "cat", + about = "Display object content", + disable_version_flag = true +)] +pub struct CatCmd { + #[command(flatten)] + pub config_params: ConfigParams, + #[arg()] + pub target: String, +} - let target = args - .get_one::("target") - .ok_or_else(|| anyhow!("missing target"))?; - let (op, path) = cfg.parse_location(target)?; +impl CatCmd { + pub async fn run(&self) -> Result<()> { + let cfg = Config::load(&self.config_params.config)?; - let reader = op.reader(&path).await?; - let meta = op.stat(&path).await?; - let mut buf_reader = reader - .into_futures_async_read(0..meta.content_length()) - .await?; - let mut stdout = io::AllowStdIo::new(std::io::stdout()); - io::copy_buf(&mut buf_reader, &mut stdout).await?; - Ok(()) -} + let (op, path) = cfg.parse_location(&self.target)?; -pub fn cli(cmd: Command) -> Command { - cmd.about("display object content") - .arg(Arg::new("target").required(true)) + let reader = op.reader(&path).await?; + let meta = op.stat(&path).await?; + let mut buf_reader = reader + .into_futures_async_read(0..meta.content_length()) + .await?; + let mut stdout = io::AllowStdIo::new(std::io::stdout()); + io::copy_buf(&mut buf_reader, &mut stdout).await?; + Ok(()) + } } diff --git a/bin/oli/src/commands/cli.rs b/bin/oli/src/commands/cli.rs deleted file mode 100644 index 320ed155d214..000000000000 --- a/bin/oli/src/commands/cli.rs +++ /dev/null @@ -1,47 +0,0 @@ -// 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 anyhow::anyhow; -use anyhow::Result; -use clap::ArgMatches; -use clap::Command; - -pub async fn main(args: &ArgMatches) -> Result<()> { - match args.subcommand() { - Some(("cat", sub_args)) => super::cat::main(sub_args).await?, - Some(("cp", sub_args)) => super::cp::main(sub_args).await?, - Some(("ls", sub_args)) => super::ls::main(sub_args).await?, - Some(("rm", sub_args)) => super::rm::main(sub_args).await?, - Some(("stat", sub_args)) => super::stat::main(sub_args).await?, - _ => return Err(anyhow!("not handled")), - } - - Ok(()) -} - -fn new_cmd(name: &'static str) -> Command { - Command::new(name).disable_version_flag(true) -} - -pub fn cli(cmd: Command) -> Command { - cmd.about("OpenDAL Command Line Interface") - .subcommand(super::cat::cli(new_cmd("cat"))) - .subcommand(super::cp::cli(new_cmd("cp"))) - .subcommand(super::ls::cli(new_cmd("ls"))) - .subcommand(super::rm::cli(new_cmd("rm"))) - .subcommand(super::stat::cli(new_cmd("stat"))) -} diff --git a/bin/oli/src/commands/cp.rs b/bin/oli/src/commands/cp.rs index d8ea084df3bc..e96f65097c3d 100644 --- a/bin/oli/src/commands/cp.rs +++ b/bin/oli/src/commands/cp.rs @@ -16,90 +16,77 @@ // under the License. use std::path::Path; -use std::path::PathBuf; -use anyhow::anyhow; use anyhow::Result; -use clap::Arg; -use clap::ArgAction; -use clap::ArgMatches; -use clap::Command; use futures::AsyncWriteExt; use futures::TryStreamExt; use crate::config::Config; +use crate::params::config::ConfigParams; -pub async fn main(args: &ArgMatches) -> Result<()> { - let config_path = args - .get_one::("config") - .ok_or_else(|| anyhow!("missing config path"))?; - let cfg = Config::load(config_path)?; - let recursive = args.get_flag("recursive"); +#[derive(Debug, clap::Parser)] +#[command(name = "cp", about = "Copy object", disable_version_flag = true)] +pub struct CopyCmd { + #[command(flatten)] + pub config_params: ConfigParams, + #[arg()] + pub source: String, + #[arg()] + pub destination: String, + /// Copy objects recursively. + #[arg(short = 'r', long)] + pub recursive: bool, +} - let src = args - .get_one::("source") - .ok_or_else(|| anyhow!("missing source"))?; - let (src_op, src_path) = cfg.parse_location(src)?; +impl CopyCmd { + pub async fn run(&self) -> Result<()> { + let cfg = Config::load(&self.config_params.config)?; - let dst = args - .get_one::("destination") - .ok_or_else(|| anyhow!("missing target"))?; - let (dst_op, dst_path) = cfg.parse_location(dst)?; + let (src_op, src_path) = cfg.parse_location(&self.source)?; - if !recursive { - let mut dst_w = dst_op.writer(&dst_path).await?.into_futures_async_write(); - let src_meta = src_op.stat(&src_path).await?; - let reader = src_op.reader_with(&src_path).chunk(8 * 1024 * 1024).await?; - let buf_reader = reader - .into_futures_async_read(0..src_meta.content_length()) - .await?; - futures::io::copy_buf(buf_reader, &mut dst_w).await?; - // flush data - dst_w.close().await?; - return Ok(()); - } + let (dst_op, dst_path) = cfg.parse_location(&self.destination)?; - let dst_root = Path::new(&dst_path); - let mut ds = src_op.lister_with(&src_path).recursive(true).await?; - let prefix = src_path.strip_prefix('/').unwrap_or(src_path.as_str()); - while let Some(de) = ds.try_next().await? { - let meta = de.metadata(); - if meta.mode().is_dir() { - continue; + if !self.recursive { + let mut dst_w = dst_op.writer(&dst_path).await?.into_futures_async_write(); + let src_meta = src_op.stat(&src_path).await?; + let reader = src_op.reader_with(&src_path).chunk(8 * 1024 * 1024).await?; + let buf_reader = reader + .into_futures_async_read(0..src_meta.content_length()) + .await?; + futures::io::copy_buf(buf_reader, &mut dst_w).await?; + // flush data + dst_w.close().await?; + return Ok(()); } - let depath = de.path(); - let fp = depath - .strip_prefix('/') - .unwrap_or(depath) - .strip_prefix(prefix) - .expect("invalid path"); - let reader = src_op.reader_with(de.path()).chunk(8 * 1024 * 1024).await?; - let buf_reader = reader - .into_futures_async_read(0..meta.content_length()) - .await?; - let mut writer = dst_op - .writer(&dst_root.join(fp).to_string_lossy()) - .await? - .into_futures_async_write(); + let dst_root = Path::new(&dst_path); + let mut ds = src_op.lister_with(&src_path).recursive(true).await?; + let prefix = src_path.strip_prefix('/').unwrap_or(src_path.as_str()); + while let Some(de) = ds.try_next().await? { + let meta = de.metadata(); + if meta.mode().is_dir() { + continue; + } + let depath = de.path(); + let fp = depath + .strip_prefix('/') + .unwrap_or(depath) + .strip_prefix(prefix) + .expect("invalid path"); + let reader = src_op.reader_with(de.path()).chunk(8 * 1024 * 1024).await?; + let buf_reader = reader + .into_futures_async_read(0..meta.content_length()) + .await?; - println!("Copying {}", de.path()); - futures::io::copy_buf(buf_reader, &mut writer).await?; - writer.close().await?; - } - Ok(()) -} + let mut writer = dst_op + .writer(&dst_root.join(fp).to_string_lossy()) + .await? + .into_futures_async_write(); -pub fn cli(cmd: Command) -> Command { - cmd.about("copy") - .arg(Arg::new("source").required(true)) - .arg(Arg::new("destination").required(true)) - .arg( - Arg::new("recursive") - .required(false) - .long("recursive") - .short('r') - .help("Copy files under source recursively to destination") - .action(ArgAction::SetTrue), - ) + println!("Copying {}", de.path()); + futures::io::copy_buf(buf_reader, &mut writer).await?; + writer.close().await?; + } + Ok(()) + } } diff --git a/bin/oli/src/commands/ls.rs b/bin/oli/src/commands/ls.rs index 50c60c56ec6a..3e7eb1026889 100644 --- a/bin/oli/src/commands/ls.rs +++ b/bin/oli/src/commands/ls.rs @@ -15,53 +15,42 @@ // specific language governing permissions and limitations // under the License. -use std::path::PathBuf; - -use anyhow::anyhow; use anyhow::Result; -use clap::Arg; -use clap::ArgAction; -use clap::ArgMatches; -use clap::Command; use futures::TryStreamExt; use crate::config::Config; +use crate::params::config::ConfigParams; + +#[derive(Debug, clap::Parser)] +#[command(name = "ls", about = "List object", disable_version_flag = true)] +pub struct LsCmd { + #[command(flatten)] + pub config_params: ConfigParams, + #[arg()] + pub target: String, + /// List objects recursively. + #[arg(short, long)] + pub recursive: bool, +} -pub async fn main(args: &ArgMatches) -> Result<()> { - let config_path = args - .get_one::("config") - .ok_or_else(|| anyhow!("missing config path"))?; - let cfg = Config::load(config_path)?; +impl LsCmd { + pub async fn run(&self) -> Result<()> { + let cfg = Config::load(&self.config_params.config)?; - let recursive = args.get_flag("recursive"); + let (op, path) = cfg.parse_location(&self.target)?; - let target = args - .get_one::("target") - .ok_or_else(|| anyhow!("missing target"))?; - let (op, path) = cfg.parse_location(target)?; + if !self.recursive { + let mut ds = op.lister(&path).await?; + while let Some(de) = ds.try_next().await? { + println!("{}", de.name()); + } + return Ok(()); + } - if !recursive { - let mut ds = op.lister(&path).await?; + let mut ds = op.lister_with(&path).recursive(true).await?; while let Some(de) = ds.try_next().await? { - println!("{}", de.name()); + println!("{}", de.path()); } - return Ok(()); + Ok(()) } - - let mut ds = op.lister_with(&path).recursive(true).await?; - while let Some(de) = ds.try_next().await? { - println!("{}", de.path()); - } - Ok(()) -} - -pub fn cli(cmd: Command) -> Command { - cmd.about("ls").arg(Arg::new("target").required(true)).arg( - Arg::new("recursive") - .required(false) - .long("recursive") - .short('r') - .help("List recursively") - .action(ArgAction::SetTrue), - ) } diff --git a/bin/oli/src/commands/mod.rs b/bin/oli/src/commands/mod.rs index 749af022a40e..e70d0c101a69 100644 --- a/bin/oli/src/commands/mod.rs +++ b/bin/oli/src/commands/mod.rs @@ -15,27 +15,31 @@ // specific language governing permissions and limitations // under the License. -//! Commands provides the implementation of each commands. -//! -//! Each submodule represents a single command, and should export 2 functions respectively. -//! The signature of those should be like the following: -//! -//! ```ignore -//! pub async fn main(args: &ArgMatches) -> Result<()> { -//! // the main logic -//! } -//! -//! // cli is used to customize the command, like setting the arguments. -//! // As each command can be invoked like a separate binary, -//! // we will pass a command with different name to get the complete command. -//! pub fn cli(cmd: Command) -> Command { -//! // set the arguments, help message, etc. -//! } -//! ``` +//! Provides the implementation of each command. pub mod cat; -pub mod cli; pub mod cp; pub mod ls; pub mod rm; pub mod stat; + +#[derive(Debug, clap::Subcommand)] +pub enum OliSubcommand { + Cat(cat::CatCmd), + Cp(cp::CopyCmd), + Ls(ls::LsCmd), + Rm(rm::RmCmd), + Stat(stat::StatCmd), +} + +impl OliSubcommand { + pub async fn run(&self) -> anyhow::Result<()> { + match self { + Self::Cat(cmd) => cmd.run().await, + Self::Cp(cmd) => cmd.run().await, + Self::Ls(cmd) => cmd.run().await, + Self::Rm(cmd) => cmd.run().await, + Self::Stat(cmd) => cmd.run().await, + } + } +} diff --git a/bin/oli/src/commands/rm.rs b/bin/oli/src/commands/rm.rs index 87fbe913aedc..04bc258d48c9 100644 --- a/bin/oli/src/commands/rm.rs +++ b/bin/oli/src/commands/rm.rs @@ -15,50 +15,37 @@ // specific language governing permissions and limitations // under the License. -use std::path::PathBuf; - -use anyhow::anyhow; use anyhow::Result; -use clap::Arg; -use clap::ArgAction; -use clap::ArgMatches; -use clap::Command; use crate::config::Config; +use crate::params::config::ConfigParams; + +#[derive(Debug, clap::Parser)] +#[command(name = "rm", about = "Remove object", disable_version_flag = true)] +pub struct RmCmd { + #[command(flatten)] + pub config_params: ConfigParams, + #[arg()] + pub target: String, + /// Remove objects recursively. + #[arg(short, long)] + pub recursive: bool, +} -pub async fn main(args: &ArgMatches) -> Result<()> { - let config_path = args - .get_one::("config") - .ok_or_else(|| anyhow!("missing config path"))?; - let cfg = Config::load(config_path)?; +impl RmCmd { + pub async fn run(&self) -> Result<()> { + let cfg = Config::load(&self.config_params.config)?; - let recursive = args.get_flag("recursive"); + let (op, path) = cfg.parse_location(&self.target)?; - let target = args - .get_one::("target") - .ok_or_else(|| anyhow!("missing target"))?; - let (op, path) = cfg.parse_location(target)?; + if !self.recursive { + println!("Delete: {path}"); + op.delete(&path).await?; + return Ok(()); + } - if !recursive { - println!("Delete: {path}"); - op.delete(&path).await?; - return Ok(()); + println!("Delete all: {path}"); + op.remove_all(&path).await?; + Ok(()) } - - println!("Delete all: {path}"); - op.remove_all(&path).await?; - Ok(()) -} - -pub fn cli(cmd: Command) -> Command { - cmd.about("remove object") - .arg(Arg::new("target").required(true)) - .arg( - Arg::new("recursive") - .required(false) - .long("recursive") - .short('r') - .help("List recursively") - .action(ArgAction::SetTrue), - ) } diff --git a/bin/oli/src/commands/stat.rs b/bin/oli/src/commands/stat.rs index d4efacae485a..8f1051f1a1c7 100644 --- a/bin/oli/src/commands/stat.rs +++ b/bin/oli/src/commands/stat.rs @@ -15,47 +15,47 @@ // specific language governing permissions and limitations // under the License. -use std::path::PathBuf; - -use anyhow::anyhow; use anyhow::Result; -use clap::Arg; -use clap::ArgMatches; -use clap::Command; use crate::config::Config; - -pub async fn main(args: &ArgMatches) -> Result<()> { - let config_path = args - .get_one::("config") - .ok_or_else(|| anyhow!("missing config path"))?; - let cfg = Config::load(config_path)?; - - let target = args - .get_one::("target") - .ok_or_else(|| anyhow!("missing target"))?; - let (op, path) = cfg.parse_location(target)?; - - let meta = op.stat(&path).await?; - println!("path: {target}"); - let size = meta.content_length(); - println!("size: {size}"); - if let Some(etag) = meta.etag() { - println!("etag: {etag}"); - } - let file_type = meta.mode(); - println!("type: {file_type}"); - if let Some(content_type) = meta.content_type() { - println!("content-type: {content_type}"); - } - if let Some(last_modified) = meta.last_modified() { - println!("last-modified: {last_modified}"); - } - - Ok(()) +use crate::params::config::ConfigParams; + +#[derive(Debug, clap::Parser)] +#[command( + name = "stat", + about = "Show object metadata", + disable_version_flag = true +)] +pub struct StatCmd { + #[command(flatten)] + pub config_params: ConfigParams, + #[arg()] + pub target: String, } -pub fn cli(cmd: Command) -> Command { - cmd.about("show object metadata") - .arg(Arg::new("target").required(true)) +impl StatCmd { + pub async fn run(&self) -> Result<()> { + let cfg = Config::load(&self.config_params.config)?; + + let target = &self.target; + println!("path: {target}"); + let (op, path) = cfg.parse_location(target)?; + + let meta = op.stat(&path).await?; + let size = meta.content_length(); + println!("size: {size}"); + if let Some(etag) = meta.etag() { + println!("etag: {etag}"); + } + let file_type = meta.mode(); + println!("type: {file_type}"); + if let Some(content_type) = meta.content_type() { + println!("content-type: {content_type}"); + } + if let Some(last_modified) = meta.last_modified() { + println!("last-modified: {last_modified}"); + } + + Ok(()) + } } diff --git a/bin/oli/src/config/mod.rs b/bin/oli/src/config/mod.rs index 93d888e4ff73..d15ea884a498 100644 --- a/bin/oli/src/config/mod.rs +++ b/bin/oli/src/config/mod.rs @@ -30,7 +30,6 @@ use opendal::services; use opendal::Operator; use opendal::Scheme; use serde::Deserialize; -use toml; use url::Url; #[derive(Deserialize, Default)] diff --git a/bin/oli/src/lib.rs b/bin/oli/src/lib.rs index 7f0fce639553..e829973afc58 100644 --- a/bin/oli/src/lib.rs +++ b/bin/oli/src/lib.rs @@ -17,3 +17,4 @@ pub mod commands; pub mod config; +pub mod params; diff --git a/bin/oli/src/params/config.rs b/bin/oli/src/params/config.rs new file mode 100644 index 000000000000..3ceb8f951bfc --- /dev/null +++ b/bin/oli/src/params/config.rs @@ -0,0 +1,35 @@ +// 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 std::ffi::OsString; +use std::path::PathBuf; + +#[derive(Debug, clap::Args)] +pub struct ConfigParams { + /// Path to the config file. + #[arg( + long, + default_value = default_config_path(), + value_parser = clap::value_parser!(PathBuf) + )] + pub config: PathBuf, +} + +fn default_config_path() -> OsString { + let d = dirs::config_dir().expect("unknown config dir"); + d.join("oli/config.toml").as_os_str().to_owned() +} diff --git a/bin/oli/src/params/mod.rs b/bin/oli/src/params/mod.rs new file mode 100644 index 000000000000..207d7e279fb3 --- /dev/null +++ b/bin/oli/src/params/mod.rs @@ -0,0 +1,20 @@ +// 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. + +//! Provides the implementation of common parameters. + +pub mod config;