diff --git a/Cargo.lock b/Cargo.lock index 307d878..d10c125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,6 +169,15 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap_complete" +version = "3.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4179da71abd56c26b54dd0c248cc081c1f43b0a1a7e8448e28e57a29baa993d" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "3.2.18" @@ -199,6 +208,7 @@ dependencies = [ "bitvec", "chacha20poly1305", "clap", + "clap_complete", "color-eyre", "crc-any", "either", diff --git a/Cargo.toml b/Cargo.toml index d3b76f7..996144b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ base64 = "0.13.0" bitvec = "1.0.1" chacha20poly1305 = "0.10.1" clap = { version = "3.2.20", features = ["clap_derive", "derive", "wrap_help"] } +clap_complete = "3.2.4" color-eyre = "0.6.2" crc-any = "2.4.3" either = { version = "1.8.0", features = ["serde"] } diff --git a/README.md b/README.md index 2287444..d39011c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Use a simple encryption program and put the config into a NixOS module. Just lik url = "github:GoldsteinE/classified"; # to avoid having one more copy of nixpkgs inputs.nixpkgs.follows = "nixpkgs"; - # you can also do this with rust-overlay and naersk + # you can also do this with naersk }; }; outputs = { nixpkgs, classified, ... }: { diff --git a/flake.lock b/flake.lock index 51cd7c3..d7b9f19 100644 --- a/flake.lock +++ b/flake.lock @@ -15,24 +15,11 @@ "type": "github" } }, - "flake-utils_2": { - "locked": { - "lastModified": 1656928814, - "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "naersk": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1659610603, @@ -49,18 +36,6 @@ } }, "nixpkgs": { - "locked": { - "lastModified": 0, - "narHash": "sha256-nkMQ1TKIIAYIVbbUzjxfjPn3H1zZFW20TrHUFAjwvNU=", - "path": "/nix/store/c3qqpbi359a0dvx80bkhzyqgd839y5if-source", - "type": "path" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_2": { "locked": { "lastModified": 1662019588, "narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=", @@ -76,47 +51,11 @@ "type": "github" } }, - "nixpkgs_3": { - "locked": { - "lastModified": 1659102345, - "narHash": "sha256-Vbzlz254EMZvn28BhpN8JOi5EuKqnHZ3ujFYgFcSGvk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "11b60e4f80d87794a2a4a8a256391b37c59a1ea7", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "root": { "inputs": { "flake-utils": "flake-utils", "naersk": "naersk", - "nixpkgs": "nixpkgs_2", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_3" - }, - "locked": { - "lastModified": 1662087605, - "narHash": "sha256-Gpf2gp2JenKGf+TylX/YJpttY2bzsnvAMLdLaxoZRyU=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "60c2cfaa8b90ed8cebd18b214fac8682dcf222dd", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" + "nixpkgs": "nixpkgs" } } }, diff --git a/flake.nix b/flake.nix index bf1d8a5..d38c130 100644 --- a/flake.nix +++ b/flake.nix @@ -1,36 +1,29 @@ { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - rust-overlay.url = "github:oxalica/rust-overlay"; flake-utils.url = "github:numtide/flake-utils"; naersk.url = "github:nix-community/naersk"; + naersk.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = { self, nixpkgs, rust-overlay, flake-utils, naersk }: + outputs = { self, nixpkgs, flake-utils, naersk }: flake-utils.lib.eachDefaultSystem (system: let packageName = "classified"; - - overlays = [ (import rust-overlay) ]; pkgs = import nixpkgs { - inherit system overlays; - }; - rust = (pkgs.rust-bin.stable.latest.default.override { - extensions = [ - "rust-src" - "cargo" - "rustc" - "rustfmt" - ]; - }); - naersk-lib = naersk.lib."${system}".override { - cargo = rust; - rustc = rust; + inherit system; }; + naersk-lib = naersk.lib."${system}"; in rec { packages.${packageName} = naersk-lib.buildPackage { pname = "${packageName}"; root = ./.; + postInstall = '' + mkdir -p $out/share/{bash-completion/completions,zsh/site-functions,fish/vendor_completions.d} + $out/bin/classified completions bash > $out/share/bash-completion/completions/classified.bash + $out/bin/classified completions zsh > $out/share/zsh/site-functions/_classified + $out/bin/classified completions fish > $out/share/fish/vendor_completions.d/classified.fish + ''; }; defaultPackage = packages.${packageName}; @@ -40,9 +33,11 @@ nixosModules.default = import ./module.nix defaultApp; devShell = pkgs.mkShell { - buildInputs = [ - rust - pkgs.rust-analyzer + buildInputs = with pkgs;[ + rustc + cargo + rustfmt + rust-analyzer ]; }; } diff --git a/src/main.rs b/src/main.rs index 936ce28..d64fe61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ use chacha20poly1305::{ aead::{Aead as _, Key, Nonce}, AeadCore, KeyInit as _, XChaCha20Poly1305 as Cipher, }; -use clap::Parser; +use clap::{CommandFactory as _, Parser, Subcommand}; use color_eyre::eyre::{self, eyre, WrapErr as _}; use indexmap::IndexMap; use itertools::Itertools as _; @@ -45,12 +45,33 @@ use crate::config::{Config, FileDesc}; mod config; mod keyarmor; +#[derive(Subcommand)] +enum Shell { + Bash, + Zsh, + Fish, +} + +impl From for clap_complete::Shell { + fn from(this: Shell) -> Self { + match this { + Shell::Bash => Self::Bash, + Shell::Zsh => Self::Zsh, + Shell::Fish => Self::Fish, + } + } +} + +#[allow(clippy::doc_markdown)] +/// Simple encryption tool intended for use with NixOS #[derive(Parser)] enum Command { /// Generate a new encryption key and print it to stdout + #[clap(display_order = 1)] GenKey, /// Encrypt file or stdin with given encryption key and print result to stdout (armored as /// base64) + #[clap(display_order = 2)] Encrypt { /// Path to the key file #[clap(short, long)] @@ -58,6 +79,7 @@ enum Command { /// File to encrypt, stdin if absent file: Option, }, + #[clap(display_order = 3)] /// Decrypt file that was previously encrypted with `encrypt` and print result to stdout Decrypt { /// Path to the key file @@ -66,11 +88,16 @@ enum Command { /// File to decrypt, stdin if absent file: Option, }, + #[clap(display_order = 4)] /// Decrypt multiple files to their target directories, according to JSON/TOML config Batch { /// Config file, stdin if absent config: Option, }, + #[clap(display_order = 5)] + /// Generate shell completions + #[clap(subcommand)] + Completions(Shell), } fn trim_newline(mut x: &[u8]) -> &[u8] { @@ -229,6 +256,14 @@ fn main() -> eyre::Result<()> { contents.zeroize(); } } + Command::Completions(shell) => { + clap_complete::generate( + clap_complete::Shell::from(shell), + &mut Command::command(), + "classified", + &mut io::stdout().lock(), + ); + } } Ok(())