diff --git a/CHANGELOG.md b/CHANGELOG.md index 96afd06..5ec6ad1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ ## Unreleased +### Added + +- Add `--completions` CLI flag. + ### Changed - **BREAKING**: Use gauges for `system_used_memory` and `system_total_memory`. +- Update dependencies. ## 0.9.5 (2026-05-25) diff --git a/Cargo.lock b/Cargo.lock index 227a638..1182379 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b657e772794c6b04730ea897b66a058ccd866c16d1967da05eeeecec39043fe" dependencies = [ "crypto-common 0.2.1", - "inout 0.2.2", + "inout", ] [[package]] @@ -562,15 +562,6 @@ dependencies = [ "rand_pcg", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "block-padding" version = "0.4.2" @@ -749,7 +740,7 @@ checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" dependencies = [ "block-buffer 0.12.0", "crypto-common 0.2.1", - "inout 0.2.2", + "inout", "zeroize", ] @@ -775,6 +766,15 @@ dependencies = [ "strsim 0.11.1", ] +[[package]] +name = "clap_complete" +version = "4.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.6.1" @@ -1122,12 +1122,12 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "5.0.0-pre.6" +version = "5.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335f1947f241137a14106b6f5acc5918a5ede29c9d71d3f2cb1678d5075d9fc3" +checksum = "4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bf" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures 0.3.0", "curve25519-dalek-derive", "digest 0.11.2", "fiat-crypto", @@ -1453,9 +1453,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "3.0.0-pre.7" +version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20449acd54b660981ae5caa2bcb56d1fe7f25f2e37a38ec507400fab034d4bb6" +checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60" dependencies = [ "curve25519-dalek", "ed25519", @@ -1475,22 +1475,22 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" -version = "0.14.0-rc.32" +version = "0.14.0-rc.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda94f31325c4275e9706adecbb6f0650dee2f904c915a98e3d81adaaaa757aa" +checksum = "102d3643d30dd8b559613c5cced68317199597fffb278cdc88daa2ef7fafc935" dependencies = [ "base16ct 1.0.0", "crypto-bigint", "crypto-common 0.2.1", "digest 0.11.2", + "ff", + "group", "hkdf", "hybrid-array", "once_cell", "pem-rfc7468", "pkcs8", "rand_core 0.10.0", - "rustcrypto-ff", - "rustcrypto-group", "sec1", "subtle", "zeroize", @@ -1640,6 +1640,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" +dependencies = [ + "rand_core 0.10.0", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.3.0" @@ -1928,11 +1938,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.0", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1950,6 +1962,17 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +[[package]] +name = "group" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" +dependencies = [ + "ff", + "rand_core 0.10.0", + "subtle", +] + [[package]] name = "h2" version = "0.4.12" @@ -2474,23 +2497,13 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding 0.3.3", - "generic-array 0.14.7", -] - [[package]] name = "inout" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "block-padding 0.4.2", + "block-padding", "hybrid-array", ] @@ -2902,9 +2915,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md5" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" [[package]] name = "memchr" @@ -3304,9 +3317,9 @@ dependencies = [ [[package]] name = "p256" -version = "0.14.0-rc.9" +version = "0.14.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b97e3bf0465157ae90975ff52dbeb1362ba618924878c9f74c25baa27a65f9a" +checksum = "41adc63effe99d48837a8cc0e6d7a77e32ae6a07f6000df466178dbc2193093e" dependencies = [ "ecdsa", "elliptic-curve", @@ -3317,9 +3330,9 @@ dependencies = [ [[package]] name = "p384" -version = "0.14.0-rc.9" +version = "0.14.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437f30ebcb1e16ff48acead5f08bd69fbcdbc82421687bb48af5c315a0bfab03" +checksum = "9bd5333afa5ae0347f39e6a0f2c9c155da431583fd71fe5555bd0521b4ccaf02" dependencies = [ "ecdsa", "elliptic-curve", @@ -3331,9 +3344,9 @@ dependencies = [ [[package]] name = "p521" -version = "0.14.0-rc.9" +version = "0.14.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9fd792bab86ecf6249561752fb5a413511f999887107dd054bbda5143743d7" +checksum = "a3a5297f53dc16d35909060ba3032cff7867e8809f01e273ff325579d5f0ceae" dependencies = [ "base16ct 1.0.0", "ecdsa", @@ -3637,23 +3650,23 @@ dependencies = [ [[package]] name = "primefield" -version = "0.14.0-rc.9" +version = "0.14.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b52e6ee42db392378a95622b463c9740631171d1efce43fa445a569c1600cb6" +checksum = "f845ec3240cd5ed5e1e31cf3ff633a5bf47c698dc4092ba9e767415b3d393406" dependencies = [ "crypto-bigint", "crypto-common 0.2.1", + "ff", "rand_core 0.10.0", - "rustcrypto-ff", "subtle", "zeroize", ] [[package]] name = "primeorder" -version = "0.14.0-rc.9" +version = "0.14.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0556580e42c19833f5d232aca11a7687a503ee41f937b54f5ae1d50fc2a6a36a" +checksum = "7d2793f22b9b6fd11ef3ac1d59bf003c2573593e4968702341605c2748fd90bf" dependencies = [ "elliptic-curve", ] @@ -4144,14 +4157,14 @@ dependencies = [ [[package]] name = "russh" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67013f080c226e5a34db1c71f2567f44d95a6300005bb6cd4e2c8fe3c326d1b" +checksum = "bbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0" dependencies = [ "aes", "aws-lc-rs", "bitflags 2.10.0", - "block-padding 0.4.2", + "block-padding", "byteorder", "bytes", "cbc", @@ -4170,12 +4183,11 @@ dependencies = [ "flate2", "futures", "generic-array 1.3.5", - "getrandom 0.2.16", + "getrandom 0.4.2", "ghash", "hex-literal", - "hkdf", "hmac", - "inout 0.1.4", + "inout", "internal-russh-num-bigint", "keccak", "log", @@ -4266,27 +4278,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustcrypto-ff" -version = "0.14.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6" -dependencies = [ - "rand_core 0.10.0", - "subtle", -] - -[[package]] -name = "rustcrypto-group" -version = "0.14.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "369f9b61aa45933c062c9f6b5c3c50ab710687eca83dd3802653b140b43f85ed" -dependencies = [ - "rand_core 0.10.0", - "rustcrypto-ff", - "subtle", -] - [[package]] name = "rusticata-macros" version = "4.1.0" @@ -4475,6 +4466,7 @@ dependencies = [ "bytesize", "chrono", "clap", + "clap_complete", "color-eyre", "crossterm", "dashmap", diff --git a/Cargo.toml b/Cargo.toml index afb91fb..cd133b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ bytes = "1.11.1" bytesize = "2.3.1" chrono = "0.4.44" clap = { version = "4.6.1", features = ["derive", "string"] } +clap_complete = "4.6.5" color-eyre = "0.6.5" crossterm = { version = "0.29.0", default-features = false } dashmap = "6.1.0" @@ -71,7 +72,7 @@ reqwest = { version = "0.13.3", optional = true, default-features = false, featu "json", "rustls", ] } -russh = "0.61.1" +russh = "0.61.2" rustls = "0.23.40" rustls-acme = { version = "0.15.2", optional = true, default-features = false, features = [ "tokio", diff --git a/book/src/cli.md b/book/src/cli.md index 3da592b..c017589 100644 --- a/book/src/cli.md +++ b/book/src/cli.md @@ -18,6 +18,11 @@ Expose HTTP/SSH/TCP services through SSH port forwarding. This option disables subdomains. + --completions <COMPLETIONS> + Generate shell completions for Sandhole + + [possible values: bash, elvish, fish, powershell, zsh] + --domain-redirect <URL> Where to redirect requests to the root domain diff --git a/flake.nix b/flake.nix index faa06f7..c7ba36b 100644 --- a/flake.nix +++ b/flake.nix @@ -98,18 +98,15 @@ { packages.${system} = packages; - apps.${system}.default = { - type = "app"; - program = lib.getExe self.packages.${system}.default; - meta = { - name = "sandhole"; - description = "Expose HTTP/SSH/TCP services through SSH port forwarding"; - homepage = "https://sandhole.com.br"; - license = lib.licenses.mit; - mainProgram = "sandhole"; - platforms = lib.platforms.linux ++ lib.platforms.darwin; + apps.${system}.default = + let + sandhole = self.packages.${system}.default; + in + { + type = "app"; + program = lib.getExe sandhole; + inherit (sandhole) meta; }; - }; checks.${system} = checks; diff --git a/justfile b/justfile index 97c7b4a..22bc7f8 100644 --- a/justfile +++ b/justfile @@ -18,7 +18,7 @@ cli: echo "" >> book/src/cli.md echo "---" >> book/src/cli.md echo "" >> book/src/cli.md - cat result >> book/src/cli.md + cat result/cli.html >> book/src/cli.md nixos-docs: nix-build ./nix -A packages._docs diff --git a/nix/checks.nix b/nix/checks.nix index 1f7fc73..57ca82b 100644 --- a/nix/checks.nix +++ b/nix/checks.nix @@ -4,21 +4,12 @@ craneLib, pkgs, sandhole, + sandhole-no-default-features, src, ... }: { - inherit sandhole; - - sandhole-no-default-features = craneLib.buildPackage ( - commonArgs - // { - inherit cargoArtifacts; - pname = "sandhole-no-default-features"; - cargoExtraArgs = "--locked --no-default-features"; - doCheck = false; - } - ); + inherit sandhole sandhole-no-default-features; sandhole-clippy = craneLib.cargoClippy ( commonArgs diff --git a/nix/default.nix b/nix/default.nix index c279da5..ce9a8e9 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -28,6 +28,7 @@ let nativeBuildInputs = [ pkgs.cmake + pkgs.installShellFiles pkgs.perl ] ++ lib.optionals (system == "x86_64-darwin" || system == "aarch64-darwin") [ pkgs.lld ]; @@ -40,17 +41,36 @@ let // { inherit cargoArtifacts; doCheck = false; - meta.mainProgram = "sandhole"; + postInstall = lib.optionalString (pkgs.stdenv.buildPlatform.canExecute pkgs.stdenv.hostPlatform) '' + $out/bin/sandhole --completions bash + installShellCompletion --cmd sandhole \ + --bash <($out/bin/sandhole --completions bash) \ + --fish <($out/bin/sandhole --completions fish) \ + --zsh <($out/bin/sandhole --completions zsh) + ''; + meta = { + name = "sandhole"; + description = "Expose HTTP/SSH/TCP services through SSH port forwarding"; + homepage = "https://sandhole.com.br"; + license = lib.licenses.mit; + mainProgram = "sandhole"; + platforms = lib.platforms.linux ++ lib.platforms.darwin; + }; } ); + + sandhole-no-default-features = sandhole.overrideAttrs { + cargoExtraArgs = "--locked --no-default-features"; + }; in { - inherit sandhole; + inherit sandhole sandhole-no-default-features; packages = import ./packages.nix { inherit pkgs sandhole + sandhole-no-default-features ; }; @@ -61,6 +81,7 @@ in craneLib pkgs sandhole + sandhole-no-default-features src ; }; diff --git a/nix/packages.nix b/nix/packages.nix index 865149d..c6bcf47 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -1,6 +1,7 @@ { pkgs, sandhole, + sandhole-no-default-features, ... }: let @@ -25,7 +26,7 @@ let }; in { - inherit sandhole; + inherit sandhole sandhole-no-default-features; default = sandhole; _docs = @@ -42,7 +43,8 @@ in ]; } '' - to-html --no-prompt "sandhole --help" > $out + mkdir $out + to-html --no-prompt "sandhole --help" > $out/cli.html ''; _book = pkgs.stdenv.mkDerivation { diff --git a/npins/default.nix b/npins/default.nix index 884fc8c..8ec5eca 100644 --- a/npins/default.nix +++ b/npins/default.nix @@ -65,7 +65,9 @@ let if pkgs == null then { inherit (builtins) fetchTarball fetchurl; - # For some fucking reason, fetchGit has a different signature than the other builtin fetchers … + # Frustratingly, due to flakes and `fetchTree`, `fetchGit` + # has a different signature than the other builtin + # fetchers fetchGit = args: (builtins.fetchGit args).outPath; } else @@ -95,7 +97,6 @@ let }; }; - # Dispatch to the correct code path based on the type path = if spec.type == "Git" then mkGitSource fetchers spec @@ -105,8 +106,8 @@ let mkPyPiSource fetchers spec else if spec.type == "Channel" then mkChannelSource fetchers spec - else if spec.type == "Tarball" then - mkTarballSource fetchers spec + else if spec.type == "Url" || spec.type == "MutableUrl" then + mkUrlSource fetchers spec else if spec.type == "Container" then mkContainerSource pkgs spec else @@ -192,16 +193,20 @@ let sha256 = hash; }; - mkTarballSource = - { fetchTarball, ... }: + mkUrlSource = + { + fetchTarball, + fetchurl, + ... + }: { url, - locked_url ? url, hash, + unpack, ... }: - fetchTarball { - url = locked_url; + (if unpack then fetchTarball else fetchurl) { + inherit url; sha256 = hash; }; @@ -211,16 +216,22 @@ let image_name, image_tag, image_digest, + hash, ... - }: + }@args: if pkgs == null then builtins.throw "container sources require passing in a Nixpkgs value: https://github.com/andir/npins/blob/master/README.md#using-the-nixpkgs-fetchers" else - pkgs.dockerTools.pullImage { - imageName = image_name; - imageDigest = image_digest; - finalImageTag = image_tag; - }; + pkgs.dockerTools.pullImage ( + { + imageName = image_name; + imageDigest = image_digest; + finalImageTag = image_tag; + hash = hash; + } + // (if args.arch or null != null then { arch = args.arch; } else { }) + ); + in mkFunctor ( { @@ -231,7 +242,7 @@ mkFunctor ( if builtins.isPath input then # while `readFile` will throw an error anyways if the path doesn't exist, # we still need to check beforehand because *our* error can be caught but not the one from the builtin - # *piegames sighs* + # See: if builtins.pathExists input then builtins.fromJSON (builtins.readFile input) else @@ -242,7 +253,7 @@ mkFunctor ( throw "Unsupported input type ${builtins.typeOf input}, must be a path or an attrset"; version = data.version; in - if version == 7 then + if version == 8 then builtins.mapAttrs (name: spec: mkFunctor (mkSource name spec)) data.pins else throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/npins/sources.json b/npins/sources.json index d1c8677..ab92f6d 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -9,15 +9,16 @@ }, "branch": "master", "submodules": false, - "revision": "27711550d109bf6236478dc9f53b9e29c1a374c5", - "url": "https://github.com/ipetkov/crane/archive/27711550d109bf6236478dc9f53b9e29c1a374c5.tar.gz", - "hash": "sha256-5fDkKTYEgue2klksd52WvcXfZdY1EIlbk0QggAwpFog=" + "revision": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37", + "url": "https://github.com/ipetkov/crane/archive/59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37.tar.gz", + "hash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=" }, "nixpkgs": { "type": "Channel", "name": "nixpkgs-unstable", - "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre958799.917fec990948/nixexprs.tar.xz", - "hash": "sha256-QKxBW7o8gmUwDXQhsbIb0JCoUgCr8B80ltkjbg840UQ=" + "artifact": "nixexprs.tar.xz", + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1009182.ffa10e26ae11/nixexprs.tar.xz", + "hash": "sha256-JX05Ms/dk0c+UoW9IqQriB53HNZFckX9Qd3EJqmcqEw=" }, "rust-overlay": { "type": "Git", @@ -28,10 +29,10 @@ }, "branch": "master", "submodules": false, - "revision": "40b0a3a193e0840c76174b4a322874c8f6dd0a63", - "url": "https://github.com/oxalica/rust-overlay/archive/40b0a3a193e0840c76174b4a322874c8f6dd0a63.tar.gz", - "hash": "sha256-aU9nlrS9S+IJ2EiCzsaxzOXUhggogqTrJojBicE6Oeg=" + "revision": "27b7e78c6935293ee868469cc4172e9b8b17823b", + "url": "https://github.com/oxalica/rust-overlay/archive/27b7e78c6935293ee868469cc4172e9b8b17823b.tar.gz", + "hash": "sha256-4+8gPeiPeud89mjo865RwpqmKwa1MThRsq2SvRxo7mg=" } }, - "version": 7 + "version": 8 } diff --git a/src/config.rs b/src/config.rs index d34eec8..e7e4f50 100644 --- a/src/config.rs +++ b/src/config.rs @@ -79,20 +79,24 @@ pub enum LogFormat { #[derive(Debug, Args, PartialEq)] #[group(required = true, multiple = false)] -pub struct Domain { +pub struct Mode { /// The root domain of the application. #[arg( long, value_parser = validate_domain, - group = "sandhole_domain" + group = "sandhole_mode" )] pub domain: Option, /// Whether to run Sandhole without a root domain. /// /// This option disables subdomains. - #[arg(long, default_value_t = false, group = "sandhole_domain")] + #[arg(long, default_value_t = false, group = "sandhole_mode")] pub no_domain: bool, + + /// Generate shell completions for Sandhole. + #[arg(long, group = "sandhole_mode")] + pub completions: Option, } // CLI configuration for Sandhole. @@ -101,7 +105,7 @@ pub struct Domain { #[command(version, about, long_about = None)] pub struct ApplicationConfig { #[command(flatten)] - pub domain: Domain, + pub mode: Mode, /// Where to redirect requests to the root domain. #[arg( @@ -569,7 +573,7 @@ mod application_config_tests { use clap::Parser; use ipnet::IpNet; - use crate::config::{Domain, LoadBalancingAlgorithm, LogFormat}; + use crate::config::{LoadBalancingAlgorithm, LogFormat, Mode}; use super::{ApplicationConfig, BindHostnames, LoadBalancingStrategy, RandomSubdomainSeed}; @@ -579,9 +583,10 @@ mod application_config_tests { assert_eq!( config, ApplicationConfig { - domain: Domain { + mode: Mode { domain: Some("foobar.tld".into()), no_domain: false, + completions: None, }, domain_redirect: "https://github.com/EpicEric/sandhole".into(), user_keys_directory: "./deploy/user_keys/".into(), @@ -712,9 +717,10 @@ mod application_config_tests { assert_eq!( config, ApplicationConfig { - domain: Domain { + mode: Mode { domain: None, no_domain: true, + completions: None, }, domain_redirect: "https://sandhole.eric.dev.br".into(), user_keys_directory: "/etc/user_keys/".into(), @@ -781,6 +787,19 @@ mod application_config_tests { ) } + #[test_log::test] + fn parses_completions() { + let config = ApplicationConfig::parse_from(["sandhole", "--completions", "fish"]); + assert_eq!( + config.mode, + Mode { + domain: None, + no_domain: false, + completions: Some(clap_complete::Shell::Fish), + } + ) + } + #[test_log::test] fn fails_to_parse_if_invalid_domain() { let Err(error) = ApplicationConfig::try_parse_from(["sandhole", "--domain=.foobar.tld"]) diff --git a/src/entrypoint.rs b/src/entrypoint.rs index 11dbfa2..6e4b12a 100644 --- a/src/entrypoint.rs +++ b/src/entrypoint.rs @@ -103,7 +103,7 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { .into()); } } - if config.domain.no_domain { + if config.mode.no_domain { if config.allow_requested_subdomains { #[cfg(not(coverage_nightly))] tracing::warn!("--allow-requested-subdomains has no effect with --no-domain"); @@ -332,7 +332,7 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { let builder = AddressDelegator::builder() .resolver(DnsResolver::new()?) .txt_record_prefix(config.txt_record_prefix) - .maybe_root_domain(config.domain.domain.clone()) + .maybe_root_domain(config.mode.domain.clone()) .bind_hostnames(config.bind_hostnames) .force_random_subdomains(!config.allow_requested_subdomains) .maybe_random_subdomain_seed(config.random_subdomain_seed) @@ -369,7 +369,7 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { } }); // Configure the default domain redirect for Sandhole. - let domain_redirect = config.domain.domain.clone().map(|from| { + let domain_redirect = config.mode.domain.clone().map(|from| { Arc::new(DomainRedirect { from, to: config.domain_redirect, @@ -601,7 +601,7 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { }); let admin_notifications = Arc::new(Mutex::default()); let notifications_clone = Arc::clone(&admin_notifications); - let domain_clone = config.domain.domain.clone(); + let domain_clone = config.mode.domain.clone(); let certificates_clone = Arc::clone(&certificates); // Periodically check for problems (every 10 seconds) and update notifications. tokio::spawn(async move { @@ -711,7 +711,7 @@ pub async fn entrypoint(config: ApplicationConfig) -> color_eyre::Result<()> { api_login, address_delegator: addressing, tcp_handler, - domain: config.domain.domain, + domain: config.mode.domain, http_port: config.http_port.into(), https_port: config.https_port.into(), ssh_port: config.ssh_port.into(), diff --git a/src/main.rs b/src/main.rs index 783bccf..a1bf958 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use clap::Parser; +use clap::{CommandFactory, Parser}; use sandhole::{ApplicationConfig, LogFormat, entrypoint}; use tracing_subscriber::{Layer, layer::SubscriberExt, util::SubscriberInitExt}; @@ -8,6 +8,16 @@ async fn main() -> color_eyre::Result<()> { let config = ApplicationConfig::parse(); + if let Some(shell) = config.mode.completions { + clap_complete::generate( + shell, + &mut ApplicationConfig::command(), + env!("CARGO_BIN_NAME"), + &mut std::io::stdout(), + ); + return Ok(()); + } + let env_filter = tracing_subscriber::EnvFilter::builder() .with_default_directive(tracing::level_filters::LevelFilter::INFO.into()) .from_env_lossy();