#![deny(missing_debug_implementations)]
#![forbid(unsafe_code)]
extern crate amxml;
extern crate chrono;
extern crate curl;
extern crate phf_codegen;
pub use error::Error;
use std::env;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};
use amxml::dom::new_document;
use curl::easy::Easy;
use generate::CategoryMap;
mod error;
mod generate;
const SPEC_URL: &str = "https://specifications.freedesktop.org/menu-spec/";
#[derive(Debug)]
pub enum Version {
V090,
V091,
V092,
V100,
V110,
Latest,
}
impl Display for Version {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
match *self {
Version::V090 => write!(fmt, "0.9"),
Version::V091 => write!(fmt, "0.91"),
Version::V092 => write!(fmt, "0.92"),
Version::V100 => write!(fmt, "1.0"),
Version::V110 => write!(fmt, "1.1"),
Version::Latest => write!(fmt, "latest"),
}
}
}
#[derive(Debug)]
pub struct DesktopMenuSpec {
xml_cache_dir: Option<PathBuf>,
always_download: bool,
output_name: &'static str,
version: Version,
}
impl DesktopMenuSpec {
pub fn new() -> Self {
DesktopMenuSpec {
xml_cache_dir: None,
always_download: false,
output_name: "map.rs",
version: Version::Latest,
}
}
pub fn xml_cache_dir<P: Into<PathBuf>>(&mut self, path: P) -> &mut Self {
self.xml_cache_dir = Some(path.into());
self
}
pub fn always_download(&mut self, value: bool) -> &mut Self {
self.always_download = value;
self
}
pub fn output_file_name(&mut self, name: &'static str) -> &mut Self {
self.output_name = name;
self
}
pub fn version(&mut self, ver: Version) -> &mut Self {
self.version = ver;
self
}
pub fn gen_static_map(&self) -> Result<(), Error> {
let cache_dir = self
.xml_cache_dir
.clone()
.unwrap_or(env::var("OUT_DIR")?.into());
let xml = fetch_or_download(&self.version, &cache_dir, self.always_download)?
.replace("&version", "version")
.replace("&dtd-version", "dtd-version");
let doc = new_document(&xml)?;
let root = doc.root_element();
let map = CategoryMap::generate(&root)?;
let out = Path::new(&env::var("OUT_DIR")?).join(self.output_name);
map.write_file(&out)?;
Ok(())
}
}
fn fetch_or_download(
ver: &Version,
out_dir: &Path,
always_download: bool,
) -> Result<String, Error> {
let file_name = format!("menu-spec-{}.xml", ver);
let path = Path::new(&out_dir).join(&file_name);
if !path.exists() || always_download {
let mut file = File::create(&path)?;
let mut handle = Easy::new();
handle.url(&format!("{}/{}", SPEC_URL, file_name))?;
let mut transfer = handle.transfer();
transfer.write_function(|data| {
file.write(data)
.expect("Unable to write received data to file");
Ok(data.len())
})?;
transfer.perform()?;
}
fs::read_to_string(&path).map_err(|e| e.into())
}