#applications #boilerplate

entrypoint

opinionated application framework/wrapper that eliminates main function boilerplate

5 unstable releases

0.2.0 Feb 22, 2024
0.1.2 Dec 19, 2023
0.1.1 Dec 15, 2023
0.1.0 Sep 25, 2023
0.0.0 Sep 20, 2023

#452 in Configuration

Download history 25/week @ 2024-09-23

66 downloads per month
Used in tera-former

MIT license

27KB
165 lines

entrypoint

Crates.io Crates.io Documentation License

eliminate main function boilerplate with this opinionated application framework/wrapper

About

entrypoint has the following design goals:

  • eliminate application startup/configuration boilerplate
  • help enforce application best practices

What does this crate actually do?

entrypoint wraps a user defined function with automatic configuration/setup/processing of:

  • easy application error handling (via anyhow)
  • command-line argument parsing (via clap)
  • .dotenv file processing and environment variable population/overrides (via dotenvy)
  • logging (via tracing)

The user defined function is intended to be/replace main().

Meaning, this main/entrypoint function can be written as if all the configuration/processing/boilerplate is ready-to-use. More explicitly:

  • anyhow is available and ready to use
  • clap::Parser struct has been parsed and populated
  • .dotenv files have been parsed; environment variables are ready to go
  • tracing has been configured and the global subscriber has been registered

A note from the developer

entrypoint was as much about deploying my first crate as anything else.

Turns out, it's really not that useful. I kind of think it's better just to explicitly set this stuff up in your application. The juice isn't work the squeeze.

It's unlikely further development will occur.

Usage

Default Config

  1. Include the entrypoint prelude:

    use entrypoint::prelude::*;
    
  2. Define a clap struct and derive default entrypoint trait impls:

    #[derive(clap::Parser, DotEnvDefault, LoggerDefault, Debug)]
    #[log_format(full)]
    #[log_level(entrypoint::tracing::Level::INFO)]
    #[command(version, about, long_about = None)]
    struct CLIArgs {
        #[arg(short, long, env)]
        cli_arg: bool,
    }
    
  3. Define an entrypoint/main function:

    #[entrypoint::entrypoint]
    fn entrypoint(args: CLIArgs) -> entrypoint::anyhow::Result<()> {
        // args are parsed and ready to use
        info!("cli_arg set to: {:?}", args.cli_arg);
    
        // env::vars() already loaded-from/merged-with .dotenv file(s)
        let _my_var = env::vars("SOMETHING_FROM_DOTENV_FILE");
    
        // logging is ready to use
        info!("entrypoint::entrypoint");
    
        Ok(())
    }
    

Custom Config

Using the default behavior is totally reasonable, but overwriting some default impl(s) can provide customization.

Usage Notes

  1. The entrypoint function must:
    1. Have a clap::Parser input parameter
    2. return entrypoint::anyhow::Result<()>
  2. #[entrypoint::entrypoint] ordering may matter when used with other attribute macros (e.g. [tokio::main]).

Documentation

For more information, refer to:

Crates

entrypoint is divided into the following crates:

Contributing

Before doing anything else: open an issue.

Dependencies

~3–4MB
~76K SLoC