rust/lockfile: Add YAML support

Fixes #1904

Signed-off-by: Rafael Fonseca <r4f4rfs@gmail.com>
This commit is contained in:
Rafael Fonseca 2019-09-27 13:59:31 +02:00 committed by OpenShift Merge Robot
parent 75a2f8bb33
commit 6dab08b646
3 changed files with 66 additions and 42 deletions

View File

@ -18,23 +18,39 @@ use std::io;
use crate::utils;
/// Parse a JSON lockfile definition.
fn lockfile_parse_stream<R: io::Read>(input: &mut R,) -> Fallible<LockfileConfig> {
let lockfile: LockfileConfig = serde_json::from_reader(input).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("serde-json: {}", e.to_string()),
)
})?;
fn lockfile_parse_stream<R: io::Read>(
fmt: utils::InputFormat,
input: &mut R,
) -> Fallible<LockfileConfig> {
let lockfile: LockfileConfig = match fmt {
utils::InputFormat::JSON => {
let lf: LockfileConfig = serde_json::from_reader(input).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("serde-json: {}", e.to_string()),
)
})?;
lf
}
utils::InputFormat::YAML => {
let lf: LockfileConfig = serde_yaml::from_reader(input).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("serde-yaml: {}", e.to_string()),
)
})?;
lf
}
};
Ok(lockfile)
}
/// Given a lockfile filename, parse it
fn lockfile_parse<P: AsRef<Path>>(filename: P,) -> Fallible<LockfileConfig> {
let filename = filename.as_ref();
let fmt = utils::InputFormat::detect_from_filename(filename)?;
let mut f = io::BufReader::new(utils::open_file(filename)?);
filename.file_name().map(|s| s.to_string_lossy()).ok_or_else(
|| io::Error::new(io::ErrorKind::InvalidInput, "Expected a filename"))?;
let lf = lockfile_parse_stream(&mut f).map_err(|e| {
let lf = lockfile_parse_stream(fmt, &mut f).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Parsing {}: {}", filename.to_string_lossy(), e.to_string()),
@ -126,7 +142,7 @@ mod tests {
#[test]
fn basic_valid() {
let mut input = io::BufReader::new(VALID_PRELUDE_JS.as_bytes());
let lockfile = lockfile_parse_stream(&mut input).unwrap();
let lockfile = lockfile_parse_stream(utils::InputFormat::JSON, &mut input).unwrap();
assert!(lockfile.packages.len() == 2);
}
@ -144,11 +160,11 @@ mod tests {
#[test]
fn basic_valid_override() {
let mut base_input = io::BufReader::new(VALID_PRELUDE_JS.as_bytes());
let mut base_lockfile = lockfile_parse_stream(&mut base_input).unwrap();
let mut base_lockfile = lockfile_parse_stream(utils::InputFormat::JSON, &mut base_input).unwrap();
assert!(base_lockfile.packages.len() == 2);
let mut override_input = io::BufReader::new(OVERRIDE_JS.as_bytes());
let override_lockfile = lockfile_parse_stream(&mut override_input).unwrap();
let override_lockfile = lockfile_parse_stream(utils::InputFormat::JSON, &mut override_input).unwrap();
assert!(override_lockfile.packages.len() == 1);
base_lockfile.merge(override_lockfile);
@ -160,7 +176,7 @@ mod tests {
#[test]
fn test_invalid() {
let mut input = io::BufReader::new(INVALID_PRELUDE_JS.as_bytes());
match lockfile_parse_stream(&mut input) {
match lockfile_parse_stream(utils::InputFormat::JSON, &mut input) {
Err(ref e) => match e.downcast_ref::<io::Error>() {
Some(ref ioe) if ioe.kind() == io::ErrorKind::InvalidInput => {}
_ => panic!("Expected invalid lockfile, not {}", e.to_string()),

View File

@ -56,21 +56,15 @@ struct ConfigAndExternals {
externals: TreefileExternals,
}
#[derive(PartialEq)]
enum InputFormat {
YAML,
JSON,
}
/// Parse a YAML treefile definition using base architecture `basearch`.
/// This does not open the externals.
fn treefile_parse_stream<R: io::Read>(
fmt: InputFormat,
fmt: utils::InputFormat,
input: &mut R,
basearch: Option<&str>,
) -> Fallible<TreeComposeConfig> {
let mut treefile: TreeComposeConfig = match fmt {
InputFormat::YAML => {
utils::InputFormat::YAML => {
let tf: TreeComposeConfig = serde_yaml::from_reader(input).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
@ -79,7 +73,7 @@ fn treefile_parse_stream<R: io::Read>(
})?;
tf
}
InputFormat::JSON => {
utils::InputFormat::JSON => {
let tf: TreeComposeConfig = serde_json::from_reader(input).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
@ -113,7 +107,7 @@ fn treefile_parse_stream<R: io::Read>(
// remove from packages-${arch} keys from the extra keys
let mut archful_pkgs: Option<Vec<String>> = take_archful_pkgs(basearch, &mut treefile)?;
if fmt == InputFormat::YAML && !treefile.extra.is_empty() {
if fmt == utils::InputFormat::YAML && !treefile.extra.is_empty() {
let keys: Vec<&str> = treefile.extra.keys().map(|k| k.as_str()).collect();
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
@ -225,15 +219,7 @@ fn treefile_parse<P: AsRef<Path>>(
}
};
let mut f = io::BufReader::new(f);
let basename = filename
.file_name()
.map(|s| s.to_string_lossy())
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Expected a filename"))?;
let fmt = if basename.ends_with(".yaml") || basename.ends_with(".yml") {
InputFormat::YAML
} else {
InputFormat::JSON
};
let fmt = utils::InputFormat::detect_from_filename(filename)?;
let tf = treefile_parse_stream(fmt, &mut f, basearch).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
@ -887,7 +873,7 @@ packages-s390x:
fn basic_valid() {
let mut input = io::BufReader::new(VALID_PRELUDE.as_bytes());
let mut treefile =
treefile_parse_stream(InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile = treefile.substitute_vars().unwrap();
assert!(treefile.treeref.unwrap() == "exampleos/x86_64/blah");
assert!(treefile.packages.unwrap().len() == 5);
@ -911,7 +897,7 @@ remove-files:
let buf = buf.as_bytes();
let mut input = io::BufReader::new(buf);
let treefile =
treefile_parse_stream(InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
assert!(treefile.add_files.unwrap().len() == 2);
assert!(treefile.remove_files.unwrap().len() == 2);
}
@ -920,7 +906,7 @@ remove-files:
fn basic_js_valid() {
let mut input = io::BufReader::new(VALID_PRELUDE_JS.as_bytes());
let mut treefile =
treefile_parse_stream(InputFormat::JSON, &mut input, Some(ARCH_X86_64)).unwrap();
treefile_parse_stream(utils::InputFormat::JSON, &mut input, Some(ARCH_X86_64)).unwrap();
treefile = treefile.substitute_vars().unwrap();
assert!(treefile.treeref.unwrap() == "exampleos/x86_64/blah");
assert!(treefile.packages.unwrap().len() == 5);
@ -929,7 +915,7 @@ remove-files:
#[test]
fn basic_valid_noarch() {
let mut input = io::BufReader::new(VALID_PRELUDE.as_bytes());
let mut treefile = treefile_parse_stream(InputFormat::YAML, &mut input, None).unwrap();
let mut treefile = treefile_parse_stream(utils::InputFormat::YAML, &mut input, None).unwrap();
treefile = treefile.substitute_vars().unwrap();
assert!(treefile.treeref.unwrap() == "exampleos/x86_64/blah");
assert!(treefile.packages.unwrap().len() == 3);
@ -939,14 +925,14 @@ remove-files:
let buf = VALID_PRELUDE.to_string() + append;
let mut input = io::BufReader::new(buf.as_bytes());
let treefile =
treefile_parse_stream(InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile.substitute_vars().unwrap()
}
fn test_invalid(data: &'static str) {
let buf = VALID_PRELUDE.to_string() + data;
let mut input = io::BufReader::new(buf.as_bytes());
match treefile_parse_stream(InputFormat::YAML, &mut input, Some(ARCH_X86_64)) {
match treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)) {
Err(ref e) => match e.downcast_ref::<io::Error>() {
Some(ref ioe) if ioe.kind() == io::ErrorKind::InvalidInput => {}
_ => panic!("Expected invalid treefile, not {}", e.to_string()),
@ -965,7 +951,7 @@ mutate-os-release: ${releasever}
"###;
let mut input = io::BufReader::new(buf.as_bytes());
let mut treefile =
treefile_parse_stream(InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap();
treefile = treefile.substitute_vars().unwrap();
assert!(treefile.treeref.unwrap() == "exampleos/x86_64/30");
assert!(treefile.releasever.unwrap() == "30");
@ -1173,9 +1159,9 @@ etc-group-members:
"###
.as_bytes(),
);
let mut mid = treefile_parse_stream(InputFormat::YAML, &mut mid_input, basearch).unwrap();
let mut mid = treefile_parse_stream(utils::InputFormat::YAML, &mut mid_input, basearch).unwrap();
let mut top_input = io::BufReader::new(ROJIG_YAML.as_bytes());
let mut top = treefile_parse_stream(InputFormat::YAML, &mut top_input, basearch).unwrap();
let mut top = treefile_parse_stream(utils::InputFormat::YAML, &mut top_input, basearch).unwrap();
assert!(top.add_commit_metadata.is_none());
treefile_merge(&mut mid, &mut base);
treefile_merge(&mut top, &mut mid);

View File

@ -14,6 +14,28 @@ use tempfile;
use curl::easy::Easy;
#[derive(PartialEq)]
/// Supported config serialization used by treefile and lockfile
pub enum InputFormat {
YAML,
JSON,
}
impl InputFormat {
pub fn detect_from_filename<P: AsRef<Path>>(filename: P) -> Fallible<Self> {
let filename = filename.as_ref();
let basename = filename
.file_name()
.map(|s| s.to_string_lossy())
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Expected a filename"))?;
if basename.ends_with(".yaml") || basename.ends_with(".yml") {
Ok(Self::YAML)
} else {
Ok(Self::JSON)
}
}
}
fn download_url_to_tmpfile(url: &str) -> Fallible<fs::File> {
let mut tmpf = tempfile::tempfile()?;
{