doku2dot/src/main.rs
Yannik 9a3d948cbf error-handling, more parsing, dir parsing
hab das error-handling vereinfacht, es panict jetzt sofort sobald ein
fehler gefunden wurde, anstatt die fehler zurückzugeben. ratio ist, dass
die fehler eh nicht behandelt werden können, und sonst nur weiter oben
im call-stack zum abbruch geführt hätten.

parst jetzt ein bischen mehr attribute, es ist im code einstellbar beim
fehlen welcher attribute gepanict werden soll und bei welchen nur eine
zeile auf stderr gesetzt werden soll; schreibt bei fehlenden attributen
jetzt eine warnung auf stderr.

kann jetzt auch die in verzeichnisse aufgeteilten einträge verarbeiten
2017-11-17 17:35:00 +01:00

149 lines
4.4 KiB
Rust

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;
use std::path::Path;
mod parsing;
fn main() {
//read the files
//let paths = [Path::new("test.yml")];
let filenames: Vec<_> = std::env::args_os().skip(1).collect();
let hosts: Vec<Host> = filenames.iter()
.map(Path::new)
.map(|path| Host::from_file(&path))
.collect();
//build dot-graph
let nodes = hosts.iter().map(Host::to_dot_node);
let edges = hosts.iter().flat_map(Host::to_dot_edge);
//render it
println!("graph antennen {{");
for node in nodes {
println!("{}", node);
}
for edge in edges {
println!("{}", edge);
}
println!("}}");
}
#[derive(Debug)]
pub struct Host {
name: String,
ip: String,
kind: HostKind,
}
impl Host {
fn from_file(path: &Path) -> Self {
let (host, hostname) = parsing::RawHost::from_file(path);
host.parse(hostname)
}
fn to_dot_node(&self) -> String {
let mut attributes = vec!
[ "shape=record".to_string()
, "style=filled".into()
];
let record;
// type-specific handling
use HostKind::*;
match self.kind {
Client {coordinates, ref subnet, ref mac, .. } =>
{ attributes.push("fillcolor=lightgray".into())
; if let Some(coordinates) = coordinates
{ attributes.push(format!("pos=\"{breitengrad},{längengrad}\""
, längengrad=coordinates[0], breitengrad=coordinates[1]))
}
; record =
( self.name.clone()
, (self.kind.name(), mac.clone())
, (self.ip.clone(), subnet.clone())
, ("no ipv6", "no 6-subnet")
).recordify()
},
AccessPoint { ref mac, .. } => record =
( self.name.clone()
, (self.kind.name(), mac.clone() )
, self.ip.clone()
).recordify(),
_ => record = (self.name.clone(), self.kind.name(), self.ip.clone()).recordify(),
};
attributes.push(format!("label=\"{}\"", record));
let attributes = attributes.join(", ");
format!("\"{name}\" [{attributes}]", name=self.name, attributes=attributes)
}
fn to_dot_edge(&self) -> Option<String> {
match self.kind {
HostKind::Client { ref parent, ref ssid, .. } =>
format!("\"{name}\" -- \"{parent}\" [label=\"{ssid}\"]", name=self.name, parent=parent, ssid=ssid).into(),
HostKind::AccessPoint { ref parent, .. } =>
format!("\"{name}\" -- \"{parent}\"", name=self.name, parent=parent).into(),
_ => None,
}
}
}
#[derive(Debug)]
enum HostKind {
Client { mac: String, subnet: String, coordinates: Option<[f64;2]>, parent: String, ssid: String },
AccessPoint { mac: String, ssid: String, parent: String },
Service,
Other,
}
impl HostKind {
fn name(&self) -> &'static str {
use HostKind::*;
match *self {
Client { .. } => "Client",
AccessPoint { .. } => "AccessPoint",
Service => "Service",
Other => "Other",
}
}
}
/** dieser Trait ermöglicht es verschachtelte tupel in ein label für einen record-shaped-node für
dotfiles umzuwandeln. inputwerte werden nicht escaped
assert_eq!(
("a", ("b", "c", "d"), ("e","f"), "g").recordify(),
"{a|{b|c|d}|{e|f}|g}".into())
*/
pub trait DotRecord {
fn recordify(self) -> String;
}
impl DotRecord for String {
fn recordify(self) -> String { self }
}
impl<'a> DotRecord for &'a str {
fn recordify(self) -> String { self.into() }
}
impl<A: DotRecord, B: DotRecord> DotRecord for (A,B) {
fn recordify(self) -> String {
format!("{{{}|{}}}", self.0.recordify(), self.1.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord> DotRecord for (A,B,C) {
fn recordify(self) -> String {
format!("{{{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord> DotRecord for (A,B,C,D) {
fn recordify(self) -> String {
format!("{{{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord, E: DotRecord> DotRecord for (A,B,C,D,E) {
fn recordify(self) -> String {
format!("{{{}|{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify(), self.4.recordify())
}
}