From: Ian Jackson Date: Sat, 26 Sep 2020 15:53:14 +0000 (+0100) Subject: library loading, compiles X-Git-Tag: otter-0.2.0~910 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=e1314bcff89165c3ab00a5f0b04a84df310017c9;p=otter.git library loading, compiles Signed-off-by: Ian Jackson --- diff --git a/src/bin/daemon-otter.rs b/src/bin/daemon-otter.rs index 267a2ed7..a3fee207 100644 --- a/src/bin/daemon-otter.rs +++ b/src/bin/daemon-otter.rs @@ -91,6 +91,8 @@ fn main() { .with_context(||bundled_sources.clone()) .context("check bundled-sources directory's index.html")?; + shapelib::load()?; + load_games()?; let cl = CommandListener::new()?; diff --git a/src/bin/otterlib.rs b/src/bin/otterlib.rs index 84b4dfcc..3a873481 100644 --- a/src/bin/otterlib.rs +++ b/src/bin/otterlib.rs @@ -2,6 +2,13 @@ pub use otter::imports::*; #[throws(anyhow::Error)] fn main(){ - let f = env::args().nth(1).unwrap(); - shapelib::load(f.clone(),f)?; + let mut a = env::args(); + a.next().unwrap(); + let name = a.next().unwrap(); + let dirname = a.next().unwrap(); + let catalogue = format!("{}.toml", &dirname); + let e = shapelib::Explicit1 { + name, dirname, catalogue + }; + shapelib::load1(&e).unwrap(); } diff --git a/src/global.rs b/src/global.rs index 7bad84cf..a296d2db 100644 --- a/src/global.rs +++ b/src/global.rs @@ -978,6 +978,7 @@ const DEFAULT_CONFIG_FILENAME : &str = "server.toml"; const DEFAULT_SAVE_DIRECTORY : &str = "save"; const DEFAULT_COMMAND_SOCKET : &str = "command.socket"; // in save dir const DEFAULT_TEMPLATE_DIR : &str = "templates"; +const DEFAULT_LIBRARY_DIR : &str = "library"; #[derive(Deserialize,Debug,Clone)] pub struct ServerConfigSpec { @@ -989,6 +990,7 @@ pub struct ServerConfigSpec { pub template_dir: Option, pub log: Option, pub bundled_sources: Option, + pub shapelibs: Option>, } #[derive(Debug,Clone)] @@ -1001,6 +1003,7 @@ pub struct ServerConfig { pub template_dir: String, pub log: LogSpecification, pub bundled_sources: String, + pub shapelibs: Vec, } impl TryFrom for ServerConfig { @@ -1010,6 +1013,7 @@ impl TryFrom for ServerConfig { let ServerConfigSpec { save_directory, command_socket, debug, http_port, rocket_workers, template_dir, log, bundled_sources, + shapelibs, } = spec; let save_directory = save_directory @@ -1046,9 +1050,15 @@ impl TryFrom for ServerConfig { let bundled_sources = bundled_sources .unwrap_or_else(|| save_directory.clone()); + let shapelibs = shapelibs.unwrap_or_else( + ||vec![ shapelib::Config1::PathGlob( + format!("{}/*.toml", DEFAULT_LIBRARY_DIR) + )]); + ServerConfig { save_directory, command_socket, debug, http_port, rocket_workers, template_dir, log, bundled_sources, + shapelibs, } } } diff --git a/src/shapelib.rs b/src/shapelib.rs index c244cf70..7e606c21 100644 --- a/src/shapelib.rs +++ b/src/shapelib.rs @@ -19,18 +19,18 @@ pub struct Contents { #[derive(Debug,Clone)] #[derive(Serialize,Deserialize)] -pub struct ItemDetails { +struct ItemDetails { desc: Html, } #[derive(Debug,Clone)] -pub struct ItemData { +struct ItemData { d: Arc, group: Arc, } #[derive(Debug,Deserialize)] -pub struct GroupDetails { +struct GroupDetails { size: Vec, category: String, #[serde(default)] centre: [f64; 2], @@ -40,7 +40,7 @@ pub struct GroupDetails { } #[derive(Debug)] -pub struct GroupData { +struct GroupData { groupname: String, d: GroupDetails, } @@ -76,8 +76,16 @@ trait OutlineDefn : Debug + Sync + Send { pub enum LibraryLoadError{ #[error(transparent)] TomlParseError(#[from] toml::de::Error), - #[error("error reading/opening library file: {0}")] - FileError(#[from] io::Error), + #[error("error reading/opening library file: {0}: {1}")] + FileError(String, io::Error), + #[error("OS error globbing for files: {0}")] + GlobFileError(#[from] glob::GlobError), + #[error("bad glob pattern: {pat:?} (near char {pos}): {msg}")] + BadGlobPattern { pat: String, msg: &'static str, pos: usize }, + #[error("glob pattern {pat:?} matched non-utf-8 filename {actual:?}")] + GlobNonUTF8 { pat: String, actual: PathBuf }, + #[error("glob pattern {pat:?} matched filename with no extension {path:?}")] + GlobNoExtension { pat: String, path: String }, #[error("{:?}",&self)] ExpectedTable(String), #[error("{:?}",&self)] @@ -107,7 +115,7 @@ type TV = toml::Value; type SE = SpecError; #[derive(Debug,Serialize,Deserialize)] -pub struct ItemSpec { +struct ItemSpec { lib: String, item: String, } @@ -235,16 +243,16 @@ fn resolve_inherit<'r>(depth: u8, groups: &toml::value::Table, } #[throws(LibraryLoadError)] -fn load_catalogue(dirname: String) -> Contents { - let toml_path = format!("{}.toml", &dirname); - let f = File::open(toml_path)?; +fn load_catalogue(dirname: &str, toml_path: &str) -> Contents { + let ioe = |io| LLE::FileError(toml_path.to_string(), io); + let f = File::open(toml_path).map_err(ioe)?; let mut f = BufReader::new(f); let mut s = String::new(); - f.read_to_string(&mut s).unwrap(); + f.read_to_string(&mut s).map_err(ioe)?; let toplevel : toml::Value = s.parse()?; let mut l = Contents { items: HashMap::new(), - dirname, + dirname: dirname.to_string(), }; let empty_table = toml::value::Value::Table(Default::default()); let groups = @@ -281,12 +289,82 @@ fn load_catalogue(dirname: String) -> Contents { l } +#[derive(Deserialize,Debug,Clone)] +#[serde(untagged)] +pub enum Config1 { + PathGlob(String), + Explicit(Explicit1), +} + +#[derive(Deserialize,Debug,Clone)] +pub struct Explicit1 { + pub name: String, + pub catalogue: String, + pub dirname: String, +} + +#[throws(LibraryLoadError)] +pub fn load1(l: &Explicit1) { + let data = load_catalogue(&l.dirname, &l.catalogue)?; + GLOBAL.shapelibs.write().unwrap().insert(l.name.clone(), data); + info!("loaded library {:?} from {:?} and {:?}", + &l.name, &l.catalogue, &l.dirname); +} + +impl Config1 { + fn resolve(&self) -> Result>, LibraryLoadError> { + use Config1::*; + Ok(match self { + Explicit(e) => Box::new(iter::once(e.clone())), + PathGlob(pat) => { + + #[throws(LLE)] + fn resolve_globresult(pat: &str, globresult: glob::GlobResult) + -> Explicit1 { + let path = globresult?; + let path = path.to_str().ok_or_else( + || LLE::GlobNonUTF8 + { pat: pat.to_string(), actual: path.clone() })? + .to_string(); + + let dirname = path.rsplitn(2,'.').nth(1).ok_or_else( + || LLE::GlobNoExtension + { pat: pat.to_string(), path: path.clone() })?; + + let base = dirname.rsplit('/').next().unwrap(); + + Explicit1 { + name: base.to_string(), + dirname: dirname.to_string(), + catalogue: path, + } + }; + + let results = glob::glob_with(pat, glob::MatchOptions { + require_literal_separator: true, + require_literal_leading_dot: true, + .. Default::default() + }) + .map_err( + |glob::PatternError { pos, msg, .. }| + LLE::BadGlobPattern { pat: pat.clone(), pos, msg } + )? + .map(|globresult| resolve_globresult(pat, globresult)) + .collect::, LLE>>()?; + + Box::new(results.into_iter()) + }, + }) + } +} + #[throws(LibraryLoadError)] -pub fn load(libname: String, dirname: String) { - let data = load_catalogue(dirname.clone())?; - dbg!(&data); - GLOBAL.shapelibs.write().unwrap().insert(libname.clone(), data); - info!("loaded library {:?} from {:?}", libname, dirname); +pub fn load() { + for l in &config().shapelibs { + for e in l.resolve()? { + load1(&e)?; + } + } } #[derive(Serialize,Deserialize,Debug)]