Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Rust-starter, a boilerplate to build Rust CLI applications (github.com/rust-starter)
97 points by csomar on Jan 25, 2021 | hide | past | favorite | 48 comments



While useful as a list of handy libraries, I don't think you need to concern yourself with using such a framework if you want to build a CLI app in Rust. If your intended CLI interface isn't extremely simple, then pick a handy argument parser like clap or structopt (which is built on top of clap). From there add these other libraries only if you feel the need.


A project like this can still be very useful if only to show newbies which libraries are the canonical ones. I've noticed with Rust their are many libraries which any experience Rust user would know about but which are not obvious to a newbie.


But it doesn't do that either. For example, it uses failure for error handling, which has been deprecated for quite some time.

It would be better to just go look at real CLI utilities and see what they do instead of trying to use something like this IMO. This project seems to just be throwing everything against the wall. It's likely you won't need most of it. For example, this template uses twice as many dependencies as ripgrep.


I disagree that there are "canonical" libraries outside of std.

Rust is quite feature rich and perfectly usable without any of these.

Some people are a bit trigger happy when adding dependencies, without considering the extra cost in maintenance and security.


I consider rand, clap, tokio, serde, and hyper, among others, to be canonical Rust libraries.

There may be alternatives, but a new person might be wondering "how do I generate a random number in Rust" and not want to roll their own RNG or find another library.

And that's not to say you have to use any of those in any particular project, just that they are the main options for achieving their particular functionality.


Cargo's website is quite good. It is easy to punch in a keyword and compare results to figure out which lib fits my use case best.

I don't think it gets enough credit for being so pleasant to use.


Yep.

The fact that there isn't a framework doesn't mean there's a problem. It could just be you have an unnatural need for structure where none is needed.


I would like to see a rust starter template for fully async (http, db, logging, files) web services with pg as the db


Here is one built with actix-web that I have looked at

https://github.com/nemesiscodex/actix-todo

My advice is pick a http server that you want to use and search github for Cargo.lock


Might be better to turn this into a cookiecutter template:

https://github.com/cookiecutter/cookiecutter


I've made https://github.com/Keats/kickstart which is roughly the same thing (and improved some bits) without the need to install a python package.


This looks nice. We switched from cookiecutter to yeoman and it’s been nice, but a bit annoying to need node, a custom node package, and a pile of node modules to get the same effect. I’ll give this a try today. I think my team would love having a single binary to generate our boilerplate.


What is the target audience for things like this? Are there people who start projects constantly? Or is this more just a catalog?


Pretty edge case use case over here, but we used cookiecutter (and now yeoman) internally for developing user-configured extensions to our app.

The extensions all have a lot of boilerplate so we use it as a replacement for a PHONY make target for niceties for the extension author like question prompts, enumerated lists for selecting, etc.


Let's not mix these two ecosystems.


Notice: Failure lib is deprecated now


Indeed, much of what Failure did well has since been upstreamed into Rust's own std::error::Error type. The modern recommendations for error handling convenience libs are thiserror (for library crates, where you want to define errors) and anyhow (for binary crates, where you just want to consume errors), both of which are from the author of Serde.

[EDIT: Also snafu, hello there Shepmaster :P ]


Unfortunately, backtracing is only available in nightly for thiserror and anyhow.


Nonetheless starting people off with something deprecated is not a good idea imo, and will only serve to making migration harder in the future because more and more people keep using said deprecated thing.


You can switch to the newError branch. One of the things that I like when building stuff for production is that my code compiles on Stable.


Do people still recommend snafu?


I (the author of SNAFU) absolutely recommend it!

It works well for libraries and applications and has bells and whistles you might want, such as backtrace captures on stable Rust.


Yes, why wouldn't they?


I was just wondering. I'm new to rust and still getting my bearings. Seems like there's a lot of options for error handling, from doing it yourself with an enum to snafu to thiserror and anyhow or (apparently deprecated) failure


Yep! Really, most of the error handling libraries just reduce the boilerplate associated with creating your own error types. SNAFU also adds some opinions to the mix.

You can see what the libraries do by expanding the procedural macros they use. When you look at the output, it's nothing special that you couldn't have done yourself!


You can use the newError branch: https://github.com/rust-starter/rust-starter/tree/newError

See https://rust-starter.github.io/#feature-errors for why Failure is still used.


Looks great! I’ve missed something like this. A couple of questions:

1. Is there an example application that uses the starter?

2. Does it follow the command line interface guidelines at https://clig.dev?


1. This was just released :) beyond internal apps I'm building, I guess no. But the project itself is already an example application.

2. First time I this. There are things that relate to Clap and things (like configuration) that could be implemented in rust-starter.


If you haven't seen it, I'll give a shoutout to abscissa[0]. It's used in production by quite a few apps, basically had everything I was looking for, and demonstrated thought towards why dependencies they have chosen and what those dependencies transitively include.

[0]: https://github.com/iqlusioninc/abscissa


What is the logo?


Looks like a tank of nitrogen.


That you need a "framework" to build simple CLI tools does not seem to speak too well of the language. I know nothing about rust, but isn't there a simple facility for using argc, argv, and the like?


Yes, that's std::env::args[0], however a higher level wrapper (I prefer structopt[1]) makes it trivial to produce nice usage output etc.

[0] https://doc.rust-lang.org/std/env/fn.args.html

[1] https://github.com/TeXitoi/structopt


You do not "need a framework" to build simple CLI tools in Rust. Most people use a command line argument parser, the most popular being clap [0]. Or you can just use std::env directly.

0: https://github.com/clap-rs/clap


Or you can use getopts if that's your thing (it's also a library so limited gain over clap/structop, probably smaller & faster to compile though) e.g. that's what Brian Cantrill does[0] because they're an old fogey[1] :D

[0] https://github.com/joyent/statemap/blob/rust/src/main.rs#L95

[1] https://github.com/joyent/statemap/pull/41


Not only had I entirely forgotten about that, I now use structopt for everything -- so at least this old dog can still learn new tricks? ;)


Of course, std::env::args: https://doc.rust-lang.org/std/env/fn.args.html

What clap gives you is something more like Python's argparse, which offers things like convenient parsing, automatically generated manpages and error/usage messages, etc.


As long as you're not doing any complex argument handling, it's dead simple:

https://github.com/ablakey/gameboy/blob/master/src/main.rs#L...

(I'm sure people will shout that this isn't the right way to parse optional flags)


> (I'm sure people will shout that this isn't the right way to parse optional flags)

Since that sounds like a challenge, just wanted to make sure that people are aware of Iterator::nth (https://doc.rust-lang.org/std/iter/trait.Iterator.html#metho...), which means you can entirely replace lines 8 and 9 with `let cartridge_path = env::args().nth(1);` :) In combination with Iterator::any to replace line 10, you can avoid a whopping five whole heap allocations this way!! :P


Ooooh thanks for sharing! I am a beginner to Rust (this emulator being my second project). I was not aware of that.

I feel like when I'm done I need to find a bit of cash and get a veteran to code review the whole thing. I'm learning a ton by suffering through it myself. But also probably missing a lot of great shortcuts and tips.

I assume the "five heap allocations" is kinda tongue in cheek? My understanding is that while it is good to avoid heap allocations, given this is a called-once piece of code, it's not really a big deal?


> I assume the "five heap allocations" is kinda tongue in cheek? My understanding is that while it is good to avoid heap allocations, given this is a called-once piece of code, it's not really a big deal?

Indeed. :) I can't envision a circumstance where avoiding exactly five small allocations outside of any loop would be observable in either time or memory usage. As a Rust programmer it simply provides a warm and fuzzy feeling to avoid allocations in places where it not only doesn't obscure the code, but actually makes it shorter. At best, this could be a small step towards running your code on embedded hardware (which isn't unreasonable for an emulator like this), but only if you were to also eliminate all other allocations within your program.


Given some ROMs are multiple megabytes I'm not sure how this would work.

Maybe I'm wrong but isn't the stack only a few MB in max size?

Appreciate your earlier comments. Thanks.


You definitely don't need a framework. This seems to be aimed at extras like fancy logging, config file management, and CI setup.


In this case the framework means set of dependencies. If you want to parse short-opts, long-opts etc. you need dependencies in most languages. Python is an exception, because of batteries included approach.

With Rust you will soon see that most applications require some sort of dependency like serde for serialization, etc.


Most languages have terrible CLI parsing support, I have yet to find something built in that matches Python’s argparse module. Hell, even “modern” languages like go suffer from this.


Python’s success is at least partially due to its “batteries included” methodology, but many of its standard modules didn’t get any support because external solutions just turned out to be better. Rust maintains a small but high quality standard library in part to avoid the problems that Python's standard library fell into. Things like cli parsers can be downloaded easily using cargo's amazing tooling. We get packages like structopt for example, which provides a custom derive parsing command line arguments:

   #[derive(StructOpt)]
   struct Opt {
       #[structopt(short, long)]
       debug: bool,
    
       #[structopt(short = "c", long)]
       nb_cars: Option<i32>,
    
       #[structopt(short, long)]
       level: Vec<String>,
   }


IMO structopt is way superior to argparse (which is itself not very good, it works to avoid a dependency but if I already have dependencies I'd rather use click).


As soon as https://news.ycombinator.com/item?id=25903259 was posted, two posts in /new, it helped bring this one, got to the front page:

26. Show HN: Rust-starter, a boilerplate to build Rust CLI applications (github.com/rust-starter) 18 points by csomar 19 minutes ago | flag | hide | past | 6 comments

27. Finland has slashed homelessness; the rest of Europe is failing (economist.com) 30 points by ashergill 19 minutes ago | flag | hide | past | 11 comments

28. The Reasons I’m Joining BIGtoken as CEO (medium.com/crypto-oracle) 3 points by simonebrunozzi 19 minutes ago | flag | hide | past | 1 comment

29. Upvote to encourage more people to visit New Links on Hacker News (ycombinator.com) 164 points by crazypython 21 minutes ago | hide | past | 19 comments




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: