Opinionated Android 15+ Linux Terminal Setup
android linux command-line-tools

Merge pull request #6 from tsirysndr/feat/remote-config

feat: add support for loading config from a remote git repo

authored by tsiry-sandratraina.com and committed by

GitHub 2ae91761 7f4386a5

+401 -8
+283
Cargo.lock
··· 125 125 ] 126 126 127 127 [[package]] 128 + name = "displaydoc" 129 + version = "0.2.5" 130 + source = "registry+https://github.com/rust-lang/crates.io-index" 131 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 132 + dependencies = [ 133 + "proc-macro2", 134 + "quote", 135 + "syn", 136 + ] 137 + 138 + [[package]] 128 139 name = "equivalent" 129 140 version = "1.0.2" 130 141 source = "registry+https://github.com/rust-lang/crates.io-index" 131 142 checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 132 143 133 144 [[package]] 145 + name = "form_urlencoded" 146 + version = "1.2.2" 147 + source = "registry+https://github.com/rust-lang/crates.io-index" 148 + checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 149 + dependencies = [ 150 + "percent-encoding", 151 + ] 152 + 153 + [[package]] 134 154 name = "getrandom" 135 155 version = "0.2.16" 136 156 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 148 168 checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 149 169 150 170 [[package]] 171 + name = "icu_collections" 172 + version = "2.0.0" 173 + source = "registry+https://github.com/rust-lang/crates.io-index" 174 + checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 175 + dependencies = [ 176 + "displaydoc", 177 + "potential_utf", 178 + "yoke", 179 + "zerofrom", 180 + "zerovec", 181 + ] 182 + 183 + [[package]] 184 + name = "icu_locale_core" 185 + version = "2.0.0" 186 + source = "registry+https://github.com/rust-lang/crates.io-index" 187 + checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 188 + dependencies = [ 189 + "displaydoc", 190 + "litemap", 191 + "tinystr", 192 + "writeable", 193 + "zerovec", 194 + ] 195 + 196 + [[package]] 197 + name = "icu_normalizer" 198 + version = "2.0.0" 199 + source = "registry+https://github.com/rust-lang/crates.io-index" 200 + checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 201 + dependencies = [ 202 + "displaydoc", 203 + "icu_collections", 204 + "icu_normalizer_data", 205 + "icu_properties", 206 + "icu_provider", 207 + "smallvec", 208 + "zerovec", 209 + ] 210 + 211 + [[package]] 212 + name = "icu_normalizer_data" 213 + version = "2.0.0" 214 + source = "registry+https://github.com/rust-lang/crates.io-index" 215 + checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 216 + 217 + [[package]] 218 + name = "icu_properties" 219 + version = "2.0.1" 220 + source = "registry+https://github.com/rust-lang/crates.io-index" 221 + checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 222 + dependencies = [ 223 + "displaydoc", 224 + "icu_collections", 225 + "icu_locale_core", 226 + "icu_properties_data", 227 + "icu_provider", 228 + "potential_utf", 229 + "zerotrie", 230 + "zerovec", 231 + ] 232 + 233 + [[package]] 234 + name = "icu_properties_data" 235 + version = "2.0.1" 236 + source = "registry+https://github.com/rust-lang/crates.io-index" 237 + checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 238 + 239 + [[package]] 240 + name = "icu_provider" 241 + version = "2.0.0" 242 + source = "registry+https://github.com/rust-lang/crates.io-index" 243 + checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 244 + dependencies = [ 245 + "displaydoc", 246 + "icu_locale_core", 247 + "stable_deref_trait", 248 + "tinystr", 249 + "writeable", 250 + "yoke", 251 + "zerofrom", 252 + "zerotrie", 253 + "zerovec", 254 + ] 255 + 256 + [[package]] 257 + name = "idna" 258 + version = "1.1.0" 259 + source = "registry+https://github.com/rust-lang/crates.io-index" 260 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 261 + dependencies = [ 262 + "idna_adapter", 263 + "smallvec", 264 + "utf8_iter", 265 + ] 266 + 267 + [[package]] 268 + name = "idna_adapter" 269 + version = "1.2.1" 270 + source = "registry+https://github.com/rust-lang/crates.io-index" 271 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 272 + dependencies = [ 273 + "icu_normalizer", 274 + "icu_properties", 275 + ] 276 + 277 + [[package]] 151 278 name = "indexmap" 152 279 version = "2.10.0" 153 280 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 196 323 ] 197 324 198 325 [[package]] 326 + name = "litemap" 327 + version = "0.8.0" 328 + source = "registry+https://github.com/rust-lang/crates.io-index" 329 + checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 330 + 331 + [[package]] 199 332 name = "memchr" 200 333 version = "2.7.5" 201 334 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 212 345 "serde", 213 346 "serde_yml", 214 347 "toml", 348 + "url", 215 349 ] 216 350 217 351 [[package]] ··· 233 367 checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" 234 368 235 369 [[package]] 370 + name = "percent-encoding" 371 + version = "2.3.2" 372 + source = "registry+https://github.com/rust-lang/crates.io-index" 373 + checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 374 + 375 + [[package]] 376 + name = "potential_utf" 377 + version = "0.1.2" 378 + source = "registry+https://github.com/rust-lang/crates.io-index" 379 + checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 380 + dependencies = [ 381 + "zerovec", 382 + ] 383 + 384 + [[package]] 236 385 name = "proc-macro2" 237 386 version = "1.0.97" 238 387 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 312 461 ] 313 462 314 463 [[package]] 464 + name = "smallvec" 465 + version = "1.15.1" 466 + source = "registry+https://github.com/rust-lang/crates.io-index" 467 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 468 + 469 + [[package]] 470 + name = "stable_deref_trait" 471 + version = "1.2.0" 472 + source = "registry+https://github.com/rust-lang/crates.io-index" 473 + checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 474 + 475 + [[package]] 315 476 name = "strsim" 316 477 version = "0.11.1" 317 478 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 329 490 ] 330 491 331 492 [[package]] 493 + name = "synstructure" 494 + version = "0.13.2" 495 + source = "registry+https://github.com/rust-lang/crates.io-index" 496 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 497 + dependencies = [ 498 + "proc-macro2", 499 + "quote", 500 + "syn", 501 + ] 502 + 503 + [[package]] 332 504 name = "thiserror" 333 505 version = "2.0.14" 334 506 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 349 521 ] 350 522 351 523 [[package]] 524 + name = "tinystr" 525 + version = "0.8.1" 526 + source = "registry+https://github.com/rust-lang/crates.io-index" 527 + checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 528 + dependencies = [ 529 + "displaydoc", 530 + "zerovec", 531 + ] 532 + 533 + [[package]] 352 534 name = "toml" 353 535 version = "0.9.5" 354 536 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 392 574 version = "1.0.18" 393 575 source = "registry+https://github.com/rust-lang/crates.io-index" 394 576 checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 577 + 578 + [[package]] 579 + name = "url" 580 + version = "2.5.6" 581 + source = "registry+https://github.com/rust-lang/crates.io-index" 582 + checksum = "137a3c834eaf7139b73688502f3f1141a0337c5d8e4d9b536f9b8c796e26a7c4" 583 + dependencies = [ 584 + "form_urlencoded", 585 + "idna", 586 + "percent-encoding", 587 + ] 588 + 589 + [[package]] 590 + name = "utf8_iter" 591 + version = "1.0.4" 592 + source = "registry+https://github.com/rust-lang/crates.io-index" 593 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 395 594 396 595 [[package]] 397 596 name = "utf8parse" ··· 496 695 version = "0.7.12" 497 696 source = "registry+https://github.com/rust-lang/crates.io-index" 498 697 checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" 698 + 699 + [[package]] 700 + name = "writeable" 701 + version = "0.6.1" 702 + source = "registry+https://github.com/rust-lang/crates.io-index" 703 + checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 704 + 705 + [[package]] 706 + name = "yoke" 707 + version = "0.8.0" 708 + source = "registry+https://github.com/rust-lang/crates.io-index" 709 + checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 710 + dependencies = [ 711 + "serde", 712 + "stable_deref_trait", 713 + "yoke-derive", 714 + "zerofrom", 715 + ] 716 + 717 + [[package]] 718 + name = "yoke-derive" 719 + version = "0.8.0" 720 + source = "registry+https://github.com/rust-lang/crates.io-index" 721 + checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 722 + dependencies = [ 723 + "proc-macro2", 724 + "quote", 725 + "syn", 726 + "synstructure", 727 + ] 728 + 729 + [[package]] 730 + name = "zerofrom" 731 + version = "0.1.6" 732 + source = "registry+https://github.com/rust-lang/crates.io-index" 733 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 734 + dependencies = [ 735 + "zerofrom-derive", 736 + ] 737 + 738 + [[package]] 739 + name = "zerofrom-derive" 740 + version = "0.1.6" 741 + source = "registry+https://github.com/rust-lang/crates.io-index" 742 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 743 + dependencies = [ 744 + "proc-macro2", 745 + "quote", 746 + "syn", 747 + "synstructure", 748 + ] 749 + 750 + [[package]] 751 + name = "zerotrie" 752 + version = "0.2.2" 753 + source = "registry+https://github.com/rust-lang/crates.io-index" 754 + checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 755 + dependencies = [ 756 + "displaydoc", 757 + "yoke", 758 + "zerofrom", 759 + ] 760 + 761 + [[package]] 762 + name = "zerovec" 763 + version = "0.11.4" 764 + source = "registry+https://github.com/rust-lang/crates.io-index" 765 + checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" 766 + dependencies = [ 767 + "yoke", 768 + "zerofrom", 769 + "zerovec-derive", 770 + ] 771 + 772 + [[package]] 773 + name = "zerovec-derive" 774 + version = "0.11.1" 775 + source = "registry+https://github.com/rust-lang/crates.io-index" 776 + checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 777 + dependencies = [ 778 + "proc-macro2", 779 + "quote", 780 + "syn", 781 + ]
+1
Cargo.toml
··· 11 11 serde = { version = "1.0.219", features = ["serde_derive", "derive"] } 12 12 serde_yml = "0.0.12" 13 13 toml = "0.9.5" 14 + url = "2.5.6"
+8
README.md
··· 88 88 89 89 You can customize it and run `oh-my-droid apply` to apply the changes. 90 90 91 + ## Remote Configuration 92 + 93 + You can use a remote configuration file by specifying a git URL: 94 + 95 + ```bash 96 + oh-my-droid apply github:tsirysndr/pkgs 97 + ``` 98 + 91 99 ## License 92 100 93 101 This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
+96 -6
src/cmd/setup.rs
··· 1 - use std::path::Path; 1 + use std::{fs, path::Path}; 2 2 3 - use anyhow::Error; 3 + use anyhow::{Context, Error}; 4 4 use owo_colors::OwoColorize; 5 + use url::Url; 5 6 6 - use crate::{config::Configuration, consts::CONFIG_FILE, diff::compare_configurations}; 7 + use crate::{ 8 + command::run_command, config::Configuration, consts::CONFIG_FILE, diff::compare_configurations, 9 + }; 7 10 8 - pub fn setup(dry_run: bool, no_confirm: bool) -> Result<(), Error> { 11 + pub fn setup(dry_run: bool, no_confirm: bool, config_path: &str) -> Result<(), Error> { 9 12 let mut cfg = Configuration::default(); 10 13 11 - if std::path::Path::new(CONFIG_FILE).exists() { 12 - let toml_str = std::fs::read_to_string(CONFIG_FILE)?; 14 + let repo_url = parse_config_path(config_path)?; 15 + 16 + let toml_config = match clone_repo(&repo_url) { 17 + Ok(toml_config) => toml_config, 18 + Err(err) => { 19 + if !repo_url.starts_with("https://") { 20 + repo_url 21 + } else { 22 + return Err(err); 23 + } 24 + } 25 + }; 26 + 27 + if std::path::Path::new(&toml_config).exists() { 28 + let toml_str = std::fs::read_to_string(&toml_config)?; 13 29 cfg = toml::from_str(&toml_str)?; 30 + } 31 + 32 + if toml_config != CONFIG_FILE && !std::path::Path::new(&toml_config).exists() { 33 + return Err(anyhow::anyhow!( 34 + "{} does not exist.", 35 + toml_config.as_str().green() 36 + )); 14 37 } 15 38 16 39 let home_dir = ··· 63 86 64 87 Ok(()) 65 88 } 89 + 90 + fn parse_config_path(config_path: &str) -> Result<String, Error> { 91 + if config_path.starts_with("github:") { 92 + let repo = &config_path["github:".len()..]; 93 + return Ok(format!("https://github.com/{}.git", repo)); 94 + } 95 + 96 + if config_path.starts_with("tangled:") { 97 + let repo = &config_path["tangled:".len()..]; 98 + return Ok(format!("https://tangled.sh/{}.git", repo)); 99 + } 100 + 101 + Ok(config_path.to_string()) 102 + } 103 + 104 + fn clone_repo(repo_url: &str) -> Result<String, Error> { 105 + if !repo_url.starts_with("https://") { 106 + return Err(anyhow::anyhow!( 107 + "Unsupported repository URL. Only HTTPS URLs are supported." 108 + )); 109 + } 110 + 111 + // extract repo name: username-repo: e.g: https://github.com/tsirysndr/pkgs.git -> tsirysndr-pkgs 112 + let repo_name = extract_repo_name(repo_url).context("Failed to extract repository name")?; 113 + let home_dir = dirs::home_dir().context("Failed to get home directory")?; 114 + let cache = home_dir.join(".oh-my-droid").join("cache"); 115 + fs::create_dir_all(&cache)?; 116 + let dest = cache.join(repo_name); 117 + 118 + run_command( 119 + "bash", 120 + &["-c", "type git || (apt update && apt install -y git)"], 121 + )?; 122 + 123 + match dest.exists() { 124 + true => { 125 + run_command("git", &["-C", dest.to_str().unwrap(), "pull"])?; 126 + } 127 + false => { 128 + run_command( 129 + "git", 130 + &["clone", "--depth", "1", repo_url, dest.to_str().unwrap()], 131 + )?; 132 + } 133 + } 134 + 135 + if !dest.join("oh-my-droid.toml").exists() { 136 + return Err(anyhow::anyhow!( 137 + "The repository does not contain an oh-my-droid.toml configuration file." 138 + )); 139 + } 140 + 141 + Ok(dest.join("oh-my-droid.toml").to_str().unwrap().to_string()) 142 + } 143 + 144 + fn extract_repo_name(url: &str) -> Option<String> { 145 + let parsed = Url::parse(url).ok()?; 146 + let mut segments = parsed.path_segments()?; 147 + let username = segments.next()?; 148 + let mut repo = segments.next()?; 149 + 150 + if let Some(stripped) = repo.strip_suffix(".git") { 151 + repo = stripped; 152 + } 153 + 154 + Some(format!("{}-{}", username, repo)) 155 + }
+13 -2
src/main.rs
··· 43 43 .about("Set up the environment with the default configuration.") 44 44 .arg(arg!(-d --"dry-run" "Simulate the setup process without making any changes.")) 45 45 .arg(arg!(-y --"yes" "Skip confirmation prompts during setup.")) 46 + .arg( 47 + arg!([config] "Path to a custom configuration file or a remote git repository e.g., github:tsirysndr/pkgs") 48 + .default_value(CONFIG_FILE), 49 + ) 46 50 .alias("apply"), 47 51 ) 48 52 .arg(arg!(-d --"dry-run" "Simulate the setup process without making any changes.")) 49 53 .arg(arg!(-y --"yes" "Skip confirmation prompts during setup.")) 54 + .arg( 55 + arg!([config] "Path to a custom configuration file or a remote git repository e.g., github:tsirysndr/pkgs") 56 + .default_value(CONFIG_FILE), 57 + ) 58 + .after_help("If no subcommand is provided, the 'setup' command will be executed by default.") 50 59 } 51 60 52 61 fn main() -> Result<(), Error> { ··· 57 66 Some(("setup", args)) => { 58 67 let yes = args.get_flag("yes"); 59 68 let dry_run = args.get_flag("dry-run"); 60 - setup(dry_run, yes)? 69 + let config = args.get_one::<String>("config").unwrap(); 70 + setup(dry_run, yes, config)? 61 71 } 62 72 _ => { 63 73 let yes = matches.get_flag("yes"); 64 74 let dry_run = matches.get_flag("dry-run"); 65 - setup(dry_run, yes)? 75 + let config = matches.get_one::<String>("config").unwrap(); 76 + setup(dry_run, yes, config)? 66 77 } 67 78 } 68 79