This is an automated email from the ASF dual-hosted git repository.
psiace pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal-oli.git
The following commit(s) were added to refs/heads/main by this push:
new bb2c686 feat: implement `config view` (#9)
bb2c686 is described below
commit bb2c686a170c3286a809bcfb304964db458606ea
Author: Ruihang Xia <[email protected]>
AuthorDate: Wed Nov 26 11:48:29 2025 +0800
feat: implement `config view` (#9)
Signed-off-by: Ruihang Xia <[email protected]>
---
Cargo.lock | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-
Cargo.toml | 1 +
src/commands/config.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++
src/commands/mod.rs | 3 ++
src/config/mod.rs | 8 ++++
5 files changed, 218 insertions(+), 1 deletion(-)
diff --git a/Cargo.lock b/Cargo.lock
index ab7ce87..db1aa01 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -331,7 +331,7 @@ version = "7.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a"
dependencies = [
- "crossterm",
+ "crossterm 0.28.1",
"unicode-segmentation",
"unicode-width",
]
@@ -387,6 +387,15 @@ dependencies = [
"tiny-keccak",
]
+[[package]]
+name = "convert_case"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -424,6 +433,24 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "crossterm"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "derive_more",
+ "document-features",
+ "mio",
+ "parking_lot",
+ "rustix 1.0.7",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
@@ -469,6 +496,27 @@ dependencies = [
"powerfmt",
]
+[[package]]
+name = "derive_more"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "difflib"
version = "0.4.0"
@@ -534,6 +582,21 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+[[package]]
+name = "document-features"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
+dependencies = [
+ "litrs",
+]
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
[[package]]
name = "either"
version = "1.15.0"
@@ -1067,6 +1130,19 @@ dependencies = [
"generic-array",
]
+[[package]]
+name = "inquire"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2628910d0114e9139056161d8644a2026be7b117f8498943f9437748b04c9e0a"
+dependencies = [
+ "bitflags",
+ "crossterm 0.29.0",
+ "dyn-clone",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
[[package]]
name = "insta"
version = "1.43.1"
@@ -1213,6 +1289,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+[[package]]
+name = "litrs"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
+
[[package]]
name = "lock_api"
version = "0.4.12"
@@ -1283,6 +1365,7 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
+ "log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
@@ -1373,6 +1456,7 @@ dependencies = [
"humantime",
"humantime-serde",
"indicatif",
+ "inquire",
"insta",
"insta-cmd",
"opendal",
@@ -2184,6 +2268,27 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "signal-hook"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
[[package]]
name = "signal-hook-registry"
version = "1.4.5"
diff --git a/Cargo.toml b/Cargo.toml
index 52305b2..66a56b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,6 +38,7 @@ humansize = { version = "2.1" }
humantime = { version = "2.2" }
humantime-serde = { version = "1.1" }
indicatif = { version = "0.18" }
+inquire = { version = "0.9", default-features = false, features =
["crossterm"] }
opendal = { version = "0.54.0", features = [
"services-azblob",
"services-azdls",
diff --git a/src/commands/config.rs b/src/commands/config.rs
new file mode 100644
index 0000000..b543c34
--- /dev/null
+++ b/src/commands/config.rs
@@ -0,0 +1,100 @@
+// 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 anyhow::Result;
+use inquire::Select;
+use inquire::error::InquireError;
+
+use crate::config::Config;
+use crate::params::config::ConfigParams;
+
+#[derive(Debug, clap::Parser)]
+#[command(
+ name = "config",
+ about = "Manage oli configuration",
+ disable_version_flag = true
+)]
+pub struct ConfigCmd {
+ #[command(subcommand)]
+ subcommand: ConfigSubcommand,
+}
+
+#[derive(Debug, clap::Subcommand)]
+enum ConfigSubcommand {
+ View(ConfigViewCmd),
+}
+
+impl ConfigCmd {
+ pub fn run(self) -> Result<()> {
+ match self.subcommand {
+ ConfigSubcommand::View(cmd) => cmd.run(),
+ }
+ }
+}
+
+#[derive(Debug, clap::Args)]
+#[command(name = "view", about = "Inspect configured profiles")]
+pub struct ConfigViewCmd {
+ #[command(flatten)]
+ pub config_params: ConfigParams,
+}
+
+impl ConfigViewCmd {
+ pub fn run(self) -> Result<()> {
+ let cfg = Config::load(&self.config_params.config)?;
+ let mut profiles = cfg.profile_names();
+
+ if profiles.is_empty() {
+ println!(
+ "No configuration profiles found in {}",
+ self.config_params.config.display()
+ );
+ return Ok(());
+ }
+
+ profiles.sort();
+ let selected = match Select::new("Select a profile to view",
profiles).prompt() {
+ Ok(profile) => profile,
+ Err(InquireError::OperationCanceled |
InquireError::OperationInterrupted) => {
+ return Ok(());
+ }
+ Err(err) => return Err(err.into()),
+ };
+
+ let Some(options) = cfg.profile(&selected) else {
+ // Profiles are loaded up front, so missing here would indicate a
race.
+ println!("Profile `{selected}` is no longer available.");
+ return Ok(());
+ };
+
+ println!("Profile: {selected}");
+ println!("--------------------------------");
+ for (k, v) in ordered_entries(options) {
+ println!("{k} = {v}");
+ }
+
+ Ok(())
+ }
+}
+
+fn ordered_entries(options: &HashMap<String, String>) -> Vec<(&String,
&String)> {
+ let mut entries = options.iter().collect::<Vec<_>>();
+ entries.sort_by(|a, b| a.0.cmp(b.0));
+ entries
+}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 1dd7182..5696aff 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -19,6 +19,7 @@
pub mod bench;
pub mod cat;
+pub mod config;
pub mod cp;
pub mod edit;
pub mod ls;
@@ -33,6 +34,7 @@ pub enum OliSubcommand {
Cat(cat::CatCmd),
Cp(cp::CopyCmd),
Edit(edit::EditCmd),
+ Config(config::ConfigCmd),
Ls(ls::LsCmd),
Rm(rm::RmCmd),
Stat(stat::StatCmd),
@@ -47,6 +49,7 @@ impl OliSubcommand {
Self::Cat(cmd) => cmd.run(),
Self::Cp(cmd) => cmd.run(),
Self::Edit(cmd) => cmd.run(),
+ Self::Config(cmd) => cmd.run(),
Self::Ls(cmd) => cmd.run(),
Self::Rm(cmd) => cmd.run(),
Self::Stat(cmd) => cmd.run(),
diff --git a/src/config/mod.rs b/src/config/mod.rs
index d6e467d..4c493e7 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -163,6 +163,14 @@ impl Config {
Ok((op, path))
}
+ pub fn profile_names(&self) -> Vec<String> {
+ self.profiles.keys().cloned().collect()
+ }
+
+ pub fn profile(&self, name: &str) -> Option<&HashMap<String, String>> {
+ self.profiles.get(name)
+ }
+
pub fn operator(&self, profile_name: &str) -> Result<Operator> {
let profile = self
.profiles