From 0a5b3d3cbb47ef44647da985550f080d4584c1bd Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sat, 20 Jan 2024 16:59:12 +0800 Subject: [PATCH 1/7] feat(ofs): introduce ofs execute bin --- Cargo.lock | 44 +++++++++++++++++++++++++++++--- bin/ofs/Cargo.toml | 12 ++++++++- bin/ofs/ofs.toml.example | 6 +++++ bin/ofs/src/bin/ofs.rs | 55 ++++++++++++++++++++++++++++++++++++++++ bin/ofs/src/config.rs | 40 +++++++++++++++++++++++++++++ bin/ofs/src/lib.rs | 3 +++ 6 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 bin/ofs/ofs.toml.example create mode 100644 bin/ofs/src/bin/ofs.rs create mode 100644 bin/ofs/src/config.rs diff --git a/Cargo.lock b/Cargo.lock index c4d7e82eedb4..bb14cce61fe4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1706,7 +1706,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -2665,11 +2665,12 @@ dependencies = [ "futures-channel", "futures-util", "libc", - "nix", + "nix 0.26.4", "serde", "slab", "tokio", "tracing", + "which", ] [[package]] @@ -3928,6 +3929,24 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -4370,6 +4389,19 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.26.4" @@ -4379,6 +4411,7 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", + "memoffset 0.7.1", ] [[package]] @@ -4572,12 +4605,17 @@ dependencies = [ name = "ofs" version = "0.0.1" dependencies = [ + "anyhow", "async-trait", "fuse3", "futures-util", "libc", "log", + "nix 0.22.3", "opendal", + "serde", + "tokio", + "toml 0.8.8", ] [[package]] @@ -5652,7 +5690,7 @@ dependencies = [ "cfg-if", "indoc", "libc", - "memoffset", + "memoffset 0.9.0", "parking_lot 0.12.1", "pyo3-build-config", "pyo3-ffi", diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index 1829f0788204..dc578b159cec 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -31,8 +31,18 @@ rust-version.workspace = true [dependencies] async-trait = "0.1.75" -fuse3 = { "version" = "0.6.1", "features" = ["tokio-runtime"] } +fuse3 = { "version" = "0.6.1", "features" = ["tokio-runtime", "unprivileged"] } futures-util = "0.3.30" libc = "0.2.151" log = "0.4.20" +anyhow = "1" +tokio = { version = "1.34", features = [ + "fs", + "macros", + "rt-multi-thread", + "io-std", +] } +toml = "0.8.8" +serde = { version = "1", features = ["derive"] } +nix = "0.22.1" opendal.workspace = true diff --git a/bin/ofs/ofs.toml.example b/bin/ofs/ofs.toml.example new file mode 100644 index 000000000000..ab912df9273f --- /dev/null +++ b/bin/ofs/ofs.toml.example @@ -0,0 +1,6 @@ +[backend] +type = "fs" +root = "/tmp" + +[frontends] +mount_path = "./example" diff --git a/bin/ofs/src/bin/ofs.rs b/bin/ofs/src/bin/ofs.rs new file mode 100644 index 000000000000..3b6244d03205 --- /dev/null +++ b/bin/ofs/src/bin/ofs.rs @@ -0,0 +1,55 @@ +// 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::str::FromStr; + +use anyhow::Context; +use anyhow::Result; +use fuse3::path::Session; +use fuse3::MountOptions; +use ofs::Config; +use ofs::Ofs; +use opendal::Operator; +use opendal::Scheme; + +#[tokio::main] +async fn main() -> Result<()> { + ofs().await +} + +async fn ofs() -> Result<()> { + let cfg: Config = + toml::from_str(&std::fs::read_to_string("ofs.toml").context("failed to open ofs.toml")?)?; + let scheme = Scheme::from_str(&cfg.backend.typ).context("unsupported scheme")?; + let op = Operator::via_map(scheme, cfg.backend.map.clone())?; + + let mut mount_option = MountOptions::default(); + mount_option.uid(nix::unistd::getuid().into()); + mount_option.gid(nix::unistd::getgid().into()); + + let mount_path = cfg.frontends.mount_path.clone(); + + let ofs = Ofs { op }; + + let mounthandle = Session::new(mount_option) + .mount_with_unprivileged(ofs, mount_path) + .await?; + + mounthandle.await?; + + Ok(()) +} diff --git a/bin/ofs/src/config.rs b/bin/ofs/src/config.rs new file mode 100644 index 000000000000..e935b2f10080 --- /dev/null +++ b/bin/ofs/src/config.rs @@ -0,0 +1,40 @@ +// 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::collections::HashMap; + +use serde::Deserialize; +use serde::Serialize; + +#[derive(Serialize, Deserialize)] +pub struct Config { + pub backend: BackendConfig, + pub frontends: FrontendsConfig, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct BackendConfig { + #[serde(rename = "type")] + pub typ: String, + #[serde(flatten)] + pub map: HashMap, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct FrontendsConfig { + pub mount_path: String, +} diff --git a/bin/ofs/src/lib.rs b/bin/ofs/src/lib.rs index 3fc0cadae6b5..03069ef56285 100644 --- a/bin/ofs/src/lib.rs +++ b/bin/ofs/src/lib.rs @@ -15,6 +15,9 @@ // specific language governing permissions and limitations // under the License. +mod config; +pub use config::*; + use std::ffi::OsStr; use std::vec::IntoIter; From 48a138a9ef30e1544034d62787903b2831a7a721 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sat, 20 Jan 2024 20:24:44 +0800 Subject: [PATCH 2/7] feat(ofs): fix code --- Cargo.lock | 65 ++++++++++++++++++++++++---------------- bin/ofs/Cargo.toml | 5 +++- bin/ofs/ofs.toml.example | 6 ---- bin/ofs/src/bin/ofs.rs | 48 ++++++++++++++++++++++------- 4 files changed, 82 insertions(+), 42 deletions(-) delete mode 100644 bin/ofs/ofs.toml.example diff --git a/Cargo.lock b/Cargo.lock index bb14cce61fe4..1ba1cc8ce27c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,9 +79,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -1382,9 +1382,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -2328,6 +2328,16 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" version = "0.10.1" @@ -2341,6 +2351,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eeb342678d785662fd2514be38c459bb925f02b68dd2a3e0f21d7ef82d979dd" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -3929,15 +3952,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -4391,27 +4405,25 @@ dependencies = [ [[package]] name = "nix" -version = "0.22.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cc", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", ] [[package]] name = "nix" -version = "0.26.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "libc", - "memoffset 0.7.1", ] [[package]] @@ -4607,15 +4619,18 @@ version = "0.0.1" dependencies = [ "anyhow", "async-trait", + "clap", + "env_logger 0.11.0", "fuse3", "futures-util", "libc", "log", - "nix 0.22.3", + "nix 0.27.1", "opendal", "serde", "tokio", "toml 0.8.8", + "url", ] [[package]] @@ -4626,7 +4641,7 @@ dependencies = [ "assert_cmd", "clap", "dirs", - "env_logger", + "env_logger 0.10.1", "futures", "log", "opendal", diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index dc578b159cec..3af867998d22 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -44,5 +44,8 @@ tokio = { version = "1.34", features = [ ] } toml = "0.8.8" serde = { version = "1", features = ["derive"] } -nix = "0.22.1" +nix = { version = "0.27.1", features = ["user"] } +env_logger = "0.11" +clap = { version = "4.4.18", features = ["derive", "env"] } +url = "2.5.0" opendal.workspace = true diff --git a/bin/ofs/ofs.toml.example b/bin/ofs/ofs.toml.example deleted file mode 100644 index ab912df9273f..000000000000 --- a/bin/ofs/ofs.toml.example +++ /dev/null @@ -1,6 +0,0 @@ -[backend] -type = "fs" -root = "/tmp" - -[frontends] -mount_path = "./example" diff --git a/bin/ofs/src/bin/ofs.rs b/bin/ofs/src/bin/ofs.rs index 3b6244d03205..7a33f8d57ddf 100644 --- a/bin/ofs/src/bin/ofs.rs +++ b/bin/ofs/src/bin/ofs.rs @@ -15,38 +15,66 @@ // specific language governing permissions and limitations // under the License. +use std::collections::HashMap; use std::str::FromStr; +use anyhow::anyhow; use anyhow::Context; use anyhow::Result; +use clap::Parser; use fuse3::path::Session; use fuse3::MountOptions; -use ofs::Config; use ofs::Ofs; use opendal::Operator; use opendal::Scheme; +use url::Url; #[tokio::main] async fn main() -> Result<()> { - ofs().await + env_logger::init(); + fuse().await } -async fn ofs() -> Result<()> { - let cfg: Config = - toml::from_str(&std::fs::read_to_string("ofs.toml").context("failed to open ofs.toml")?)?; - let scheme = Scheme::from_str(&cfg.backend.typ).context("unsupported scheme")?; - let op = Operator::via_map(scheme, cfg.backend.map.clone())?; +#[derive(Parser, Debug)] +#[command(version, about)] +struct Config { + /// fuse mount path + #[arg(short, long, env = "OFS_MOUNT_PATH")] + mount_path: String, + + /// location of opendal service + /// format: ://: + /// example: s3://127.0.0.1:9000?access_key=xxx&secret_key=xxx + #[arg(short, long, env = "OFS_BACKEND")] + backend: String, +} + +async fn fuse() -> Result<()> { + let cfg = Config::parse(); + + let location = Url::parse(&cfg.backend)?; + if location.has_host() { + Err(anyhow!("Host part in a location is not supported."))?; + } + + let scheme_str = location.scheme(); + + let op_args = location + .query_pairs() + .into_owned() + .collect::>(); + + let scheme = Scheme::from_str(scheme_str).context("unsupported scheme")?; + let op = Operator::via_map(scheme, op_args)?; let mut mount_option = MountOptions::default(); mount_option.uid(nix::unistd::getuid().into()); mount_option.gid(nix::unistd::getgid().into()); - let mount_path = cfg.frontends.mount_path.clone(); - let ofs = Ofs { op }; let mounthandle = Session::new(mount_option) - .mount_with_unprivileged(ofs, mount_path) + .mount_with_unprivileged(ofs, cfg.mount_path) .await?; mounthandle.await?; From f09877f2133022f6f4abe6836278c4e48c9de9bb Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sat, 20 Jan 2024 20:25:26 +0800 Subject: [PATCH 3/7] feat(ofs): fix code --- bin/ofs/src/config.rs | 40 ---------------------------------------- bin/ofs/src/lib.rs | 3 --- 2 files changed, 43 deletions(-) delete mode 100644 bin/ofs/src/config.rs diff --git a/bin/ofs/src/config.rs b/bin/ofs/src/config.rs deleted file mode 100644 index e935b2f10080..000000000000 --- a/bin/ofs/src/config.rs +++ /dev/null @@ -1,40 +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 std::collections::HashMap; - -use serde::Deserialize; -use serde::Serialize; - -#[derive(Serialize, Deserialize)] -pub struct Config { - pub backend: BackendConfig, - pub frontends: FrontendsConfig, -} - -#[derive(Serialize, Deserialize, Default)] -pub struct BackendConfig { - #[serde(rename = "type")] - pub typ: String, - #[serde(flatten)] - pub map: HashMap, -} - -#[derive(Serialize, Deserialize, Default)] -pub struct FrontendsConfig { - pub mount_path: String, -} diff --git a/bin/ofs/src/lib.rs b/bin/ofs/src/lib.rs index 03069ef56285..3fc0cadae6b5 100644 --- a/bin/ofs/src/lib.rs +++ b/bin/ofs/src/lib.rs @@ -15,9 +15,6 @@ // specific language governing permissions and limitations // under the License. -mod config; -pub use config::*; - use std::ffi::OsStr; use std::vec::IntoIter; From 85233b4bb6979399d02b2e57268254c5114e3950 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sat, 20 Jan 2024 20:30:13 +0800 Subject: [PATCH 4/7] feat(ofs): fix code --- Cargo.lock | 27 ++------------------------- bin/ofs/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ba1cc8ce27c..3e2dc9d8c06d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2328,16 +2328,6 @@ dependencies = [ "syn 2.0.39", ] -[[package]] -name = "env_filter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_logger" version = "0.10.1" @@ -2351,19 +2341,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "env_logger" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eeb342678d785662fd2514be38c459bb925f02b68dd2a3e0f21d7ef82d979dd" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -4620,7 +4597,7 @@ dependencies = [ "anyhow", "async-trait", "clap", - "env_logger 0.11.0", + "env_logger", "fuse3", "futures-util", "libc", @@ -4641,7 +4618,7 @@ dependencies = [ "assert_cmd", "clap", "dirs", - "env_logger 0.10.1", + "env_logger", "futures", "log", "opendal", diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index 3af867998d22..d36c7a203476 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -45,7 +45,7 @@ tokio = { version = "1.34", features = [ toml = "0.8.8" serde = { version = "1", features = ["derive"] } nix = { version = "0.27.1", features = ["user"] } -env_logger = "0.11" +env_logger = "0.10" clap = { version = "4.4.18", features = ["derive", "env"] } url = "2.5.0" opendal.workspace = true From 9910c2d7d14e030b471b53c5d9d9ec09586e3240 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sat, 20 Jan 2024 20:49:10 +0800 Subject: [PATCH 5/7] feat(ofs): fix code --- bin/ofs/src/bin/ofs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ofs/src/bin/ofs.rs b/bin/ofs/src/bin/ofs.rs index 7a33f8d57ddf..952807053eb8 100644 --- a/bin/ofs/src/bin/ofs.rs +++ b/bin/ofs/src/bin/ofs.rs @@ -43,8 +43,8 @@ struct Config { mount_path: String, /// location of opendal service - /// format: ://: - /// example: s3://127.0.0.1:9000?access_key=xxx&secret_key=xxx + /// format: ://?=&= + /// example: fs://root=/tmp #[arg(short, long, env = "OFS_BACKEND")] backend: String, } From 27f18a753b865da34a9746714a0fa8859f1ef7e0 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sun, 21 Jan 2024 00:02:50 +0800 Subject: [PATCH 6/7] feat(ofs): fix code --- Cargo.lock | 2 -- bin/ofs/Cargo.toml | 2 -- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e2dc9d8c06d..0381b429dd07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4604,9 +4604,7 @@ dependencies = [ "log", "nix 0.27.1", "opendal", - "serde", "tokio", - "toml 0.8.8", "url", ] diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index d36c7a203476..860904d7cead 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -42,8 +42,6 @@ tokio = { version = "1.34", features = [ "rt-multi-thread", "io-std", ] } -toml = "0.8.8" -serde = { version = "1", features = ["derive"] } nix = { version = "0.27.1", features = ["user"] } env_logger = "0.10" clap = { version = "4.4.18", features = ["derive", "env"] } From d2df534a445557ff6c38ffdcb2a7de03e8f453af Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Sun, 21 Jan 2024 00:47:49 +0800 Subject: [PATCH 7/7] feat(ofs): fix code --- bin/ofs/src/bin/ofs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/ofs/src/bin/ofs.rs b/bin/ofs/src/bin/ofs.rs index 952807053eb8..08399b56ef22 100644 --- a/bin/ofs/src/bin/ofs.rs +++ b/bin/ofs/src/bin/ofs.rs @@ -39,18 +39,18 @@ async fn main() -> Result<()> { #[command(version, about)] struct Config { /// fuse mount path - #[arg(short, long, env = "OFS_MOUNT_PATH")] + #[arg(env = "OFS_MOUNT_PATH", index = 1)] mount_path: String, /// location of opendal service /// format: ://?=&= /// example: fs://root=/tmp - #[arg(short, long, env = "OFS_BACKEND")] + #[arg(env = "OFS_BACKEND", index = 2)] backend: String, } async fn fuse() -> Result<()> { - let cfg = Config::parse(); + let cfg = Config::try_parse().context("parse command line arguments")?; let location = Url::parse(&cfg.backend)?; if location.has_host() {