Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor commands

+84 -84
+74 -83
cli/src/main.rs
··· 1 1 use crate::sower::*; 2 - use std::env; 3 2 4 3 use clap::Parser; 5 4 use clap::Subcommand; ··· 12 11 #[command(subcommand)] 13 12 action: Actions, 14 13 15 - #[arg(short, long, global = true, value_name = "sower URL")] 14 + #[arg(long, short, global = true)] 15 + name: Option<String>, 16 + 17 + #[arg( 18 + value_enum, 19 + long = "type", 20 + short = 't', 21 + default_value_t = SeedType::Nixos, 22 + global = true, 23 + value_name = "TYPE" 24 + )] 25 + seed_type: SeedType, 26 + 27 + #[arg(short, long, global = true, value_name = "SOWER_URL")] 16 28 url: Option<String>, 17 29 } 18 30 19 31 #[derive(Subcommand)] 20 32 #[command(subcommand_value_name = "ACTION", subcommand_help_heading = "Actions")] 21 33 enum Actions { 22 - /// build targets 23 - Build { 24 - #[arg(short, long, value_name = "seed name")] 25 - name: Option<String>, 34 + /// a seed is an installable served by the sower 35 + Seed { 36 + #[command(subcommand)] 37 + action: SeedCommands, 26 38 }, 27 39 28 - /// upload built targets 29 - Upload { name: Option<String> }, 40 + /// a tree grows from seeds 41 + Tree { 42 + #[command(subcommand)] 43 + action: TreeCommands, 44 + }, 45 + } 30 46 47 + #[derive(Debug, Subcommand)] 48 + #[command( 49 + subcommand_value_name = "ACTION", 50 + subcommand_help_heading = "Seed commands" 51 + )] 52 + enum SeedCommands { 31 53 /// download and activate 32 54 Activate { 33 - #[arg( 34 - value_enum, 35 - long = "type", 36 - short = 't', 37 - default_value_t = SeedType::Nixos, 38 - )] 39 - seed_type: SeedType, 40 - 41 - #[arg(long, short, value_name = "seed name")] 42 - name: Option<String>, 43 - 44 55 #[arg(long, short, value_name = "how to activate nixos")] 45 56 mode: Option<ActivationMode>, 46 57 }, 47 58 48 59 /// download target 49 - Download { 50 - #[arg( 51 - value_enum, 52 - long = "type", 53 - short = 't', 54 - default_value_t = SeedType::Nixos, 55 - )] 56 - seed_type: SeedType, 60 + Download {}, 61 + } 57 62 58 - #[arg(long, short, value_name = "seed name")] 59 - name: Option<String>, 63 + #[derive(Debug, Subcommand)] 64 + #[command( 65 + subcommand_value_name = "ACTION", 66 + subcommand_help_heading = "Tree commands" 67 + )] 68 + enum TreeCommands { 69 + Reboot { 70 + #[arg(long, short, default_value_t = false)] 71 + yes: bool, 60 72 }, 61 73 62 - Reboot { 74 + Upgrade { 75 + #[arg(long, short, value_name = "how to activate nixos")] 76 + mode: Option<ActivationMode>, 77 + 78 + #[arg(long, short, default_value_t = false)] 79 + reboot: bool, 80 + 63 81 #[arg(long, short, default_value_t = false)] 64 82 yes: bool, 65 83 }, ··· 69 87 async fn main() -> Result<(), Box<dyn std::error::Error>> { 70 88 let cli = Cli::parse(); 71 89 72 - match &cli.action { 73 - Actions::Activate { 74 - name, 75 - seed_type, 76 - mode, 77 - .. 78 - } => { 79 - let sower = Sower::new(cli.url.expect("missing url")); 80 - let name = name.clone().unwrap_or(match &seed_type { 81 - SeedType::Nixos => nix::unistd::gethostname() 82 - .expect("Failed getting hostname") 83 - .into_string() 84 - .unwrap(), 85 - SeedType::HomeManager => env::var("USER").expect("can not detect username"), 86 - _ => panic!("Unsupported seed type"), 87 - }); 88 - 89 - let seed = sower 90 - .expect("failed to fetch seed") 91 - .find_seed(name, seed_type.clone()) 92 - .await?; 93 - 94 - let activation = seed 95 - .realize() 96 - .expect("failed to realize") 97 - .activate(&mode) 98 - .expect("failed to activate"); 99 - 100 - println!("{:#?}", activation); 101 - } 102 - 103 - Actions::Download { 104 - name, seed_type, .. 105 - } => { 106 - let sower = Sower::new(cli.url.expect("missing url")); 107 - let name = name.clone().unwrap_or(match seed_type.clone() { 108 - SeedType::Nixos => nix::unistd::gethostname() 109 - .expect("Failed getting hostname") 110 - .into_string() 111 - .unwrap(), 112 - SeedType::HomeManager => env::var("USER").expect("can not detect username"), 113 - _ => panic!("Unsupported seed type"), 114 - }); 90 + let url = cli.url.expect("missing Sower URL"); 91 + let seed = Sower::new(url.clone()) 92 + .expect("failed to find latest seed") 93 + .find_seed(cli.name.clone(), cli.seed_type.clone()) 94 + .await?; 115 95 116 - let seed = sower 117 - .expect("failed to fetch seed") 118 - .find_seed(name, seed_type.clone()) 119 - .await?; 96 + match &cli.action { 97 + Actions::Seed { action } => match action { 98 + SeedCommands::Activate { mode, .. } => { 99 + seed.activate(&mode).expect("failed to activate"); 100 + } 120 101 121 - let seed = seed.realize().expect("failed to realize"); 102 + SeedCommands::Download {} => { 103 + seed.realize().expect("failed to realize"); 104 + } 105 + }, 122 106 123 - println!("{:#?}", seed); 124 - () 125 - } 107 + Actions::Tree { action } => match action { 108 + TreeCommands::Upgrade { mode, reboot, yes } => { 109 + seed.realize() 110 + .expect("failed to realize") 111 + .activate(&mode) 112 + .expect("failed to activate"); 126 113 127 - Actions::Reboot { yes } => Tree::reboot(yes.clone()), 128 - _ => panic!("unsupported action"), 114 + if reboot.clone() { 115 + Tree::reboot(yes.clone()); 116 + } 117 + } 118 + TreeCommands::Reboot { yes } => Tree::reboot(yes.clone()), 119 + }, 129 120 } 130 121 131 122 Ok(())
+10 -1
cli/src/sower.rs
··· 1 1 use clap::ValueEnum; 2 2 use serde::Deserialize; 3 + use std::env; 3 4 use std::fs; 4 5 use std::process::Command; 5 6 use strum::{Display, VariantNames}; ··· 99 100 100 101 pub async fn find_seed( 101 102 &self, 102 - name: String, 103 + name: Option<String>, 103 104 seed_type: SeedType, 104 105 ) -> Result<Seed, Box<dyn std::error::Error>> { 106 + let name = name.clone().unwrap_or(match seed_type.clone() { 107 + SeedType::Nixos | SeedType::NixDarwin => nix::unistd::gethostname() 108 + .expect("Failed getting hostname") 109 + .into_string() 110 + .unwrap(), 111 + SeedType::HomeManager => env::var("USER").expect("can not detect username"), 112 + }); 113 + 105 114 let client = reqwest::Client::new(); 106 115 Ok(client 107 116 .get(&self.url)