Skip to content

A template repository for Rust-based command-line interface applications.

License

Notifications You must be signed in to change notification settings

christopherkeim/rust-cli-template

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CI Cargo Version Clap

rust-cli-template

This repository implements a simple Rust command-line interface application that converts webpages to markdown files.

Quickstart 🦀 🚀 ✨

This repository is a GitHub Template that you can use to create a new repository for Rust-based command-line applications. It comes pre-configured to use cargo 1.76.0 with automated setup for Ubuntu 20.04/22.04.

To get started, you can:

  1. Simply click Use this template in the top right corner of this repository, or

  2. Clone this repository onto your machine with:

git clone https://github.com/christopherkeim/rust-cli-template.git

Setup

Note: this template targets Ubuntu 20.04/22.04 development environments for automated setup.

  1. Once you have local copy of this repository in your development environment, navigate into this directory and run the setup.sh script:
cd rust-cli-template/
bash setup.sh

If you would like to include Docker 24.0.6 in your development environment, you can run:

bash setup.sh --docker
  1. You can ensure that the code currently passes the provided tests with:
make test
  1. You can directly try the CLI application with:
cargo run -- \
  --url https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/error-handling.html \
  --file rust_error_handling.md

This webpage is an excellent resource on error handling rust 😊.

Development Workflow Automation (Makefile)

I like to use a Makefile to automate parts of my development workflow - this allows you to alias parts of your development process like linting, formatting, testing, and building binaries.

The Makefile in this repository comes with the following commands:

  1. make build
cargo build --release
  1. make clean
cargo clean
  1. make doc
cargo doc --no-deps --open
  1. make lint
cargo clippy
  1. make format
cargo fmt
  1. make test
cargo test

Continuous Integration (ci.yaml)

This repository has continuous integration that runs when Pull Requests are opened to the main branch.

Note that GitHub Action runners come pre-installed with cargo 1.76.0 (latest)

The continuous integration pipeline implemented in ci.yaml runs the following steps:

  1. Checkout: Checks out the source code into the runner VM

  2. Format: Formats the source code files

  3. Test: Runs the unit tests defined in each module

  4. Build: Builds a release binary for deployment (commented out - replace with your deployment strategy)

Containerization (Dockerfile)

This template includes a Dockerfile that implements a multistage build with the final image using scratch and the rust_cli_template release binary as its entrypoint.

The setup.sh script is idempotent, and it will only make changes that bring your development environment closer to the desired state described in the script. If you'd like to include docker in your development environment, you can run it again with --docker.

If you'd like to containerize the application:

  1. Create the image:
docker build -t rust-cli-template:v0 .
  1. Run the container with:
docker run -it rust-cli-template:v0 \
  --url https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/error-handling.html \
  --file rust_error_handling.md

For this example application, it's a bit silly. But I've included it as a convenient starting point for building cloud native workloads.

rust:1.76-alpine (Builder)

The rust:1.76-alpine official Rust image uses musl libc to a build statically-linked Rust release binary. This is crucial for allowing the binary to run in our scratch image.

scratch (Final)

FROM scratch essentially is an empty container - it is a no-op in the docker build process and it is used as a starting point for building minimal Docker Images ground up.

https://hub.docker.com/_/scratch:

You can use Docker’s reserved, minimal image, scratch, as a starting point for building containers. Using the scratch “image” signals to the build process that you want the next command in the Dockerfile to be the first filesystem layer in your image.

While scratch appears in Docker’s repository on the hub, you can’t pull it, run it, or tag any image with the name scratch. Instead, you can refer to it in your Dockerfile.

In addition to making making your final image's size extremely small, it also hardens the security posture of our software by isolating the execution environment of the program - if an attacker penetrates into your runtime environment, it's an empty container with no further exploitable software.

Notes

Dev and Release Profiles

Cargo has two main profiles: the dev profile Cargo uses when you run cargo build and the release profile Cargo uses when you run cargo build --release. The dev profile is defined with good defaults for development, and the release profile has good defaults for release builds.

These profile names might be familiar from the output of your builds:

$ cargo build
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
$ cargo build --release
    Finished release [optimized] target(s) in 0.0s
The dev and release are these different profiles used by the compiler.

opt-level (Cargo.toml)

By adding [profile.*] sections for any profile you want to customize, you override any subset of the default settings. For example, here are the default values for the opt-level setting for the dev and release profiles:

Filename: Cargo.toml

[profile.dev]
opt-level = 0

[profile.release]
opt-level = 3

The opt-level setting controls the number of optimizations Rust will apply to your code, with a range of 0 to 3. Applying more optimizations extends compiling time, so if you’re in development and compiling your code often, you’ll want fewer optimizations to compile faster even if the resulting code runs slower.

Documentation (Overall Rust)

The best documentation with very clear examples is Rust By Example: https://doc.rust-lang.org/rust-by-example/index.html

rustc Targets

rustc is a cross-compiler by default. This means that you can use any compiler to build for any architecture. The list of targets are the possible architectures that you can build for can be seen with:

rustc --print target-list

The rustc Book: https://doc.rust-lang.org/rustc/targets/index.html

Cross-compiling for Raspberry Pi Targets

https://jakewharton.com/cross-compiling-static-rust-binaries-in-docker-for-raspberry-pi/

The Cargo Book

Documentation on Rust's package manager cargo.

https://doc.rust-lang.org/cargo/index.html

About

A template repository for Rust-based command-line interface applications.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published