use crate::{Pakige, PakigeParseError, VerOp};
use std::collections::{HashMap, VecDeque};
use std::hash::Hash;
use std::str::FromStr;
use deb_version7::DebVersion;
use regex::Regex;
mod setters;
use setters::{set_package, set_source, set_version, set_section, set_priority,
set_architecture, set_essential, set_depends, set_recommends,
set_suggests, set_enhances, set_pre_depends, set_breaks, set_conflicts,
set_provides, set_replaces, set_installed_size, set_maintainer,
set_description, set_homepage, set_built_using, set_multi_arch};
pub struct BinaryDeb
{
pub package: String,
pub source: Option<String>,
pub version: DebVersion,
pub section: Option<String>,
pub priority: Option<String>,
pub architecture: String,
pub essential: bool,
pub depends: Option<DependsPackageList>,
pub recommends: Option<DependsPackageList>,
pub suggests: Option<DependsPackageList>,
pub enhances: Option<DependsPackageList>,
pub pre_depends: Option<DependsPackageList>,
pub breaks: Option<ProvidesPackageList>,
pub conflicts: Option<ProvidesPackageList>,
pub provides: Option<ProvidesPackageList>,
pub replaces: Option<ProvidesPackageList>,
pub installed_size: Option<u64>,
pub maintainer: String,
pub description: String,
pub homepage: Option<String>,
pub built_using: Option<ProvidesPackageList>,
pub multi_arch: MultiArch,
pub all_fields: Fields
}
fn str_to_table (data: &str) -> Result<Fields,PakigeParseError>
{
let normal_line = Regex::new(r"^[[:space:]]*([[!-9--#---][;-~]][[!-9][;-~]]*)[[:space:]]*:[[:space:]]*(.*)[[:space:]]*$").unwrap();
let continuation = Regex::new(r"^( .*)$").unwrap();
let mut lines: VecDeque<&str> = data.trim().lines().collect();
let mut fields: Fields = HashMap::new();
while let Some(line) = lines.pop_front()
{
if let Some(captures) = normal_line.captures(line)
{
let key = captures.get(1)
.ok_or(PakigeParseError::InvalidFormat)?
.as_str()
.to_lowercase(); let value = captures.get(2)
.ok_or(PakigeParseError::InvalidFormat)?
.as_str();
if fields.contains_key(&key)
{
return Err(PakigeParseError::DuplicateField);
}
let mut field_data = String::from(value);
while let Some(next_line) = lines.pop_front()
{
if let Some(capture_append) = continuation.captures(next_line)
{
let to_append = capture_append.get(1)
.ok_or(PakigeParseError::InvalidFormat)?
.as_str();
field_data.push('\n'); field_data.push_str(to_append);
}
else
{
lines.push_front(next_line); break;
}
}
fields.insert(key, field_data);
}
else
{
return Err(PakigeParseError::InvalidFormat);
}
}
if fields.is_empty()
{
return Err(PakigeParseError::EmptyInput);
}
return Ok(fields);
}
type Fields = HashMap<String, String>;
impl FromStr for BinaryDeb
{
type Err = PakigeParseError;
fn from_str (data: &str) -> Result<Self, Self::Err>
{
let mut fields = str_to_table(data)?;
let mut deb = BinaryDeb {
package: set_package (&fields)?.ok_or (PakigeParseError::MissingMandatoryField)?,
source: set_source (&fields)?,
version: set_version (&fields)?.ok_or (PakigeParseError::MissingMandatoryField)?,
section: set_section (&fields)?,
priority: set_priority (&fields)?,
architecture: set_architecture (&fields)?.ok_or (PakigeParseError::MissingMandatoryField)?,
essential: set_essential (&fields)?.unwrap_or (false), depends: set_depends (&fields)?,
recommends: set_recommends (&fields)?,
suggests: set_suggests (&fields)?,
enhances: set_enhances (&fields)?,
pre_depends: set_pre_depends (&fields)?,
breaks: set_breaks (&fields)?,
conflicts: set_conflicts (&fields)?,
provides: set_provides (&fields)?,
replaces: set_replaces (&fields)?,
installed_size: set_installed_size (&fields)?,
maintainer: set_maintainer (&fields)?.ok_or (PakigeParseError::MissingMandatoryField)?,
description: set_description (&fields)?.ok_or (PakigeParseError::MissingMandatoryField)?,
homepage: set_homepage (&fields)?,
built_using: set_built_using (&fields)?,
multi_arch: set_multi_arch (&fields)?.unwrap_or (MultiArch::No), all_fields: fields,
};
Ok(deb)
}
}
pub struct BinaryIndexFields
{
filename: String,
size: u64,
md5sum: Option<String>,
sha1: Option<String>,
sha256: Option<String>,
sha512: Option<String>,
desc_md5: Option<String>
}
pub struct PackageIndex(Vec<(BinaryDeb, BinaryIndexFields)>);
pub struct PackageRef
{
package: String,
architecture: Option<String>,
version: Option<VersionRef>
}
pub struct VersionRef
{
operation: VerOp,
version_string: DebVersion
}
pub struct DependsPackageList(Vec<Vec<PackageRef>>);
pub struct ProvidesPackageList(Vec<PackageRef>);
#[derive(Clone, Copy)]
pub enum MultiArch
{
No,
Same,
Foreign,
Allowed
}
impl Default for MultiArch
{
fn default() -> Self
{
MultiArch::No
}
}