summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: cb244740ff2c71551562b6a5a18511e50fb766da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use anyhow::Result;
use std::fs;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
use thiserror::Error;

#[derive(Debug, StructOpt)]
#[structopt(about = "maintain a journal")]
enum JT {
    Init {
        #[structopt(help = "Directory where journal should be stored")]
        dirname: PathBuf,
        #[structopt(help = "Short name for journal")]
        journalname: String,
        #[structopt(help = "Short description of journal, its title")]
        description: String,
    },
    IsJournal {
        #[structopt(help = "Directory that may or may not be a journal")]
        dirname: PathBuf,
    },
    New {
        #[structopt(long, short, help = "Use DIRNAME as the location of the journal")]
        dirname: PathBuf,
        #[structopt(
            long,
            short,
            help = "Invoke EDITOR for user to edit draft",
            default_value = "/usr/bin/editor"
        )]
        editor: String,
        #[structopt(help = "Title of new draft")]
        title: String,
    },
    Finish {
        #[structopt(long, short, help = "Use DIRNAME as the location of the journal")]
        dirname: PathBuf,
    },
}

#[derive(Debug, Error)]
enum JournalError {
    #[error("directory {0} is not a journal")]
    NotAJournal(String),
}

fn main() -> Result<()> {
    let opt = JT::from_args();
    match opt {
        JT::Init {
            dirname,
            journalname,
            description,
        } => init(&dirname, &journalname, &description)?,
        JT::IsJournal { dirname } => is_journal(&dirname)?,
        JT::New {
            title,
            dirname,
            editor,
        } => new_draft(&title, &dirname, &editor)?,
        JT::Finish { dirname } => finish_draft(&dirname)?,
    }
    Ok(())
}

fn init(dirname: &Path, _journalname: &str, _description: &str) -> anyhow::Result<()> {
    std::fs::create_dir(dirname)?;
    Ok(())
}

fn is_journal(dirname: &Path) -> anyhow::Result<()> {
    let meta = fs::symlink_metadata(dirname)?;
    if !meta.is_dir() {
        return Err(JournalError::NotAJournal(dirname.display().to_string()).into());
    }
    Ok(())
}

fn new_draft(title: &str, dirname: &Path, editor: &str) -> anyhow::Result<()> {
    let drafts = dirname.join("drafts");
    if !drafts.exists() {
        std::fs::create_dir(&drafts)?;
    }
    let draft_filename = drafts.join("0.md");
    std::fs::write(draft_filename, title)?;
    Ok(())
}

fn finish_draft(dirname: &Path) -> anyhow::Result<()> {
    let drafts = dirname.join("drafts");
    let draft = drafts.join("0.md");

    let entries = dirname.join("entries");
    if !entries.exists() {
        std::fs::create_dir(&entries)?;
    }
    let entry = entries.join("0.md");

    std::fs::rename(draft, entry)?;
    Ok(())
}