feat: cli only prints json, cli-pretty-json feature

This commit is contained in:
gak 2023-08-29 13:11:28 +10:00
parent 44fe9bc48e
commit 8881d0fa59
No known key found for this signature in database
7 changed files with 77 additions and 30 deletions

View file

@ -6,10 +6,11 @@ edition = "2021"
license = "MIT OR Apache-2.0"
[features]
default = ["cli", "fancy"]
default = ["cli", "cli-pretty-json", "fancy-errors"]
fancy = ["miette/fancy"]
fancy-errors = ["miette/fancy"]
cli = ["dep:clap", "dep:tracing-subscriber"]
cli-pretty-json = ["dep:colored_json"]
[dependencies]
miette = { version = "5.10.0", features = ["fancy"] }
@ -30,6 +31,7 @@ pkce = "0.2.0"
clap = { version = "4.3.19", features = ["derive", "env"], optional = true }
tracing-subscriber = { version = "0.3.17", optional = true }
colored_json = { version = "3.2.0", optional = true }
[dev-dependencies]
test-log = { version = "0.2.12", default-features = false, features = ["trace"] }

View file

@ -1,4 +1,20 @@
use crate::Data;
pub mod calendar_history;
pub mod energy;
pub mod powerwall;
pub mod vehicle;
pub fn print_json<T>(data: Data<T>) {
#[cfg(feature = "cli-pretty-json")]
{
use colored_json::prelude::*;
println!("{}", data.body().to_colored_json_auto().unwrap());
}
#[cfg(not(feature = "cli-pretty-json"))]
{
println!("{:#?}", data.body());
panic!();
}
}

View file

@ -1,5 +1,6 @@
use crate::calendar_history::CalendarHistoryValues;
use crate::cli::calendar_history::CalendarHistoryArgs;
use crate::cli::print_json;
use crate::energy::EnergySiteId;
use crate::Api;
use chrono::DateTime;
@ -42,8 +43,7 @@ impl EnergySiteArgs {
start_date,
end_date,
};
let history = api.energy_sites_calendar_history(&values).await?;
println!("{:#?}", history);
print_json(api.energy_sites_calendar_history(&values).await?);
}
}
Ok(())

View file

@ -1,4 +1,5 @@
use crate::calendar_history::{HistoryKind, HistoryPeriod};
use crate::cli::print_json;
use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId};
use crate::Api;
use clap::{Args, Subcommand};
@ -23,18 +24,18 @@ impl PowerwallArgs {
pub async fn run(&self, api: &Api) -> miette::Result<()> {
match self.command {
PowerwallCommand::Status => {
dbg!(api.powerwall_status(&self.id).await?);
print_json(api.powerwall_status(&self.id).await?);
}
PowerwallCommand::History => {
dbg!(
print_json(
api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
powerwall_id: self.id.clone(),
period: HistoryPeriod::Day,
kind: HistoryKind::Power,
start_date: None,
end_date: None
end_date: None,
})
.await?
.await?,
);
}
}

View file

@ -1,3 +1,4 @@
use crate::cli::print_json;
use crate::vehicles::{SetChargeLimit, SetChargingAmps};
use crate::{Api, VehicleId};
use clap::{Args, Subcommand};
@ -35,28 +36,24 @@ impl VehicleArgs {
pub async fn run(self, api: &Api) -> miette::Result<()> {
match self.command {
VehicleCommand::Data => {
dbg!(api.vehicle_data(&self.id).await?);
print_json(api.vehicle_data(&self.id).await?);
}
VehicleCommand::ChargeState => {
dbg!(api.charge_state(&self.id).await?);
print_json(api.charge_state(&self.id).await?);
}
VehicleCommand::SetChargeLimit { percent } => {
dbg!(
api.set_charge_limit(&self.id, &SetChargeLimit { percent })
.await?
);
api.set_charge_limit(&self.id, &SetChargeLimit { percent })
.await?;
}
VehicleCommand::SetChargingAmps { charging_amps } => {
dbg!(
api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps })
.await?
);
api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps })
.await?;
}
VehicleCommand::ChargeStart => {
dbg!(api.charge_start(&self.id).await?);
api.charge_start(&self.id).await?;
}
VehicleCommand::ChargeStop => {
dbg!(api.charge_stop(&self.id).await?);
api.charge_stop(&self.id).await?;
}
}
Ok(())

View file

@ -55,7 +55,7 @@ impl Api {
}
#[instrument(skip(self))]
async fn get<D>(&self, url: &str) -> Result<D, TeslatteError>
async fn get<D>(&self, url: &str) -> Result<Data<D>, TeslatteError>
where
D: for<'de> Deserialize<'de> + Debug,
{
@ -82,10 +82,10 @@ impl Api {
})?;
trace!(?body);
let json = Self::parse_json::<D, _>(&body, request)?;
trace!(?json);
let data = Self::parse_json::<D, _>(&body, request)?;
trace!(?data);
Ok(json)
Ok(Data { data, body })
}
#[instrument(skip(self))]
@ -201,10 +201,40 @@ struct ResponseError {
#[derive(Debug, Serialize)]
struct Empty {}
/// Data and body from a request. The body can be used for debugging. The CLI can optionally
/// print the raw JSON so the user can manipulate it.
///
/// This struct will automatically deref to the data type for better ergonomics.
#[derive(Debug)]
pub struct Data<T> {
data: T,
body: String,
}
impl<T> Data<T> {
pub fn data(&self) -> &T {
&self.data
}
pub fn body(&self) -> &str {
&self.body
}
}
impl<T> std::ops::Deref for Data<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
/// GET /api/1/[url]
macro_rules! get {
($name:ident, $return_type:ty, $url:expr) => {
pub async fn $name(&self) -> Result<$return_type, crate::error::TeslatteError> {
pub async fn $name(
&self,
) -> Result<crate::Data<$return_type>, crate::error::TeslatteError> {
let url = format!("{}{}", crate::API_URL, $url);
self.get(&url).await
}
@ -220,7 +250,7 @@ macro_rules! get_arg {
pub async fn $name(
&self,
arg: &$arg_type,
) -> miette::Result<$return_type, crate::error::TeslatteError> {
) -> miette::Result<crate::Data<$return_type>, crate::error::TeslatteError> {
let url = format!($url, arg);
let url = format!("{}{}", crate::API_URL, url);
self.get(&url).await
@ -235,7 +265,7 @@ macro_rules! get_args {
pub async fn $name(
&self,
values: &$args,
) -> miette::Result<$return_type, crate::error::TeslatteError> {
) -> miette::Result<crate::Data<$return_type>, crate::error::TeslatteError> {
let url = values.format($url);
let url = format!("{}{}", crate::API_URL, url);
self.get(&url).await

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use teslatte::auth::{AccessToken, RefreshToken};
use teslatte::cli::energy::EnergySiteArgs;
use teslatte::cli::powerwall::PowerwallArgs;
use teslatte::cli::print_json;
use teslatte::cli::vehicle::VehicleArgs;
use teslatte::Api;
@ -10,7 +11,7 @@ use teslatte::Api;
///
/// A command line interface for the Tesla API.
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[clap(author, version)]
struct Cli {
#[clap(subcommand)]
command: Command,
@ -105,13 +106,13 @@ async fn main() -> miette::Result<()> {
let api = Api::new(access_token, refresh_token);
match api_args.command {
ApiCommand::Vehicles => {
dbg!(api.vehicles().await?);
print_json(api.vehicles().await?);
}
ApiCommand::Vehicle(v) => {
v.run(&api).await?;
}
ApiCommand::EnergySites => {
dbg!(api.energy_sites().await?);
print_json(api.energy_sites().await?);
}
ApiCommand::EnergySite(e) => {
e.run(&api).await?;