Skip to content

Commit

Permalink
Large refactoring of Cli module (#115)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrHedmad authored Nov 25, 2024
2 parents fe27e3d + c360099 commit 8f5d07b
Show file tree
Hide file tree
Showing 18 changed files with 1,242 additions and 1,025 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ the top. Non pre-release versions sometimes have an associated name.
- The way that profiles are handled was changed.
Now, the original files are moved to `.kerblam/scratch/` during the workflow,
instead of remaining in the original directory (and being renamed `.original`).
- For developers: the Command Line Interface module was refactored and subdivided
into sub-modules.

### Fixed
- Fixed a bug that occurred if you used a profile in a run, then deleted that
Expand Down
19 changes: 10 additions & 9 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,11 @@ use anyhow::Result;
use homedir::get_my_home;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Default)]
pub struct Cache {
pub last_executed_profile: Option<String>,
}

impl Default for Cache {
fn default() -> Self {
Cache {
last_executed_profile: None,
}
}
}

/// Return the cache file for the current directory
///
/// The location of the cache file is dependent on the hash of the path
Expand Down Expand Up @@ -83,6 +75,7 @@ pub fn write_cache(content: Cache) -> Result<()> {
/// Returns None if there is no cache.
///
/// Also updates the cache to the new profile
#[allow(clippy::needless_update)]
pub fn check_last_profile(current_profile: String) -> Option<bool> {
let last_profile = get_cache();

Expand All @@ -93,6 +86,9 @@ pub fn check_last_profile(current_profile: String) -> Option<bool> {

let new_cache = Cache {
last_executed_profile: Some(current_profile),
// This line is where clippy complains: there is no need to do this
// as Cache has only the `last_executed_profile` field.
// But - just for now. It's added for future compatibility
..last_profile.clone().unwrap_or_default()
};
match write_cache(new_cache) {
Expand All @@ -112,11 +108,15 @@ pub fn check_last_profile(current_profile: String) -> Option<bool> {
/// Delete from the cache the last profile used.
///
/// This currently just deletes the cache.
#[allow(clippy::needless_update)]
pub fn delete_last_profile() -> Result<()> {
let cache = get_cache();

let new_cache = Cache {
last_executed_profile: None,
// This line is where clippy complains: there is no need to do this
// as Cache has only the `last_executed_profile` field.
// But - just for now. It's added for future compatibility
..cache.unwrap_or_default()
};

Expand All @@ -125,6 +125,7 @@ pub fn delete_last_profile() -> Result<()> {
Ok(())
}

/// Calculate the hash of some hashable object
fn calc_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
Expand Down
78 changes: 78 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use clap::{Parser, Subcommand};
use std::ffi::OsString;

use anyhow::Result;

use crate::commands::{
DataCommand, IgnoreCommand, NewCommand, PackageCommand, ReplayCommand, RunCommand,
};

/// This string is displayed when the help message is invoked.
const KERBLAM_LONG_ABOUT: &str = concat!(
" _ __ _ _ _ \n",
" | |/ / ___ _ _ | |__ | | __ _ _ __ | |\n",
" | ' < / -_)| '_|| '_ \\| |/ _` || ' \\ |_|\n",
" |_|\\_\\\\___||_| |_.__/|_|\\__,_||_|_|_|(_)\n",
" \n",
"Manage your data analysis projects quickly and easily.\n\n",
"Kerblam! is a project manager that lets you focus on getting things done,\n",
"with it taking care of tedious or tricky parts of project management.\n\n",
"You can find the Kerblam! manual online at https://kerblam.dev/.\n",
"The source code is available at https://github.com/MrHedmad/kerblam"
);

/// A very simple trait that every command has
///
/// This makes it easier to implement the right signature with tab-completion
pub trait Executable {
fn execute(self) -> Result<()>;
}

#[derive(Parser, Debug)]
#[command(author = "hedmad", version, about = KERBLAM_LONG_ABOUT)]
pub struct Cli {
#[command(subcommand)]
command: Command,
}

// Each command has its own docstring near the implementation of the
// **Command struct. See the deeper files.

#[derive(Subcommand, Debug)]
enum Command {
New(NewCommand),
Run(RunCommand),
Data(DataCommand),
Replay(ReplayCommand),
Package(PackageCommand),
Ignore(IgnoreCommand),
}

impl Executable for Command {
fn execute(self) -> Result<()> {
match self {
Self::New(x) => x.execute(),
Self::Run(x) => x.execute(),
Self::Data(x) => x.execute(),
Self::Replay(x) => x.execute(),
Self::Package(x) => x.execute(),
Self::Ignore(x) => x.execute(),
}
}
}

// This is the same as the trait `Executable`, but for module privacy reasons
// it's not implemented as such, but as a normal (associated) function.
// Plus, it's hard to store the args data in the Cli struct, so an associated
// function would be needed anyway.
impl Cli {
pub fn execute<I, T>(raw_args: I) -> Result<()>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let args = Cli::parse_from(raw_args);

args.command.execute()
}
}
Loading

0 comments on commit 8f5d07b

Please sign in to comment.