Skip to content

Commit

Permalink
Global flags for subcommands in structopt
Browse files Browse the repository at this point in the history
We want to build out functionality to let the user
write into a file in their garden. To do that, we
have to know the location of their garden.

We'll start by implementing a function to get the
default garden path.

```rust
fn get_default_garden_dir() -> Result<PathBuf> {
    let user_dirs = UserDirs::new().ok_or_else(|| eyre!("Could not find home directory"))?;
    Ok(user_dirs.home_dir().join(".garden"))
}
```

This uses the user's system directories via the
`directories` crate to find their home dir. We
then add `.garden` to the home dir for the default
garden.

Ideally, we would want the user to be able to
specify their garden path. Using structopt, we
can let them specify it as a short, long, or
env var.

In our README, we'll specify how this should work.

````

```shell
GARDEN_PATH=~/github/my-digital-garden garden write
garden -p ~/github/my-digital-garden write
garden --garden_path ~/github/my-digital-garden write
```
````

And in our `Opt` struct, we can tell structopt how to
handle it. Putting this in our `Opt` struct instead of
our `Command` enum make it a global flag that can be
specified for all subcommands.

```rust
struct Opt {
    #[structopt(parse(from_os_str), short = "p", long, env)]
    garden_path: Option<PathBuf>,

    #[structopt(subcommand)]
    cmd: Command,
}
```

structopt is only handling the user input, so in
`main()` we still need to fall back to the
default if the `garden_path` is not specified.

```rust
let garden_path = match opt.garden_path {
    Some(pathbuf) => Ok(pathbuf),
    None => get_default_garden_dir().wrap_err("`garden_path` was not supplied"),
}?;
```

if we force an `Err` in `get_default_garden_dir`
We can see how the wrapped errors end up stacking.

```
Error:
   0: `garden_path` was not supplied
   1: Could not find home directory
```

We'll also change the signature of `write` to
accept the pathbuf.

```
Command::Write { title } => write(garden_path, title),
```

Note that we need to import `PathBuf`. We can also
`dbg!` the garden path and title to see their
values.

```rust
use std::path::PathBuf;

pub fn write(garden_path: PathBuf, title: Option<String>) -> Result<()> {
    dbg!(garden_path, title);
    todo!()
}
```
  • Loading branch information
ChristopherBiscardi committed Jan 16, 2021
1 parent 695f144 commit 75020e4
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 3 deletions.
113 changes: 113 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -15,6 +15,7 @@ path = "src/main.rs"

[dependencies]
color-eyre = "0.5.10"
directories = "3.0.1"
structopt = "0.3.21"

[dev-dependencies]
Expand Down
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -4,6 +4,14 @@ A CLI tool for the creation and maintenance of Digital Gardens.

## Commands

## Setting the garden path

```shell
GARDEN_PATH=~/github/my-digital-garden garden write
garden -p ~/github/my-digital-garden write
garden --garden_path ~/github/my-digital-garden write
```

### write

Open a new file to write in our digital garden. Since we don't necessarily know what we want to title what we're writing, we'll leave the title as optional and ask the user for it later if they don't provide it up-front.
Expand Down
18 changes: 16 additions & 2 deletions src/main.rs
@@ -1,5 +1,7 @@
use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, Result, WrapErr};
use digital_garden::write;
use directories::UserDirs;
use std::path::PathBuf;
use structopt::StructOpt;

/// A CLI for the growing and curation of a digital garden
Expand All @@ -8,6 +10,9 @@ use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "garden")]
struct Opt {
#[structopt(parse(from_os_str), short = "p", long, env)]
garden_path: Option<PathBuf>,

#[structopt(subcommand)]
cmd: Command,
}
Expand All @@ -24,12 +29,21 @@ enum Command {
title: Option<String>,
},
}

fn get_default_garden_dir() -> Result<PathBuf> {
let user_dirs = UserDirs::new().ok_or_else(|| eyre!("Could not find home directory"))?;
Ok(user_dirs.home_dir().join(".garden"))
}
fn main() -> Result<()> {
color_eyre::install()?;

let opt = Opt::from_args();
dbg!(&opt);
let garden_path = match opt.garden_path {
Some(pathbuf) => Ok(pathbuf),
None => get_default_garden_dir().wrap_err("`garden_path` was not supplied"),
}?;
match opt.cmd {
Command::Write { title } => write(title),
Command::Write { title } => write(garden_path, title),
}
}
4 changes: 3 additions & 1 deletion src/write.rs
@@ -1,5 +1,7 @@
use color_eyre::Result;
use std::path::PathBuf;

pub fn write(_title: Option<String>) -> Result<()> {
pub fn write(garden_path: PathBuf, title: Option<String>) -> Result<()> {
dbg!(garden_path, title);
todo!()
}

0 comments on commit 75020e4

Please sign in to comment.