Skip to content

Commit

Permalink
feat: split CLI and library into separate crates
Browse files Browse the repository at this point in the history
To allow for using the core business logic here outside of the CLI (eg.
integration with `-Zscript`).
  • Loading branch information
johnallen3d committed Jan 6, 2024
1 parent 162ef19 commit f7b26bc
Show file tree
Hide file tree
Showing 19 changed files with 478 additions and 512 deletions.
741 changes: 306 additions & 435 deletions Cargo.lock

Large diffs are not rendered by default.

34 changes: 13 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
[package]
name = "conditions"
[workspace]
resolver = "2"

members = ["cli", "lib"]

[workspace.package]
version = "0.2.0"
edition = "2021"
authors = ["John Allen <[email protected]>"]
repository = "https://github.com/johnallen3d/conditions"
authors = ["John Allen <[email protected]"]
homepage = "https://github.com/johnallen3d/conditions"
repository = "https://github.com/johnallen3d/mp-cli.git"
description = "Fetch basic weather conditions for current or specified location"
keywords = ["weather"]
categories = ["command-line-utilities"]
readme = "README.md"

license = "MIT"

[dependencies]
clap = { version = "4.4.13", features = ["derive"] }
confy = "0.5.1"
env_logger = "0.10.1"
eyre = "0.6.11"
lazy_static = "1.4.0"
log = "0.4.20"
rustls = "0.21.9"
[workspace.dependencies]
eyre = "0.6.8"
serde = { version = "1", features = ["derive"] }
thiserror = "1.0.56"
ureq = { version = "2.9.1", features = ["json"] }
sqlx = { version = "0.7", features = ["macros", "runtime-tokio", "sqlite"] }
tokio = { version = "1.34", features = ["macros"] }

[dev-dependencies]
tempfile = "3.8.1"
thiserror = "1.0.50"
tokio = { version = "1.33", features = ["macros"] }
28 changes: 28 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "conditions-cli"
version = { workspace = true }
edition = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
description = "CLI tootl to fetch basic weather conditions for current or specified location"
keywords = { workspace = true }
categories = ["command-line-utilities", "weather"]
readme = { workspace = true }
license = { workspace = true }

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.4.8", features = ["derive"] }
conditions = { path = "../lib" }
env_logger = "0.10.0"
eyre = { workspace = true }
log = "0.4.20"
serde = { workspace = true }
serde_json = "1.0.111"
thiserror = { workspace = true }
tokio = { workspace = true }

[dev-dependencies]
tempfile = "3.8.1"
16 changes: 3 additions & 13 deletions src/args.rs → cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,10 @@ pub enum Unit {
}

impl Unit {
#[must_use]
pub fn from_char(unit: char) -> Option<Self> {
match unit {
'c' => Some(Self::C),
'f' => Some(Self::F),
_ => None,
}
}

#[must_use]
pub fn as_char(&self) -> char {
pub fn to(&self) -> conditions::Unit {
match self {
Unit::C => 'c',
Unit::F => 'f',
Unit::C => conditions::Unit::C,
Unit::F => conditions::Unit::F,
}
}
}
Expand Down
37 changes: 24 additions & 13 deletions src/lib.rs → cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@

use clap::Parser;

mod args;

use args::{
Command, Conditions, ConfigSubcommand, LocationSubcommand, UnitSubcommand,
WeatherApiKeySubcommand,
};
use conditions::cache::Cache;
use conditions::config::Config;

use cache::Cache;
use config::Config;
// use conditions::Conditions;

pub(crate) mod api;
pub mod args;
mod cache;
mod conditions;
mod config;
pub mod icons;
mod location;
mod weather;
#[tokio::main(flavor = "current_thread")]
async fn main() {
env_logger::init();

match run().await {
Ok(result) => println!("{result}"),
Err(err) => {
// for user
eprintln!("{err}");
// for development
log::error!("{:?}", err);
}
}
}

/// Entry point for running the application logic based on parsed CLI arguments.
///
Expand All @@ -44,9 +53,11 @@ pub async fn run() -> eyre::Result<String> {
Command::Current { region } => {
let (config, mut cache) = init().await?;

conditions::Conditions::new(config, region.clone())
let output = conditions::Conditions::new(config, region.clone())
.fetch(&mut cache)
.await?
.await?;

serde_json::to_string(&output)?
}
Command::Location(cmd) => match &cmd.command {
LocationSubcommand::Set(input) => {
Expand All @@ -73,7 +84,7 @@ pub async fn run() -> eyre::Result<String> {
WeatherApiKeySubcommand::Unset => Config::unset_weatherapi_token()?,
},
Command::Unit(cmd) => match &cmd.command {
UnitSubcommand::Set(unit) => Config::set_unit(unit.unit)?,
UnitSubcommand::Set(unit) => Config::set_unit(unit.unit.to())?,
UnitSubcommand::View => {
format!("unit stored as: {}", Config::load()?.unit)
}
Expand Down
25 changes: 25 additions & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "conditions"
version = { workspace = true }
edition = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
description = "Fetch basic weather conditions for current or specified location"
keywords = { workspace = true }
categories = ["weather"]
readme = { workspace = true }
license = { workspace = true }

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
confy = "0.5.1"
eyre = { workspace = true }
lazy_static = "1.4.0"
rustls = "0.22.1"
sqlx = { version = "0.7", features = ["macros", "runtime-tokio", "sqlite"] }
thiserror = { workspace = true }
ureq = { version = "2.8.0", features = ["json"] }
serde = { workspace = true }
tokio = { workspace = true }
File renamed without changes.
File renamed without changes.
15 changes: 8 additions & 7 deletions src/conditions.rs → lib/src/conditions.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use serde::Serialize;

use crate::{
args::Unit, cache::Cache, config::Config, location,
weather::CurrentConditions,
cache::Cache, config::Config, location, weather::CurrentConditions,
};

use crate::Unit;

#[derive(Debug, Serialize)]
struct Output {
temp: i32,
icon: String,
pub struct Output {
pub temp: i32,
pub icon: String,
}

pub struct Conditions {
Expand All @@ -27,7 +28,7 @@ impl Conditions {
/// - retrieve wather conditions from weather provider(s) for location
/// - compose output structure
/// - convert output to JSON and return
pub async fn fetch(&mut self, cache: &mut Cache) -> eyre::Result<String> {
pub async fn fetch(&mut self, cache: &mut Cache) -> eyre::Result<Output> {
let location = if let Some(region) = &self.region {
location::get(cache, Some(region)).await?
} else {
Expand All @@ -37,7 +38,7 @@ impl Conditions {
let conditions = CurrentConditions::get(&self.config, &location)?;
let output = self.to_output(conditions);

Ok(ureq::serde_json::to_string(&output)?)
Ok(output)
}

fn to_output(&self, conditions: CurrentConditions) -> Output {
Expand Down
12 changes: 5 additions & 7 deletions src/config.rs → lib/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ use eyre::WrapErr;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::{
args::Unit,
cache::Cache,
location::{self, Location},
};
use crate::cache::Cache;
use crate::location;
use crate::Unit;

#[derive(Error, Debug)]
pub enum ParseConfigError {
Expand All @@ -25,7 +23,7 @@ pub const CONFIG_NAME: &str = "config";
#[serde(default)]
pub struct Config {
#[serde(flatten)]
pub location: Option<Location>,
pub location: Option<location::Location>,
pub unit: Unit,
pub weatherapi_token: Option<String>,
}
Expand Down Expand Up @@ -66,7 +64,7 @@ impl Config {
pub async fn get_location(
&mut self,
cache: &mut Cache,
) -> eyre::Result<Location> {
) -> eyre::Result<location::Location> {
match &self.location {
Some(location) => Ok(location.clone()),
None => {
Expand Down
File renamed without changes.
66 changes: 66 additions & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#![deny(clippy::pedantic)]

use std::fmt;

use serde::{Deserialize, Deserializer, Serialize};

pub(crate) mod api;
pub mod cache;
pub mod conditions;
pub mod config;
pub mod icons;
pub mod location;
mod weather;

pub use cache::Cache;
pub use conditions::Conditions;
pub use config::Config;

#[derive(Clone, Copy, Debug, Default, Serialize)]
pub enum Unit {
C,
#[default]
F,
}

impl Unit {
#[must_use]
pub fn from_char(unit: char) -> Option<Self> {
match unit {
'c' => Some(Self::C),
'f' => Some(Self::F),
_ => None,
}
}

#[must_use]
pub fn as_char(&self) -> char {
match self {
Unit::C => 'c',
Unit::F => 'f',
}
}
}

impl fmt::Display for Unit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
Unit::C => "celsius",
Unit::F => "fahrenheit",
};
write!(f, "{text}")
}
}

impl<'de> Deserialize<'de> for Unit {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?.to_lowercase();
match s.as_str() {
"c" => Ok(Unit::C),
_ => Ok(Unit::F),
}
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 0 additions & 16 deletions src/main.rs

This file was deleted.

0 comments on commit f7b26bc

Please sign in to comment.