Skip to content

Commit 9b53a74

Browse files
authored
feat: cache flag (#113)
* feat: cache flag * chore: get or create data dir * chore: use cache directory to ensure presence of templates
1 parent 2a6769d commit 9b53a74

6 files changed

Lines changed: 114 additions & 14 deletions

File tree

src/app_config/app_cache.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! src/app_config/app_cache.rs
2+
3+
use serde::Deserialize;
4+
use std::{fmt, fs, io, path::PathBuf};
5+
6+
#[derive(Debug)]
7+
pub enum CacheError {
8+
Io(io::Error),
9+
Invalid(String),
10+
}
11+
12+
impl From<io::Error> for CacheError {
13+
fn from(e: io::Error) -> Self {
14+
CacheError::Io(e)
15+
}
16+
}
17+
18+
impl From<String> for CacheError {
19+
fn from(e: String) -> Self {
20+
CacheError::Invalid(e)
21+
}
22+
}
23+
24+
impl fmt::Display for CacheError {
25+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
match self {
27+
CacheError::Io(e) => {
28+
write!(f, "{}", e)
29+
}
30+
CacheError::Invalid(e) => {
31+
write!(f, "{}", e)
32+
}
33+
}
34+
}
35+
}
36+
37+
#[derive(Deserialize, Debug)]
38+
pub struct AppCache {
39+
pub cache_dir: PathBuf,
40+
}
41+
42+
pub fn get_cache(file_path: Option<String>) -> Result<AppCache, CacheError> {
43+
let cache_path = match file_path {
44+
Some(path) => PathBuf::from(path),
45+
None => {
46+
let xdg = xdg::BaseDirectories::with_prefix("repotools");
47+
48+
let p = xdg
49+
.get_data_home()
50+
.ok_or(CacheError::Invalid(String::from("")))?;
51+
52+
fs::create_dir_all(&p).map_err(CacheError::Io)?;
53+
54+
p
55+
}
56+
};
57+
58+
Ok(AppCache {
59+
cache_dir: cache_path,
60+
})
61+
}

src/app_config/app_config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn get_config(file_path: Option<String>) -> Result<AppConfig, ConfigError> {
108108
let default_config = include_str!("../../assets/config.toml.j2");
109109

110110
let mut context = tera::Context::new();
111-
context.insert("data_dir", &xdg.get_cache_home());
111+
context.insert("data_dir", &xdg.get_data_home());
112112

113113
let rendered = match Tera::one_off(default_config, &context, false) {
114114
Ok(r) => {

src/app_config/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! src/app_config/mod.rs
22
3+
pub mod app_cache;
34
pub mod app_config;
45

6+
pub use app_cache::{AppCache, CacheError, get_cache};
57
pub use app_config::{AppConfig, ConfigError, get_config};

src/cli/cli.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ pub struct Cli {
1818
pub struct GlobalOpts {
1919
#[arg(long, name = "config")]
2020
pub config_path: Option<String>,
21-
// TODO: add data/cache path
21+
22+
#[arg(long, name = "cache")]
23+
pub cache_path: Option<String>,
24+
25+
#[arg(long, name = "clear-cache")]
26+
pub clear_cache: Option<bool>,
27+
28+
#[arg(long, name = "recreate-config")]
29+
pub recreate_config: Option<bool>,
2230
}
2331

2432
#[derive(Subcommand)]

src/initializers/init_project.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
//! src/initializers/init_project.rs
22
3-
use std::path::PathBuf;
4-
use std::{collections::HashMap, fmt, str::FromStr};
3+
use std::{collections::HashMap, fmt, path::PathBuf, str::FromStr};
54

65
use clap::Args;
76

8-
use crate::utils::file_writer::FileWriteError;
97
use crate::{
10-
app_config::app_config::AppConfig,
8+
app_config::{AppCache, app_config::AppConfig},
119
initializers::project_types::{
1210
ansible::{AnsibleProject, AnsibleProjectError},
1311
maven::{MavenProject, MavenProjectError},
1412
},
13+
utils::file_writer::FileWriteError,
1514
};
1615

1716
#[derive(Debug)]
1817
pub enum InitProjectError {
1918
Invalid(String),
2019
FileWrite(FileWriteError),
20+
NotFound(PathBuf),
2121
// Specific project type errors
2222
MavenProject(MavenProjectError),
2323
AnsibleProject(AnsibleProjectError),
@@ -50,6 +50,9 @@ impl fmt::Display for InitProjectError {
5050
InitProjectError::FileWrite(e) => {
5151
write!(f, "{}", e)
5252
}
53+
InitProjectError::NotFound(e) => {
54+
write!(f, "Template files not found: {}", e.display())
55+
}
5356
InitProjectError::MavenProject(e) => {
5457
write!(f, "{}", e)
5558
}
@@ -126,7 +129,11 @@ impl ProjectFactory {
126129
}
127130
}
128131

129-
pub fn handle(args: InitProjectArgs, config: AppConfig) -> Result<(), InitProjectError> {
132+
pub fn handle(
133+
args: InitProjectArgs,
134+
config: AppConfig,
135+
cache: AppCache,
136+
) -> Result<(), InitProjectError> {
130137
// Ensure the passed project type and given profile, if any, is present in the config file
131138
// before passing it along
132139
let template: PathBuf = config
@@ -139,8 +146,17 @@ pub fn handle(args: InitProjectArgs, config: AppConfig) -> Result<(), InitProjec
139146
p.name == args.project_type && p.profile == "default"
140147
}
141148
})
142-
.map(|p| p.template_files.clone())
143-
.ok_or(InitProjectError::Invalid("Could not find template".into()))?;
149+
.ok_or(InitProjectError::Invalid(String::from(
150+
"Could not find template",
151+
)))
152+
.and_then(|p| -> Result<PathBuf, InitProjectError> {
153+
println!("CACHE DIR: {}", cache.cache_dir.clone().display());
154+
if p.template_files.starts_with(cache.cache_dir) {
155+
Ok(p.template_files.clone())
156+
} else {
157+
Err(InitProjectError::NotFound(p.template_files.clone()))
158+
}
159+
})?;
144160

145161
// Convert custom key=value settings into map
146162
// for easier lookup

src/main.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ use clap::Parser;
66

77
use crate::cli::{Cli, Command};
88

9-
use repotools::app_config::{ConfigError, app_config};
10-
use repotools::cli;
11-
use repotools::features::{ProjectFeatureError, project_feature};
12-
use repotools::initializers::{InitProjectError, init_project};
9+
use repotools::{
10+
app_config::{CacheError, ConfigError, app_cache, app_config},
11+
cli,
12+
features::{ProjectFeatureError, project_feature},
13+
initializers::{InitProjectError, init_project},
14+
};
1315

1416
#[derive(Debug)]
1517
enum AppError {
1618
Config(ConfigError),
19+
Cache(CacheError),
1720
InitProject(InitProjectError),
1821
ProjectFeature(ProjectFeatureError),
1922
}
@@ -24,6 +27,12 @@ impl From<ConfigError> for AppError {
2427
}
2528
}
2629

30+
impl From<CacheError> for AppError {
31+
fn from(e: CacheError) -> Self {
32+
AppError::Cache(e)
33+
}
34+
}
35+
2736
impl From<InitProjectError> for AppError {
2837
fn from(e: InitProjectError) -> Self {
2938
AppError::InitProject(e)
@@ -48,6 +57,9 @@ impl fmt::Display for AppError {
4857
AppError::ProjectFeature(e) => {
4958
write!(f, "FeatureErr: {}", e)
5059
}
60+
AppError::Cache(e) => {
61+
write!(f, "CacheErr: {}", e)
62+
}
5163
}
5264
}
5365
}
@@ -56,10 +68,11 @@ fn main() -> Result<(), AppError> {
5668
let cli = Cli::parse();
5769

5870
let config = app_config::get_config(cli.global.config_path)?;
71+
let cache = app_cache::get_cache(cli.global.cache_path)?;
5972

6073
match cli.command {
6174
Command::InitProject(args) => {
62-
if let Err(e) = init_project::handle(args, config) {
75+
if let Err(e) = init_project::handle(args, config, cache) {
6376
eprintln!("Could not initialize project: {}", e)
6477
}
6578
}

0 commit comments

Comments
 (0)