cli_sub.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //! Subcommand enums split out of cli.rs (the 500-line cap).
  2. //! Clap-derive types only — `crate::cli` re-exports them so callers and
  3. //! dispatch keep their import paths.
  4. use clap::{Args, Subcommand};
  5. #[derive(Subcommand)]
  6. pub enum PowerAction {
  7. /// Power off: SSH `sudo shutdown now` + wait + HA `turn_off`.
  8. Off {
  9. #[arg(long)]
  10. cluster: String,
  11. /// Target a specific node within the cluster (default: all).
  12. #[arg(long)]
  13. node: Option<String>,
  14. },
  15. /// Power on: HA `turn_on` only (no SSH; the smart plug wakes the machine).
  16. On {
  17. #[arg(long)]
  18. cluster: String,
  19. /// Target a specific node within the cluster (default: all).
  20. #[arg(long)]
  21. node: Option<String>,
  22. },
  23. /// Switch clusters: disable nodes from source, enable nodes in target.
  24. Switch {
  25. /// Current cluster (nodes + entities to shut down).
  26. #[arg(long)]
  27. from: String,
  28. /// Target cluster (nodes + entities to wake up).
  29. #[arg(long)]
  30. to: String,
  31. },
  32. }
  33. /// `sm121 config` subcommands — manage the global config file.
  34. #[derive(Subcommand)]
  35. pub enum ConfigCommands {
  36. /// Show the active config path and where the global config lives
  37. Path,
  38. /// Create the global config file (template) if it does not exist
  39. InitGlobal,
  40. }
  41. #[derive(Args)]
  42. pub struct PublishArgs {
  43. #[arg(long, required = true)]
  44. pub recipe: String,
  45. /// Cluster whose fabric env + node count fill the generated run script
  46. #[arg(long)]
  47. pub cluster: Option<String>,
  48. /// Output dir (default: ./publish/<recipe>)
  49. #[arg(long)]
  50. pub out: Option<std::path::PathBuf>,
  51. /// Also create a public GitHub gist (requires `gh` CLI, authenticated)
  52. #[arg(long)]
  53. pub gist: bool,
  54. /// After bundling, push the recipe's image to the image registry
  55. /// (`[registry]` config) under its version tag + `latest`.
  56. #[arg(long)]
  57. pub push: bool,
  58. /// Node that has the image for `--push` (default: probe all cluster
  59. /// nodes for the first match).
  60. #[arg(long)]
  61. pub node: Option<String>,
  62. /// Re-push even if the publication ledger already records this image
  63. /// digest (with `--push`).
  64. #[arg(long)]
  65. pub force: bool,
  66. /// Upload the bundle to a recipe registry (see `sm121 registry --help`)
  67. #[arg(long, value_name = "URL")]
  68. pub registry: Option<String>,
  69. /// Registry publish token (or $SM121RECIPES_TOKEN)
  70. #[arg(long)]
  71. pub token: Option<String>,
  72. }
  73. #[derive(Subcommand)]
  74. pub enum RegistryCommands {
  75. /// List recipes on the registry
  76. List {
  77. #[arg(long, value_name = "URL")]
  78. registry: Option<String>,
  79. },
  80. /// Print a registry recipe (recipe.toml)
  81. Show {
  82. name: String,
  83. #[arg(long, value_name = "URL")]
  84. registry: Option<String>,
  85. },
  86. /// Download a recipe into ./recipes/<name>/ (+ ./docker-images/<name>/ if it has an image)
  87. Install {
  88. name: String,
  89. #[arg(long, value_name = "URL")]
  90. registry: Option<String>,
  91. /// Overwrite an existing ./recipes/<name>/
  92. #[arg(long)]
  93. force: bool,
  94. },
  95. }
  96. #[derive(Subcommand)]
  97. pub enum TmuxCommands {
  98. /// Launch cluster via tmux
  99. Serve {
  100. #[arg(long, required = true)]
  101. recipe: String,
  102. #[arg(long, default_value = "auto")]
  103. cluster: String,
  104. /// Skip pre-serve hooks (cluster-level + recipe-level).
  105. #[arg(long)]
  106. skip_before_serve: bool,
  107. },
  108. /// Stop tmux sessions
  109. Stop {
  110. #[arg(long, required = true)]
  111. recipe: String,
  112. #[arg(long, default_value = "auto")]
  113. cluster: String,
  114. },
  115. /// Detailed tmux session status
  116. Status {
  117. #[arg(long, required = true)]
  118. recipe: String,
  119. #[arg(long, default_value = "auto")]
  120. cluster: String,
  121. },
  122. /// Show tmux session logs
  123. Logs {
  124. #[arg(long, required = true)]
  125. recipe: String,
  126. #[arg(long, action = clap::ArgAction::SetTrue)]
  127. follow: bool,
  128. #[arg(long, default_value = "auto")]
  129. cluster: String,
  130. },
  131. /// Attach to head node tmux session
  132. Attach {
  133. #[arg(long, required = true)]
  134. recipe: String,
  135. #[arg(long, default_value = "auto")]
  136. cluster: String,
  137. },
  138. }
  139. /// `sm121 repos` — the configured git recipe repos. `sm121 repos` (no
  140. /// subcommand) lists state; `sm121 repos sync` clones/pulls them now.
  141. #[derive(clap::Args)]
  142. pub struct ReposArgs {
  143. #[command(subcommand)]
  144. pub command: Option<ReposCommands>,
  145. }
  146. #[derive(Clone, clap::Subcommand)]
  147. pub enum ReposCommands {
  148. /// List the configured repos with their state (cloned? archived?
  149. /// last-pull ts? recipe count?)
  150. List,
  151. /// Clone/pull the configured recipe repos now (`--force` re-clones
  152. /// each cached checkout from scratch). `--watch` keeps re-syncing in
  153. /// the background (every `--interval` minutes) so the cache never goes
  154. /// stale between commands — run it detached (nohup/launchd) the way the
  155. /// HA add-on's entrypoint loop does.
  156. Sync {
  157. #[arg(long)]
  158. force: bool,
  159. /// Re-sync continuously (background mode; Ctrl-C to stop)
  160. #[arg(long)]
  161. watch: bool,
  162. /// Re-sync interval in minutes (with --watch; default 10)
  163. #[arg(long, default_value_t = 10)]
  164. interval: u32,
  165. },
  166. }
  167. #[derive(Args)]
  168. pub struct SyncImageArgs {
  169. #[arg(long, required = true)]
  170. pub recipe: String,
  171. #[arg(long, default_value = "auto")]
  172. pub cluster: String,
  173. /// Explicit source node (default: newest image present in the set).
  174. #[arg(long)]
  175. pub source: Option<String>,
  176. }
  177. /// Docker-only launcher flags that the operator actually set — a
  178. /// `deploy = "tmux"` serve warns about each one and ignores it.
  179. pub fn tmux_unsupported_opts(opts: &crate::docker::ServeOpts) -> Vec<&'static str> {
  180. [
  181. (opts.sync_image, "--sync-image"),
  182. (opts.sync_image_source.is_some(), "--sync-image-source"),
  183. (opts.build_node.is_some(), "--build-node"),
  184. (opts.force_build, "--force-build"),
  185. (opts.keep, "--keep"),
  186. (opts.solo.is_some(), "--solo/--no-solo"),
  187. (opts.mirror.is_some(), "--mirror"),
  188. (opts.fit.is_some(), "--fit"),
  189. ]
  190. .iter()
  191. .filter_map(|(set, flag)| if *set { Some(*flag) } else { None })
  192. .collect()
  193. }