fix: update flake and refactor

This commit is contained in:
casuallyblue 2024-02-14 11:44:00 -06:00
parent 25eadea4b7
commit 88b6816133
5 changed files with 246 additions and 29 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

2
.gitignore vendored
View file

@ -1 +1,3 @@
target
.direnv
result

135
flake.lock Normal file
View file

@ -0,0 +1,135 @@
{
"nodes": {
"crane": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1707685877,
"narHash": "sha256-XoXRS+5whotelr1rHiZle5t5hDg9kpguS5yk8c8qzOc=",
"owner": "ipetkov",
"repo": "crane",
"rev": "2c653e4478476a52c6aa3ac0495e4dea7449ea0e",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": "nixpkgs",
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1707891749,
"narHash": "sha256-SeikNYElHgv8uVMbiA9/pU3Cce7ssIsiM8CnEiwd1Nc=",
"owner": "nix-community",
"repo": "fenix",
"rev": "3115aab064ef38cccd792c45429af8df43d6d277",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1707689078,
"narHash": "sha256-UUGmRa84ZJHpGZ1WZEBEUOzaPOWG8LZ0yPg1pdDF/yM=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "f9d39fb9aff0efee4a3d5f4a6d7c17701d38a1d8",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1707877513,
"narHash": "sha256-sp0w2apswd3wv0sAEF7StOGHkns3XUQaO5erhWFZWXk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "89653a03e0915e4a872788d10680e7eec92f8600",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"crane": "crane",
"fenix": "fenix",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs_2"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1707849817,
"narHash": "sha256-If6T0MDErp3/z7DBlpG4bV46IPP+7BWSlgTI88cmbw0=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "a02a219773629686bd8ff123ca1aa995fa50d976",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

76
flake.nix Normal file
View file

@ -0,0 +1,76 @@
{
description = "Build a cargo project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
crane = {
url = "github:ipetkov/crane";
inputs.nixpkgs.follows = "nixpkgs";
};
fenix = {
url = "github:nix-community/fenix";
};
flake-utils.url = "github:numtide/flake-utils";
};
outputs = inputs: with inputs;
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
inherit (pkgs) lib;
craneLib = crane.lib.${system}.overrideToolchain fenix.packages.${system}.complete.toolchain;
src = craneLib.path ./.;
# Common arguments can be set here to avoid repeating them later
commonArgs = {
inherit src;
buildInputs = [
# Add additional build inputs here
] ++ lib.optionals pkgs.stdenv.isDarwin [
# Additional darwin specific inputs can be set here
pkgs.libiconv
];
# Additional environment variables can be set directly
# MY_CUSTOM_VAR = "some value";
};
# Build *just* the cargo dependencies, so we can reuse
# all of that work (e.g. via cachix) when running in CI
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
# Build the actual crate itself, reusing the dependency
# artifacts from above.
my-crate = craneLib.buildPackage (commonArgs // {
inherit cargoArtifacts;
});
in
{
packages = {
default = my-crate;
};
apps.default = flake-utils.lib.mkApp {
drv = my-crate;
};
devShells.default = pkgs.mkShell {
# Extra inputs can be added here
nativeBuildInputs = with pkgs; [
cargo
fenix.packages.${system}.complete.toolchain
rustfmt
] ++ lib.optionals pkgs.stdenv.isDarwin [
libiconv
];
};
});
}

View file

@ -1,56 +1,59 @@
#![feature(box_patterns)]
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{parse_macro_input, ItemFn, PatType, Receiver};
#[proc_macro_attribute]
pub fn clap_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut f = parse_macro_input!(item as ItemFn);
// Make sure we actually have a function we can handle
let item_type = f
.sig
.inputs
.first()
.expect("Need exactly one argument to the function");
let renamed_main = Ident::new("clap_rewritten_main", Span::call_site());
// Rename the current main function so we can replace it
let renamed_main = Ident::new("clap_main_fn", Span::call_site());
f.sig.ident = renamed_main.clone();
let ty = match item_type {
syn::FnArg::Receiver(recv) => match *recv.ty.clone() {
syn::Type::Path(ty) => ty.path.clone(),
_ => panic!("unexpected type"),
},
syn::FnArg::Typed(typed) => match *typed.ty.clone() {
syn::Type::Path(ty) => ty.path.clone(),
_ => panic!("Unexpected type"),
},
let clap_options_type = match item_type {
// Match named types since those are the only ones that
// would have implemented Parser
syn::FnArg::Receiver(Receiver { ty, .. }) | syn::FnArg::Typed(PatType { ty, .. }) => {
match ty.as_ref() {
syn::Type::Path(ty) => ty.path.clone(),
_ => panic!("Expected a path type"),
}
}
};
let main_return_type = f.sig.output.clone();
quote! {
// Paste the renamed main function here
#f
pub fn main() {
// Set the type so the return value of main gets forwarded
pub fn main() -> #main_return_type {
use clap::Parser;
use std::io::Write;
let args = match #ty::try_parse() {
Ok(args) => args,
Err(e) => {
writeln!(&mut std::io::stderr(), "{e}").expect("Could not write to stderr!");
std::process::exit(-1);
},
// Handle the error on the type here and only continue
// if we actually parsed the options. If the user wanted
// to handle the errors manually they wouldn't be using this
let args = Ok(match #clap_options_type::try_parse()) else {
writeln!(&mut std::io::stderr(), "{e}").expect("Could not write to stderr!");
// directly exit (we don't care about what possible types main might return
// since we are erroring out before it even gets called
std::process::exit(-1);
};
match #renamed_main(args) {
Ok(()) => {},
Err(e) => {
writeln!(&mut std::io::stderr(), "{e}").expect("Could not write to stderr!");
std::process::exit(-1);
},
}
// Call the decorated main function
#renamed_main(args)
}
}
.into()