Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem Definition: Reusable Partial CLI Parsing #37

Closed
yoshuawuyts opened this issue May 28, 2018 · 7 comments
Closed

Problem Definition: Reusable Partial CLI Parsing #37

yoshuawuyts opened this issue May 28, 2018 · 7 comments
Assignees
Milestone

Comments

@yoshuawuyts
Copy link
Collaborator

yoshuawuyts commented May 28, 2018

When thinking about networked services, one of the basic command line requirements is to accept a port to listen to.

This is usually expressed through the --port command. But that's not the only version; while talking in person, we've encountered the following variations:

  • --port to accept a port (number)
  • -p as a shorthand for --port
  • $PORT, environment variable to accept a port (number)
  • $LISTEN_FD to forward a socket, usually from Systemd
  • launchd (MacOS) also has a thing

For an average program, this is a lot to think about. If we were to write this for every application we build, it'd both end up being repetitive boilerplate, and easy to get wrong.

So the question we're asking here is: how can we turn this information into a reusable component?

There's a few more constraints we need to think about here:

  • This should be a component of an argument parsing solution, but stay flexible enough that other arguments can be specified.
  • Handling ports is an example. Other solutions that could be used in conjunction would be: handling log levels, handling database ports, tokens, and more.
  • It should be scoped to just handling arguments from the command line. Ideally there would be no friction between the parsing of arguments, and using the result in different frameworks / crates.

We're not sure what the solution to these problems are, but we do know that it would be beneficial to solve them. We'll continue from here by experimenting, and we encourage people interested in this to do the same.

Thanks!

@TeXitoi
Copy link

TeXitoi commented May 28, 2018

Proposition: Bind is provided by a dedicated crate:

#[macro_use]
extern crate structopt;

use structopt::StructOpt;
use structopt::clap::ArgGroup;
use std::net::TcpListener;
use std::os::raw::c_int;
use std::os::unix::io::FromRawFd;
use std::io;

#[derive(StructOpt, Debug)]
// this annotation should be moved to Bind, but that doesn't work
// actually. Maybe creating a structopt issue?
#[structopt(raw(group = r#"ArgGroup::with_name("bind").required(true)"#))]
struct Opt {
    #[structopt(long = "debug")]
    debug: bool,
    #[structopt(flatten)]
    bind: Bind,
}

#[derive(StructOpt, Debug)]
struct Bind {
    #[structopt(short = "p", long = "port", env = "PORT", group = "bind")]
    port: Option<u16>,
    #[structopt(long = "file-descriptor", env = "FD", group = "bind")]
    fd: Option<c_int>,
}
impl Bind {
    fn bind(&self) -> std::io::Result<TcpListener> {
        match self {
            Bind { fd: Some(fd), .. } => unsafe {
                Ok(TcpListener::from_raw_fd(*fd))
            },
            Bind { port: Some(port), .. } => TcpListener::bind(("*", *port)),
            _ => Err(io::Error::new(io::ErrorKind::Other, "Not port supplied")),
        }
    }
}

fn main() -> io::Result<()> {
    let opt = Opt::from_args();
    let _bind = opt.bind.bind()?;
    Ok(())
}

@yoshuawuyts
Copy link
Collaborator Author

Published the clap-port-flag crate 🎉 https://github.com/rust-clique/clap-port-flag

@killercup
Copy link
Collaborator

Ah, thanks for the reminder! I moved the verbosity-flag repo to https://github.com/rust-clique/clap-verbosity-flag!

@killercup killercup added this to the Preview 2 milestone Jul 18, 2018
@killercup
Copy link
Collaborator

I think we have a pretty good thing going here, but we still need to make this a bit more popular. Any ideas how to do that? Long-term we might use these crates in getting-started guide or things like quicli, but we should have a larger user base to validate that they are actually helpful before doing that.

@yoshuawuyts
Copy link
Collaborator Author

@killercup I think a good first step is to add more documentation. This should perhaps include a See Also section so we link to similar crates. Perhaps an "ecosystem" section of similar under clap might also help us with exposure. It worked well with tape, back in the day.

We already got one of the crates featured in "this week in rust". We're now on >=30 average downloads a day, and the number seems to be going up.

I think perhaps another avenue worth exploring is creating PRs to the Rust cookbook. It seems be having some traction, and might be a good place for exposure.

@killercup
Copy link
Collaborator

@yoshuawuyts I assigned this to you for now to settle the popularity thing but feel free to ping me :) maybe we can piggy-back on clap3 and its website? :)

@killercup
Copy link
Collaborator

Since "only" docs and publicity remain, I'm closing this as finished (🎉) and let's move the discussion to issues focusses specifically on docs (#45)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants