Some refacto on output managment

This commit is contained in:
jcamiel 2023-12-01 17:50:04 +01:00
parent 20d86f5188
commit 9c7e793ba1
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
12 changed files with 127 additions and 149 deletions

View File

@ -1 +1 @@
error: Error ~~~: ~~~ (os error ~~~)
error: build~tmp can not be written (~~~)

View File

@ -1 +1 @@
error: Error ~~~foo~bar~baz: ~~~ (os error ~~~)
error: ~~~foo~bar~baz can not be written (~~~)

View File

@ -15,6 +15,8 @@
* limitations under the License.
*
*/
use crate::runner;
use hurl_core::error::Error as CoreError;
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq)]
@ -24,16 +26,11 @@ impl Error {
pub fn new(message: &str) -> Error {
Error(message.to_string())
}
pub fn from_path(error: std::io::Error, path: &str) -> Error {
let message = format!("Error {path}: {error}");
Error::new(&message)
}
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Error::new(&value.to_string())
impl From<runner::Error> for Error {
fn from(error: runner::Error) -> Self {
Error::new(&error.fixme())
}
}

View File

@ -15,9 +15,8 @@
* limitations under the License.
*
*/
use crate::output;
use crate::output::error::Error;
use crate::runner::HurlResult;
use crate::runner::{HurlResult, Output};
/// Writes the `hurl_result` JSON representation to the file `filename_out`.
///
@ -33,5 +32,10 @@ pub fn write_json(
let json_result = hurl_result.to_json(content, filename_in);
let serialized = serde_json::to_string(&json_result).unwrap();
let s = format!("{serialized}\n");
output::write_output(&s.into_bytes(), filename_out)
let bytes = s.into_bytes();
match filename_out {
Some(file) => Output::File(file.to_string()).write(&bytes)?,
None => Output::StdOut.write(&bytes)?,
}
Ok(())
}

View File

@ -24,29 +24,7 @@
mod error;
mod json;
mod raw;
mod stdout;
use std::io::Write;
use std::path::Path;
pub use self::error::Error;
pub use self::json::write_json;
pub use self::raw::write_body;
/// Writes `bytes` to the file `filename` or stdout by default.
fn write_output(bytes: &Vec<u8>, filename: &Option<String>) -> Result<(), Error> {
match filename {
None => stdout::write_stdout(bytes.as_slice())?,
Some(filename) => {
let path = Path::new(filename.as_str());
let mut file = match std::fs::File::create(path) {
Ok(file) => file,
Err(e) => return Err(Error::from_path(e, filename)),
};
if let Err(e) = file.write_all(bytes.as_slice()) {
return Err(Error::from_path(e, filename));
}
}
}
Ok(())
}

View File

@ -16,11 +16,11 @@
*
*/
use hurl_core::ast::{Pos, SourceInfo};
use hurl_core::error::Error;
use crate::runner::HurlResult;
use crate::output::Error;
use crate::runner;
use crate::runner::{HurlResult, Output};
use crate::util::logger::Logger;
use crate::{output, runner};
/// Writes the `hurl_result` last body response to the file `filename_out`.
///
@ -33,7 +33,7 @@ pub fn write_body(
color: bool,
filename_out: &Option<String>,
logger: &Logger,
) -> Result<(), output::error::Error> {
) -> Result<(), Error> {
// By default, we output the body response bytes of the last entry
if let Some(entry_result) = hurl_result.entries.last() {
if let Some(call) = entry_result.calls.last() {
@ -47,24 +47,27 @@ pub fn write_body(
text.push('\n');
output.append(&mut text.into_bytes());
}
let mut body = if entry_result.compressed {
match response.uncompress_body() {
Ok(bytes) => bytes,
if entry_result.compressed {
let mut bytes = match response.uncompress_body() {
Ok(b) => b,
Err(e) => {
// FIXME: we convert to a runner::Error to be able to use fixme
// method. Can we do otherwise (without creating an artificial
// error a first character).
// FIXME: we convert to a runner::Error to be able to use fixme!
// We may pass a [`SourceInfo`] as a parameter of this method to make
// a more accurate error
let source_info = SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0));
let error = runner::Error::new(source_info, e.into(), false);
let message = error.fixme();
return Err(output::error::Error::new(&message));
return Err(error.into());
}
}
};
output.append(&mut bytes);
} else {
response.body.clone()
};
output.append(&mut body);
output::write_output(&output, filename_out)?;
let bytes = &response.body;
output.extend(bytes);
}
match filename_out {
Some(file) => Output::File(file.to_string()).write(&output)?,
None => Output::StdOut.write(&output)?,
}
} else {
logger.info("No response has been received");
}

View File

@ -1,41 +0,0 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2023 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use std::io;
#[cfg(target_family = "windows")]
use std::io::IsTerminal;
use std::io::Write;
use crate::output::error::Error;
#[cfg(target_family = "unix")]
pub(crate) fn write_stdout(buf: &[u8]) -> Result<(), Error> {
let mut handle = io::stdout().lock();
handle.write_all(buf)?;
Ok(())
}
#[cfg(target_family = "windows")]
pub(crate) fn write_stdout(buf: &[u8]) -> Result<(), Error> {
if io::stdout().is_terminal() {
println!("{}", String::from_utf8_lossy(buf));
} else {
let mut handle = io::stdout().lock();
handle.write_all(buf)?;
}
Ok(())
}

View File

@ -190,7 +190,7 @@ impl hurl_core::error::Error for Error {
}
RunnerError::FileReadAccess { file } => format!("file {file} can not be read"),
RunnerError::FileWriteAccess { file, error } => {
format!("{file} can not be write ({error})")
format!("{file} can not be written ({error})")
}
RunnerError::FilterDecode(encoding) => {
format!("value can not be decoded with <{encoding}> encoding")

View File

@ -21,6 +21,7 @@
pub use self::error::{Error, RunnerError};
pub use self::hurl_file::run;
pub use self::number::Number;
pub use self::output::Output;
pub use self::result::{AssertResult, CaptureResult, EntryResult, HurlResult};
pub use self::runner_options::{RunnerOptions, RunnerOptionsBuilder};
pub use self::value::Value;
@ -38,6 +39,7 @@ mod multiline;
mod multipart;
mod number;
mod options;
mod output;
mod predicate;
mod predicate_value;
mod query;
@ -48,5 +50,4 @@ mod result;
mod runner_options;
mod template;
mod value;
mod write;
mod xpath;

View File

@ -0,0 +1,87 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2023 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use std::fs::File;
use std::io;
#[cfg(target_family = "windows")]
use std::io::IsTerminal;
use std::io::Write;
use crate::runner::{Error, RunnerError};
use hurl_core::ast::{Pos, SourceInfo};
/// Represents the output of write operation: can be either a file or stdout.
pub enum Output {
StdOut,
File(String),
}
impl Output {
/// Writes these `bytes` to the output.
pub fn write(&self, bytes: &[u8]) -> Result<(), Error> {
match self {
Output::StdOut => match write_stdout(bytes) {
Ok(_) => Ok(()),
Err(e) => Err(Error::new_file_write_access("stdout", &e.to_string())),
},
Output::File(filename) => {
let mut file = match File::create(filename) {
Ok(file) => file,
Err(e) => return Err(Error::new_file_write_access(filename, &e.to_string())),
};
match file.write_all(bytes) {
Ok(_) => Ok(()),
Err(e) => Err(Error::new_file_write_access(filename, &e.to_string())),
}
}
}
}
}
impl Error {
/// Creates a new file write access error.
fn new_file_write_access(filename: &str, error: &str) -> Error {
// TODO: improve the error with a [`SourceInfo`] passed in parameter.
let source_info = SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0));
Error::new(
source_info,
RunnerError::FileWriteAccess {
file: filename.to_string(),
error: error.to_string(),
},
false,
)
}
}
#[cfg(target_family = "unix")]
fn write_stdout(buf: &[u8]) -> Result<(), io::Error> {
let mut handle = io::stdout().lock();
handle.write_all(buf)?;
Ok(())
}
#[cfg(target_family = "windows")]
fn write_stdout(buf: &[u8]) -> Result<(), io::Error> {
if io::stdout().is_terminal() {
println!("{}", String::from_utf8_lossy(buf));
} else {
let mut handle = io::stdout().lock();
handle.write_all(buf)?;
}
Ok(())
}

View File

@ -19,8 +19,8 @@ use hurl_core::ast::{Pos, SourceInfo};
use crate::http::{Call, Cookie};
use crate::runner::error::Error;
use crate::runner::output::Output;
use crate::runner::value::Value;
use crate::runner::write::write_file;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HurlResult {
@ -123,9 +123,9 @@ impl EntryResult {
return Err(Error::new(source_info, e.into(), false));
}
};
write_file(&bytes, &filename)
Output::File(filename).write(&bytes)
} else {
write_file(&response.body, &filename)
Output::File(filename).write(&response.body)
}
}
None => Ok(()),

View File

@ -1,51 +0,0 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2023 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use crate::runner::{Error, RunnerError};
use hurl_core::ast::{Pos, SourceInfo};
use std::fs::File;
use std::io::Write;
// TODO: make functions for sdtout
/// Writes these `bytes` to the file `filename`.
pub fn write_file(bytes: &[u8], filename: &str) -> Result<(), Error> {
let mut file = match File::create(filename) {
Ok(file) => file,
Err(e) => return Err(Error::new_file_write_access(filename, &e.to_string())),
};
match file.write_all(bytes) {
Ok(_) => Ok(()),
Err(e) => Err(Error::new_file_write_access(filename, &e.to_string())),
}
}
impl Error {
/// Creates a new file write access error.
fn new_file_write_access(filename: &str, error: &str) -> Error {
// TODO: improve the error with a [`SourcInfo`] passed in parameter.
let source_info = SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0));
Error::new(
source_info,
RunnerError::FileWriteAccess {
file: filename.to_string(),
error: error.to_string(),
},
false,
)
}
}