improve error messages, edition upgrade

master
Mathias Rothenhaeusler 2026-01-19 19:38:19 +01:00
parent 2bfd2d4ba8
commit 7dcf5bb201
6 changed files with 53 additions and 53 deletions

11
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
@ -11,6 +11,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -86,8 +92,9 @@ checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]] [[package]]
name = "deepl" name = "deepl"
version = "1.0.1" version = "1.0.2"
dependencies = [ dependencies = [
"anyhow",
"clap", "clap",
"directories", "directories",
"dotenv", "dotenv",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "deepl" name = "deepl"
version = "1.0.1" version = "1.0.2"
edition = "2018" edition = "2024"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
authors = ["Mathias Rothenhäusler <safemind@posteo.net"] authors = ["Mathias Rothenhäusler <safemind@posteo.net"]
@ -15,3 +15,4 @@ clap = {version = "~2.33.0", features = ["yaml"]}
directories = "4.0" directories = "4.0"
dotenv = "0.15.0" dotenv = "0.15.0"
sprintf = "0.1.1" sprintf = "0.1.1"
anyhow = "1.0.100"

View File

@ -1,17 +1,18 @@
# Deepl deepl 1.0
Mathias Rothenhaeusler <safemind@posteo.net>
Cli API for deepl translations. Create a .env config file in your user config folder (e.g. ~/config/deepl/.env).
Required keys URI (eg. https://api-free.deepl.com/v2/translate) and KEY (eg. XYZ:rg).
Cli API for deepl translations. API-Key is required.<br> USAGE:
deepl [OPTIONS] <INPUT>
USAGE:<br> FLAGS:
&emsp;deepl [OPTIONS] \<INPUT><br> -h, --help Prints help information
-V, --version Prints version information
FLAGS:<br> OPTIONS:
&emsp;-h, --help Prints help information<br> -s, --source <source_lang> The language you want to translate. Default is autodetect.
&emsp;-V, --version Prints version information<br> -t, --target <target_lang> The language your text should be tranlated to. Default is DE.
OPTIONS:<br> ARGS:
&emsp;-s, --source <source_lang> The language you want to translate. Default is autodectect.<br> <INPUT> Text to translate
&emsp;-t, --target <target_lang> The language your text should be tranlated to. Default is DE.<br>
ARGS:<br>
&emsp;\<INPUT> Text to translate<br>

View File

@ -1,7 +1,7 @@
name: deepl name: deepl
version: "1.0" version: "1.0"
author: Mathias Rothenhaeusler <safemind@posteo.net> author: Mathias Rothenhaeusler <safemind@posteo.net>
about: Cli API for deepl translations. about: Cli API for deepl translations. Create a .env config file in your user config folder (e.g. ~/config/deepl/.env). Required keys URI (eg. https://api-free.deepl.com/v2/translate) and KEY (eg. XYZ:rg).
args: args:
- source: - source:
short: s short: s

View File

@ -1,3 +1,4 @@
use anyhow::{anyhow, Context, Result};
use clap::{load_yaml, App, ArgMatches}; use clap::{load_yaml, App, ArgMatches};
use directories::BaseDirs; use directories::BaseDirs;
use dotenv; use dotenv;
@ -13,23 +14,13 @@ pub struct Params {
} }
impl Params { impl Params {
pub fn new() -> Result<Self, String> { pub fn new() -> Result<Self> {
let base_dir: BaseDirs = BaseDirs::new().unwrap(); let base_dir: BaseDirs = BaseDirs::new().context("failed to determine base directories")?;
let my_path: PathBuf = base_dir.config_dir().join("deepl/.env"); let my_path: PathBuf = base_dir.config_dir().join("deepl/.env");
match dotenv::from_path(my_path.as_path()) {
Ok(env) => env, dotenv::from_path(my_path.as_path())
Err(_) => { .context(format!("Missing .env file {}", my_path.display()))?;
return Err(format!(
"Could not load .env file {:?}",
base_dir
.config_dir()
.join("deepl/.env")
.as_path()
.as_os_str()
));
}
};
let yaml = load_yaml!("./../../cli.yml"); let yaml = load_yaml!("./../../cli.yml");
let matches: ArgMatches = App::from_yaml(yaml).get_matches(); let matches: ArgMatches = App::from_yaml(yaml).get_matches();
@ -37,29 +28,34 @@ impl Params {
Ok(Self { Ok(Self {
source_lang: matches.value_of("source").unwrap_or("0").to_string(), source_lang: matches.value_of("source").unwrap_or("0").to_string(),
target_lang: matches.value_of("target").unwrap_or("DE").to_string(), target_lang: matches.value_of("target").unwrap_or("DE").to_string(),
key: env::var("KEY").unwrap(), key: env::var("KEY").context("KEY missing")?,
uri: env::var("URI").unwrap(), uri: env::var("URI").context("URI missing")?,
text: matches.value_of("INPUT").unwrap().to_string(), text: matches.value_of("INPUT").context("input missing")?.to_string(),
}) })
} }
pub fn url(&self) -> String {
sprintf!("%s?auth_key=%s", self.uri, self.key).unwrap() pub fn url(&self) -> Result<String> {
let url = sprintf!("%s?auth_key=%s", self.uri, self.key)
.map_err(|e| anyhow!("could not create request body: {e:?}"))?;
Ok(url)
} }
pub fn body(&self) -> String { pub fn body(&self) -> Result<String> {
let mut body = sprintf!( let mut body = sprintf!(
"auth_key=%s&text=%s&target_lang=%s", "auth_key=%s&text=%s&target_lang=%s",
self.key, self.key,
self.text, self.text,
self.target_lang self.target_lang
) )
.unwrap(); .map_err(|e| anyhow!("could not create request body: {e:?}"))?;
if self.source_lang != "0" { if self.source_lang != "0" {
let add = sprintf!("&source_lang=%s", self.source_lang).unwrap(); let add = sprintf!("&source_lang=%s", self.source_lang)
.map_err(|e| anyhow!("could not append source_lang: {e:?}"))?;
body.push_str(&add); body.push_str(&add);
} }
body Ok(body)
} }
} }

View File

@ -4,29 +4,24 @@ use crate::engine::params::Params;
use crate::engine::response::DeeplResponse; use crate::engine::response::DeeplResponse;
use hyper::{body, Body, Client, Method, Request}; use hyper::{body, Body, Client, Method, Request};
use hyper_tls::HttpsConnector; use hyper_tls::HttpsConnector;
use anyhow::Result;
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<()> {
let https = HttpsConnector::new(); let https = HttpsConnector::new();
let client = Client::builder().build::<_, hyper::Body>(https); let client = Client::builder().build::<_, hyper::Body>(https);
let params: Params = match Params::new() { let params: Params = Params::new()?;
Ok(result) => result,
Err(e) => {
eprintln!("{}", e);
return Ok(());
},
};
let request = Request::builder() let request = Request::builder()
.method(Method::POST) .method(Method::POST)
.uri(params.url()) .uri(params.url()?)
.header("content-type", "application/x-www-form-urlencoded") .header("content-type", "application/x-www-form-urlencoded")
.body(Body::from(params.body()))?; .body(Body::from(params.body()?))?;
let res = client.request(request).await?; let res = client.request(request).await?;
let body_bytes = body::to_bytes(res.into_body()).await?; let body_bytes = body::to_bytes(res.into_body()).await?;
let body = String::from_utf8(body_bytes.to_vec()).expect("response was not valid utf-8"); let body = String::from_utf8(body_bytes.to_vec())?;
let v: DeeplResponse = serde_json::from_str(&body)?; let v: DeeplResponse = serde_json::from_str(&body)?;
println!("{}", v.get_text(&params.target_lang)); println!("{}", v.get_text(&params.target_lang));
Ok(()) Ok(())