1use anyhow::anyhow;
2use clap::Parser;
3use reqwest::Url;
4use std::{error::Error, path::PathBuf, str::FromStr};
5
6#[derive(Debug, Parser)]
8pub enum Command {
9 Post {
11 #[command(flatten)]
12 id_options: IdOptions,
13 #[command(flatten)]
14 options: CliOptions,
15 },
16 Sequence {
18 #[command(flatten)]
19 id_options: IdOptions,
20 #[command(flatten)]
21 options: CliOptions,
22 },
23 All {
25 #[command(flatten)]
26 options: CliOptions,
27 },
28}
29impl Command {
30 pub fn options(&self) -> CliOptions {
31 match self {
32 Command::Post { options, .. }
33 | Command::Sequence { options, .. }
34 | Command::All { options } => options.clone(),
35 }
36 }
37}
38
39#[derive(Debug, Clone, Parser)]
40pub struct IdOptions {
41 #[clap(long, short = 'u')]
43 url: Option<String>,
44 #[clap(long)]
46 id: Option<String>,
47}
48#[derive(Debug, Clone)]
49pub enum IdOrUrl {
50 Url { url: String },
51 Id { id: String },
52}
53impl From<IdOptions> for IdOrUrl {
54 fn from(value: IdOptions) -> IdOrUrl {
55 if let Some(id) = value.id {
56 IdOrUrl::Id { id }
57 } else {
58 IdOrUrl::Url {
59 url: value
60 .url
61 .ok_or(anyhow!("No ID or URL was specified"))
62 .unwrap(),
63 }
64 }
65 }
66}
67impl IdOrUrl {
68 pub fn get_id(self) -> Result<String, Box<dyn Error>> {
69 Ok(match self {
70 IdOrUrl::Id { id } => id,
71 IdOrUrl::Url { url } => {
72 let url = Url::from_str(&url)?;
73 url.path_segments()
74 .ok_or(anyhow!("Failed to parse URL segments"))?
75 .nth(1)
76 .ok_or(anyhow!("Failed to find ID in URL"))?
77 .to_string()
78 }
79 })
80 }
81}
82
83#[derive(Debug, Clone, Parser)]
84pub struct CliOptions {
85 #[clap(long, short = 'i')]
87 pub ignore_cache: bool,
88
89 #[clap(long, short = 'd')]
91 pub delete_cache: bool,
92
93 #[clap(long, default_value = "./", short = 'o')]
95 pub output_dir: PathBuf,
96
97 #[clap(long, short = 'c')]
99 pub cache_dir: Option<PathBuf>,
100}
101#[derive(Debug, Clone)]
102pub struct ParsedCliOptions {
103 pub ignore_cache: bool,
104 pub delete_cache: bool,
105 pub output_dir: PathBuf,
106 pub cache_dir: PathBuf,
107}
108impl From<CliOptions> for ParsedCliOptions {
109 fn from(value: CliOptions) -> Self {
110 Self {
111 ignore_cache: value.ignore_cache,
112 delete_cache: value.delete_cache,
113 output_dir: value.output_dir,
114 cache_dir: value.cache_dir.unwrap_or(
115 dirs::cache_dir()
116 .unwrap_or(PathBuf::from_str("./cache").unwrap())
117 .join("lesspub"),
118 ),
119 }
120 }
121}
122
123pub struct CacheOptions {
124 pub ignore_cache: bool,
125 pub cache_dir: PathBuf,
126}