aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Pasquet <dev@etenil.net>2022-03-28 03:38:07 +0000
committerGuillaume Pasquet <dev@etenil.net>2022-03-28 03:38:07 +0000
commit6fda3e33ebeb27485a9259f2d07c0507871f58a9 (patch)
tree755005f90be61268326cf97a68571c2a1131693a
parente18c7e97b2bde449be234de25b657909acaf10c7 (diff)
Set headers from the command line
-rw-r--r--.gitlab-ci.yml10
-rw-r--r--README.md2
-rw-r--r--src/barbfile.rs37
-rw-r--r--src/executor.rs96
-rw-r--r--src/main.rs52
-rw-r--r--src/output.rs39
6 files changed, 182 insertions, 54 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f1a229f..019530a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,10 +7,16 @@ variables:
CARGO_INCREMENTAL: 0
test:
+ variables:
+ JQ_LIB_DIR: /usr/lib/x86_64-linux-gnu
stage: test
- script:
+ before_script:
- apt update && apt install libjq1 libjq-dev libonig-dev libonig5
- - JQ_LIB_DIR=/usr/lib/x86_64-linux-gnu cargo test --all --verbose
+ - rustup component add rustfmt
+ script:
+ - cargo fmt -- --check
+ - cargo build --tests
+ - cargo test --all
# pretty:
# stage: test
diff --git a/README.md b/README.md
index ae6aa40..ad9bfd3 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,8 @@ barb [options] <file 1> <file 2> ... <file n>
- `-V, --version`: Print the software version
- `-n, --no-color`: Don't use color output
- `-f, --filter`: A JSON path to override any filters defined in the barb file
+- `-F, --no-filter`: Disable all filters (except for dependencies)
+- `--hdr <HDR>`: Set/override a header with format `NAME=VALUE`, can appear multiple times (does not affect dependencies)
- `--help`: Displays the help page
## Barb format
diff --git a/src/barbfile.rs b/src/barbfile.rs
index 54ee031..e5ef916 100644
--- a/src/barbfile.rs
+++ b/src/barbfile.rs
@@ -1,13 +1,12 @@
use jsonpath_rust::JsonPathQuery;
use regex::Regex;
use serde_json::Value;
+use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use std::fs;
+use std::path::Path;
use std::str::FromStr;
use std::string::ToString;
use std::{error::Error, fmt};
-use std::cmp::{Eq, PartialEq, PartialOrd, Ord, Ordering};
-use std::fs;
-use std::path::Path;
-
#[cfg(feature = "jq")]
use jq_rs;
@@ -210,7 +209,13 @@ struct BarbPreamble {
}
impl BarbPreamble {
- fn new(method: Method, url: String, headers: Vec<Header>, filters: Vec<BarbFilter>, dependency: Option<String>) -> Self {
+ fn new(
+ method: Method,
+ url: String,
+ headers: Vec<Header>,
+ filters: Vec<BarbFilter>,
+ dependency: Option<String>,
+ ) -> Self {
BarbPreamble {
method,
url,
@@ -257,7 +262,9 @@ impl BarbFile {
let dep_path = Path::new(dep);
if !dep_path.is_absolute() {
- let my_path = Path::new(&self.file_name).parent().or(Some(Path::new("")))?;
+ let my_path = Path::new(&self.file_name)
+ .parent()
+ .or(Some(Path::new("")))?;
return Some(String::from(my_path.join(dep_path).to_str()?));
}
@@ -307,8 +314,9 @@ impl BarbFile {
let mut bfile = Self::from_str(
fs::read_to_string(file_name.as_str())
.map_err(|_| BarbParseError {})?
- .as_str()
- ).map_err(|_| BarbParseError {})?;
+ .as_str(),
+ )
+ .map_err(|_| BarbParseError {})?;
bfile.file_name = file_name;
Ok(bfile)
}
@@ -479,12 +487,19 @@ mod tests {
#[test]
fn test_parse_dependency() {
let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb").unwrap();
- assert_eq!(bfile.dependency().as_ref().unwrap(), &String::from("blah.barb"));
+ assert_eq!(
+ bfile.dependency().as_ref().unwrap(),
+ &String::from("blah.barb")
+ );
}
#[test]
fn test_parse_mult_dependency_keeps_last() {
- let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb\n#>foo.barb\n#>bar.barb").unwrap();
- assert_eq!(bfile.dependency().as_ref().unwrap(), &String::from("bar.barb"));
+ let bfile = BarbFile::from_str("#GET^http://test.com\n#>blah.barb\n#>foo.barb\n#>bar.barb")
+ .unwrap();
+ assert_eq!(
+ bfile.dependency().as_ref().unwrap(),
+ &String::from("bar.barb")
+ );
}
}
diff --git a/src/executor.rs b/src/executor.rs
index 4323bc0..6b1bc5a 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -42,14 +42,15 @@ impl Context {
let value = String::from(
var.name("value")
.map(|m| m.as_str())
- .or(Some(&String::from(""))).unwrap()
+ .or(Some(&String::from("")))
+ .unwrap(),
);
buffer = buffer.replace(
// Since this iterates over matches, having match 0 is guaranteed. So the
// `unwrap()` operation here is safe.
var.get(0).unwrap().as_str(),
- self.vars.get(&key).or(Some(&value)).unwrap()
+ self.vars.get(&key).or(Some(&value)).unwrap(),
);
}
@@ -66,23 +67,32 @@ impl Executor {
Executor { context }
}
- fn make_req(&self, bfile: &BarbFile, output: &BarbOutput) -> ureq::Request {
- output.req(
- bfile.method_as_string(),
- self.context.substitute(&bfile.url()),
- );
+ fn make_req(
+ &self,
+ bfile: &BarbFile,
+ headers: Vec<(String, String)>,
+ output: &BarbOutput,
+ ) -> ureq::Request {
let mut req = ureq::request(
bfile.method_as_string().as_str(),
self.context.substitute(&bfile.url()).as_str(),
);
+ let mut final_headers: HashMap<String, String> = HashMap::new();
+
for header in bfile.headers() {
let hdr_val = self.context.substitute(header.value());
- req = req.set(header.name(), hdr_val.as_str());
- output.req_hdr(header.name().to_string(), hdr_val);
+ final_headers.insert(String::from(header.name()), hdr_val);
}
- output.end_req();
+ for header in headers {
+ final_headers.insert(header.0, header.1);
+ }
+
+ for (hdr_name, hdr_val) in final_headers.iter() {
+ req = req.set(hdr_name.as_str(), hdr_val.as_str());
+ output.req_hdr(String::from(hdr_name), String::from(hdr_val));
+ }
req
}
@@ -125,15 +135,34 @@ impl Executor {
}
}
+ pub fn execute_dep(&mut self, bfile: &BarbFile, output: &BarbOutput) -> Result<(), String> {
+ let req = self.make_req(&bfile, vec![], output);
+ let method = String::from(req.method());
+ let url = String::from(req.url());
+
+ let response = self.run(&bfile, req)?;
+
+ output.req_dep(method, url, response.status(), response.status_text());
+ output.end_req();
+ self.apply_filters(&bfile, response.into_string().unwrap(), &None)?;
+
+ Ok(())
+ }
+
pub fn execute(
&mut self,
bfile: &BarbFile,
output: &BarbOutput,
filter: &Option<String>,
- skip_filters: bool
+ skip_filters: bool,
+ headers: Vec<(String, String)>,
) -> Result<(), String> {
- let response = self.run(&bfile, self.make_req(&bfile, output))?;
- //let response = executor.execute(&bfile, &output)?;
+ let req = self.make_req(&bfile, headers, output);
+
+ output.req(String::from(req.method()), String::from(req.url()));
+ output.end_req();
+
+ let response = self.run(&bfile, req)?;
output.status(response.status(), response.status_text());
for header_name in response.headers_names() {
@@ -144,7 +173,7 @@ impl Executor {
}
output.end_resp_hdr();
- if ! skip_filters {
+ if !skip_filters {
output.body(self.apply_filters(&bfile, response.into_string().unwrap(), filter)?);
} else {
output.body(response.into_string().unwrap());
@@ -217,9 +246,7 @@ mod tests_context {
#[test]
fn test_context_substitute_value_with_default() {
- let vars: Vec<(String, String)> = vec![
- (String::from("chewie"), String::from("han")),
- ];
+ let vars: Vec<(String, String)> = vec![(String::from("chewie"), String::from("han"))];
let ctx = Context::new(vars.into_iter());
assert_eq!(
ctx.substitute(&String::from("blah blah {chewie:-wookie} blah")),
@@ -247,8 +274,8 @@ mod tests_make_req {
fn test_make_req_simple_get() {
let executor = Executor::new(Context::empty());
let bfile = BarbFile::from_str("#GET^http://foo.bar\n\n").unwrap();
- let output = BarbOutput::new(false, false, false, false, false, false);
- let req = executor.make_req(&bfile, &output);
+ let output = BarbOutput::quiet();
+ let req = executor.make_req(&bfile, vec![], &output);
assert_eq!(req.url(), "http://foo.bar");
assert_eq!(req.method(), "GET");
@@ -258,14 +285,33 @@ mod tests_make_req {
fn test_make_req_simple_headers() {
let executor = Executor::new(Context::empty());
let bfile = BarbFile::from_str("#GET^http://foo.bar\n#Foo: Bar\n#Bar: Baz\n\n").unwrap();
- let output = BarbOutput::new(false, false, false, false, false, false);
- let req = executor.make_req(&bfile, &output);
+ let output = BarbOutput::quiet();
+ let req = executor.make_req(&bfile, vec![], &output);
- assert_eq!(
- req.header_names(),
- vec![String::from("foo"), String::from("bar")]
- );
+ let mut header_names = req.header_names();
+ header_names.sort();
+
+ assert_eq!(header_names, vec![String::from("bar"), String::from("foo")]);
assert_eq!(req.header("foo"), Some("Bar"));
assert_eq!(req.header("bar"), Some("Baz"));
}
+
+ #[test]
+ fn test_make_req_headers_override() {
+ let executor = Executor::new(Context::empty());
+ let bfile = BarbFile::from_str("#GET^http://foo.bar\n#Foo: Bar\n#Bar: Baz\n\n").unwrap();
+ let output = BarbOutput::quiet();
+ let req = executor.make_req(
+ &bfile,
+ vec![(String::from("Foo"), String::from("Qux"))],
+ &output,
+ );
+
+ let mut header_names = req.header_names();
+ header_names.sort();
+
+ assert_eq!(header_names, vec![String::from("bar"), String::from("foo")]);
+ assert_eq!(req.header("foo"), Some("Qux"));
+ assert_eq!(req.header("bar"), Some("Baz"));
+ }
}
diff --git a/src/main.rs b/src/main.rs
index 151b277..6ebfc45 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,8 @@ struct Args {
no_color: bool,
#[clap(short = 'F', long)]
no_filter: bool,
+ #[clap(long)]
+ hdr: Vec<String>,
files: Vec<String>,
}
@@ -42,6 +44,18 @@ impl Args {
self.no_filter
}
+ pub fn hdrs(&self) -> Vec<(String, String)> {
+ self.hdr
+ .iter()
+ .map(|x| x.split_once('='))
+ .filter(|x| x.is_some())
+ .map(|x| {
+ let (def, val) = x.unwrap();
+ (String::from(def), String::from(val))
+ })
+ .collect::<Vec<(String, String)>>()
+ }
+
pub fn output(&self) -> BarbOutput {
BarbOutput::new(
!self.body,
@@ -65,32 +79,32 @@ fn main() {
let mut executor = Executor::new(Context::new(env::vars()));
let output = args.output();
- let files: Vec<Result<BarbFile, String>> = args.files_iter()
- .map(read_file_barb)
- .collect();
+ let files: Vec<Result<BarbFile, String>> = args.files_iter().map(read_file_barb).collect();
- let (maybe_deps, errors): (Vec<Result<BarbFile, String>>, Vec<Result<BarbFile, String>>) = files.iter()
- .map(|x| match x.as_ref().ok() {
- Some(bfile) => bfile.dependency(),
- None => None
- })
- .filter(|x| x.is_some())
- .map(|x| read_file_barb(&String::from(x.unwrap())))
- .partition(|x| x.is_ok());
+ let (maybe_deps, errors): (Vec<Result<BarbFile, String>>, Vec<Result<BarbFile, String>>) =
+ files
+ .iter()
+ .map(|x| match x.as_ref().ok() {
+ Some(bfile) => bfile.dependency(),
+ None => None,
+ })
+ .filter(|x| x.is_some())
+ .map(|x| read_file_barb(&String::from(x.unwrap())))
+ .partition(|x| x.is_ok());
for e in errors {
println!("{}", e.err().unwrap());
}
- let mut dependencies = maybe_deps.iter()
+ let mut dependencies = maybe_deps
+ .iter()
.map(|x| x.as_ref().unwrap())
.collect::<Vec<&BarbFile>>();
dependencies.sort();
dependencies.dedup();
for dep in dependencies {
- // Always enable filters on dependencies
- match executor.execute(&dep, &output, args.jq_filter(), false) {
+ match executor.execute_dep(&dep, &output) {
Ok(()) => (),
Err(err) => println!("{}", err),
}
@@ -101,8 +115,14 @@ fn main() {
println!("{}", e);
continue;
}
-
- match executor.execute(&bfile.unwrap(), &output, args.jq_filter(), args.no_filter()) {
+
+ match executor.execute(
+ &bfile.unwrap(),
+ &output,
+ args.jq_filter(),
+ args.no_filter(),
+ args.hdrs(),
+ ) {
Ok(()) => (),
Err(err) => println!("{}", err),
}
diff --git a/src/output.rs b/src/output.rs
index d7ab74e..0f0e4a9 100644
--- a/src/output.rs
+++ b/src/output.rs
@@ -39,6 +39,45 @@ impl BarbOutput {
}
}
+ #[cfg(test)]
+ pub fn quiet() -> BarbOutput {
+ BarbOutput {
+ request: false,
+ req_headers: false,
+ headers: false,
+ body: false,
+ raw_body: false,
+ color: false,
+ }
+ }
+
+ pub fn req_dep(&self, method: String, url: String, code: u16, text: &str) {
+ if !self.request {
+ return;
+ }
+ if self.color {
+ if code >= 400 {
+ println!(
+ "{} {} {} {}",
+ code.to_string().red(),
+ text.red(),
+ method.red(),
+ url.red()
+ );
+ } else {
+ println!(
+ "{} {} {} {}",
+ code.to_string().green(),
+ text,
+ method.purple(),
+ url.purple()
+ );
+ }
+ } else {
+ println!("{} {} {} {}", code, text, method, url);
+ }
+ }
+
pub fn req(&self, method: String, url: String) {
if !self.request {
return;