1use clap::{Args, Parser, Subcommand};
2use rkubectl_args::{EnvFile, File, KeyValue};
3
4use super::*;
5
6pub use command::ApiResource;
7pub use command::ApiResources;
8pub use command::Auth;
9pub use command::Basic;
10pub use command::ClusterInfo;
11pub use command::ClusterManagement;
12pub use command::Command;
13pub use command::Config;
14pub use command::ConfigMap;
15pub use command::Create;
16pub use command::CreateResource;
17pub use command::Debug;
18pub use command::Delete;
19pub use command::Dump;
20pub use command::Get;
21pub use command::Node;
22pub use command::Secret;
23pub use command::TroubleshootingDebugging;
24
25use context::Context;
26
27mod command;
28mod context;
29
30#[derive(Debug, Parser)]
31#[command(next_line_help = true, max_term_width = 120)]
32pub struct Cli {
33 #[arg(short, long, global = true)]
35 pub debug: bool,
36
37 #[command(flatten, next_display_order = 1000)]
38 pub options: KubeapiOptions,
39
40 #[command(flatten, next_display_order = 2000)]
41 pub namespace: NamespaceOptions,
42
43 #[command(flatten, next_display_order = 3000)]
44 pub config: KubeConfigOptions,
45
46 #[arg(short, long, value_enum, global = true, display_order = 10000)]
47 pub output: Option<OutputFormat>,
48
49 #[command(subcommand)]
50 pub command: Command,
51}
52
53impl Cli {
54 pub fn new() -> Self {
55 Self::parse()
56 }
57
58 pub fn inspect(self) -> Self {
59 debug!(cli = ?self, "rk");
60 self
61 }
62
63 pub async fn exec(self) -> RkResult<()> {
64 let kubeapi = self.kubeapi().await?;
65 let ui = self.ui();
66 let context = Context::new(kubeapi, ui);
67 self.command.exec(&context).await
68 }
69
70 async fn kubeapi(&self) -> kube::Result<Kubeapi> {
71 let namespace = self.namespace.namespace();
72 let kubeapi = Kubeapi::new(&self.config, &self.options, self.debug)
73 .await?
74 .with_namespace(namespace);
75 info!(
76 ctx = kubeapi.cluster_url(),
77 namespace = ?kubeapi.namespace(),
78 "Accessing Kubernetes API server"
79 );
80
81 Ok(kubeapi)
82 }
83
84 fn ui(&self) -> Ui {
85 let output = self.output.unwrap_or_default();
86 Ui::new(output)
87 }
88}
89
90impl Default for Cli {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96#[derive(Clone, Debug, Default, Args)]
97
98pub struct NamespaceOptions {
99 #[arg(short = 'A', long, global = true, conflicts_with = "namespace")]
102 pub all_namespaces: bool,
103
104 #[arg(short = 'n', long, global = true)]
106 pub namespace: Option<String>,
107}
108
109impl NamespaceOptions {
110 fn namespace(&self) -> Namespace {
111 Namespace::new(self.all_namespaces, self.namespace.as_deref())
112 }
113}
114
115#[expect(dead_code)]
116fn metadata(name: impl ToString) -> metav1::ObjectMeta {
117 let name = Some(name.to_string());
118 metav1::ObjectMeta {
119 name,
120 ..default()
135 }
136}