Create a command line application with Rust
Tags: rust, learning
Published: 2024-05-13 21:52:14

## Introduction

In this little post, we'll build together a very simple command line application using Rust. The goal of the program will be straightforward. We'll give it a directory name, and it will create a directory with that name. Easy enough right? Let's jump into it.

## Setup

If you haven't set up Rust yet, do not hesitate to check out the [official docs](https://www.rust-lang.org/fr/learn/get-started), there are a lot of great informations there.

Now, let's create our new Rust project. To do this, we can run the following command:

`cargo new new_dir_cmd`

This will create a new directory call *new_dir_cmd*. Of course, you can replace that name with whatever you want.

If you peek inside the newly created directory, you'll see the following:
![New rust directory and contents](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/va89i2c40tval2lys466.png)

Out of the box, if you run `cargo run` inside this directory. It will print out the good old "Hello World!"

![First cargo run](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vydpdsyea5bnp7iksq5t.png)

Awesome, we're ready to go!

## Creating a folder

First step, we're going to create a folder. We will improve our program step by step.

Let's put this inside our main.rs:

```rust
use std::fs;

fn main() -> std::io::Result<()> {
    fs::create_dir_all("/Users/damiencosset/Desktop/rust/new_dir_cmd/awesome_new_dir")?;
    Ok(())
}
```

We use the *fs* module from the *std* crate. Crates, in Rust, are similar to packages in other languages. If you want more informations about crates in Rust, you can check [the docs](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html).

We use the *create_dir_all* function from the module. It takes a path as an argument. For now, I'm giving it a hardcoded path. 

Finally, this function returns a *std::io::Result* type. So we make our main function return that by adding *-> std::io::Result<()>*. After creating our new directory, we simply use the *Ok* variant that indicates that everything is fine.

*Note*: The *?* character is used in Rust for error propagation. If we encounter a error during the directory creation it would return an *Err(error)*, *Err* being the second variant that Result can take after *Ok*.

Let's run this code and check what we have:


![Creating our new directory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/todd821csd94tadrx8ur.png)

It works! We have created our first new directory with Rust!

## Adding the command line arguments

Obviously, this program isn't very useful. The goal is to give the directory name we want to create via a command line. Let's set this up.

### Adding the clap crate

To parse command line arguments, we will use the *clap* crate. To add a crate, we go into our *Cargo.toml* file. You have a line that says:
```
[dependencies]
```
This is where we add the crates we want to use in our program. 

Let's add *clap* by running the following command:

`cargo add clap --features derive`

The features flag allows us to use optional features in the crate. Here, we want to use the derive feature. To get more information about this crate, you can check [the docs](https://docs.rs/clap/latest/clap/). And if you check our *Cargo.toml*, we now have a new line:

```
[dependencies]
clap = { version = "4.5.4", features = ["derive"] }
```

### Defining our command line arguments

Let's replace our existing code with this:

```rust
use clap::Parser;
//use std::fs;

#[derive(Parser)]
struct Cli {
    directory_name: String,
}

fn main() -> std::io::Result<()> {
    let args = Cli::parse();
    println!("{}", args.directory_name);
    // fs::create_dir_all("/Users/damiencosset/Desktop/rust/new_dir_cmd/awesome_new_dir")?;
    Ok(())
}
```

We commented out the directory creation for now. 
`#[derive(Parser)]` means that we are using a custom macro that implements the *Parser* trait. Simply put, a trait defines a set of methods. Here, we implement the set of of methods defined in *Parser* to our *Cli* structure. So our structure is able to call said methods, like *parse()*.

With this code right there and the power of *clap*, we can parse command line applications. Let's run our code and give it an argument:


![Running with a command line argument](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5cce3arpy814egjhpd1h.png)

Nice! We successfully printed our argument. We can now parse the directory name from the command line.

### Getting the current directory

Now, we have a little issue. We are not going to give the full path in our argument. We only give the directory name we wish to create. Therefore, our program needs to know where to create this directory. We'll do something simple, we'll take the current directory we are in, and append the directory name we put as an argument.

So we need to:

* get the current directory's path
* append the directory name to that path

To get the current directory's path, we can add these two lines of code:

```rust
// Import 
use std::env;

// Inside the main function
let mut path = env::current_dir()?;
```

Notice that we use the keyword *mut*. This means that the variable we just defined is mutable. Variables in Rust are by default immutable. By adding the keyword *mut*, we can modify it to append the directory name we wish to create.

By combining all of this, our completed program looks like this:

```rust
use clap::Parser;
use std::env;
use std::fs;

#[derive(Parser)]
struct Cli {
    directory_name: String,
}

fn main() -> std::io::Result<()> {
    let args = Cli::parse();
    let mut path = env::current_dir()?;
    path.push(args.directory_name);
    fs::create_dir_all(path)?;
    Ok(())
}
```

By using *push()*, we can append our directory name to the current directory's path. Let's see if it works!


![Creating two folders with our new command line application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bri6eda3pfy07b2bgtai.png)

Yay! It works!

And just like that, we build a very simple program in Rust that allows us to create new directories!

Hope you found it interesting!
Have fun ❤