#!/usr/bin/env rdmd module doc_reform.sisu_document_parser; import doc_reform.conf.compile_time_info, doc_reform.meta.metadoc; import std.getopt, std.file, std.path, std.process; import doc_reform.meta, doc_reform.meta.metadoc_summary, doc_reform.meta.metadoc_from_src, doc_reform.meta.conf_make_meta_structs, doc_reform.meta.conf_make_meta_toml, doc_reform.meta.conf_make_meta_json, doc_reform.meta.defaults, doc_reform.meta.doc_debugs, doc_reform.meta.rgx, doc_reform.source.paths_source, doc_reform.source.read_config_files, doc_reform.source.read_source_files, doc_reform.output.hub; import std.algorithm; import std.parallelism; mixin(import("version.txt")); mixin CompileTimeInfo; /++ name "doc_reform" description "A SiSU inspired document parser writen in D." homepage "http://sisudoc.org" +/ void main(string[] args) { mixin DocReformRgxInit; mixin contentJSONtoDocReformStruct; mixin DocReformBiblio; mixin DocReformRgxInitFlags; mixin outputHub; string flag_action; string arg_unrecognized; enum dAM { abstraction, matters } static auto rgx = Rgx(); scope(success) { debug(checkdoc) { writefln( "~ run complete, ok ~ (doc_reform-%s.%s.%s, %s D:%s, %s %s)", ver.major, ver.minor, ver.patch, __VENDOR__, __VERSION__, bits, os, ); } } scope(failure) { debug(checkdoc) { stderr.writefln( "run failure", ); } } bool[string] opts = [ "abstraction" : false, "assertions" : false, "concordance" : false, "debug" : false, "digest" : false, "epub" : false, "html" : false, "html-seg" : false, "html-scroll" : false, "manifest" : false, "ocn" : true, "parallelise" : true, "parallelise-subprocesses" : false, "quiet" : false, "pod" : false, "source" : false, "sqlite-discrete" : false, "sqlite-db-create" : false, "sqlite-db-drop" : false, "sqlite-db-recreate" : false, "sqlite-delete" : false, "sqlite-insert" : false, "sqlite-update" : false, "text" : false, "verbose" : false, "very-verbose" : false, "xhtml" : false, "section_toc" : true, "section_body" : true, "section_endnotes" : true, "section_glossary" : true, "section_biblio" : true, "section_bookindex" : true, "section_blurb" : true, "backmatter" : true, "skip-output" : false, ]; string[string] settings = [ "output-dir" : "", "site-config-dir" : "", "lang" : "all", "sqlite-filename" : "documents", ]; auto helpInfo = getopt(args, std.getopt.config.passThrough, "abstraction", "--abstraction document abstraction ", &opts["abstraction"], "assert", "--assert set optional assertions on", &opts["assertions"], "concordance", "--concordance file for document", &opts["concordance"], "debug", "--debug", &opts["debug"], "digest", "--digest hash digest for each object", &opts["digest"], "epub", "--epub process epub output", &opts["epub"], "html", "--html process html output", &opts["html"], "html-seg", "--html-seg process html output", &opts["html-seg"], "html-scroll", "--html-seg process html output", &opts["html-scroll"], "manifest", "--manifest process manifest output", &opts["manifest"], "ocn", "--ocn object cite numbers (default)", &opts["ocn"], "parallelise", "--parallelise parallelisation", &opts["parallelise"], "parallelise-subprocesses", "--parallelise-subprocesses nested parallelisation", &opts["parallelise-subprocesses"], "quiet", "--quiet output to terminal", &opts["quiet"], "pod", "--pod doc reform pod source content bundled", &opts["pod"], "source", "--source markup source text content", &opts["source"], "sqlite-discrete", "--sqlite process discrete sqlite output", &opts["sqlite-discrete"], "sqlite-db-create", "--sqlite-db-create create db, create tables", &opts["sqlite-db-create"], "sqlite-db-drop", "--sqlite-db-drop drop tables & db", &opts["sqlite-db-drop"], "sqlite-db-recreate", "--sqlite-db-recreate create db, create tables", &opts["sqlite-db-recreate"], // "sqlite-db-populate", "--sqlite-db-populate create db & tables, insert specified", &opts["sqlite-db-populate"], "sqlite-delete", "--sqlite process sqlite output", &opts["sqlite-delete"], "sqlite-insert", "--sqlite process sqlite output", &opts["sqlite-insert"], "sqlite-update", "--sqlite process sqlite output", &opts["sqlite-update"], "text", "--text process text output", &opts["text"], "txt", "--txt process text output", &opts["text"], "verbose|v", "--verbose output to terminal", &opts["verbose"], "very-verbose", "--very-verbose output to terminal", &opts["very-verbose"], "xhtml", "--xhtml process xhtml output", &opts["xhtml"], "section-toc", "--section-toc process table of contents (default)", &opts["section_toc"], "section-body", "--section-body process document body (default)", &opts["section_body"], "section-endnotes", "--section-endnotes process document endnotes (default)", &opts["section_endnotes"], "section-glossary", "--section-glossary process document glossary (default)", &opts["section_glossary"], "section-biblio", "--section-biblio process document biblio (default)", &opts["section_biblio"], "section-bookindex", "--section-bookindex process document bookindex (default)", &opts["section_bookindex"], "section-blurb", "--section-blurb process document blurb (default)", &opts["section_blurb"], "backmatter", "--section-backmatter process document backmatter (default)", &opts["backmatter"], "skip-output", "--skip-output", &opts["skip-output"], "output-dir", "--output-dir=[dir path]", &settings["output-dir"], "site-config-dir", "--site-config-dir=[dir path]", &settings["site-config-dir"], "sqlite-filename", "--sqlite-filename=[filename].sqlite", &settings["sqlite-filename"], "lang", "--lang=[lang code e.g. =en or =en,es]", &settings["lang"], ); if (helpInfo.helpWanted) { defaultGetoptPrinter("Some information about the program.", helpInfo.options); } enum outTask { pod, source, sqlite, sqlite_multi, epub, html_scroll, html_seg, html_stuff } struct OptActions { auto assertions() { return opts["assertions"]; } auto concordance() { return opts["concordance"]; } auto debug_do() { return opts["debug"]; } auto digest() { return opts["digest"]; } auto epub() { return opts["epub"]; } auto html() { bool _is = ( opts["html"] || opts["html-seg"] || opts["html-scroll"] ) ? true : false; return _is; } auto html_seg() { bool _is = ( opts["html"] || opts["html-seg"] ) ? true : false; return _is; } auto html_scroll() { bool _is = ( opts["html"] || opts["html-scroll"] ) ? true : false; return _is; } auto html_stuff() { bool _is = ( opts["html"] || opts["html-scroll"] || opts["html-seg"] ) ? true : false; return _is; } auto manifest() { return opts["manifest"]; } auto ocn() { return opts["ocn"]; } auto quiet() { return opts["quiet"]; } auto pod() { return opts["pod"]; } auto source() { return opts["source"]; } auto sqlite_discrete() { return opts["sqlite-discrete"]; } auto sqlite_db_drop() { bool _is = ( opts["sqlite-db-recreate"] || opts["sqlite-db-drop"] ) ? true : false; return _is; } auto sqlite_db_create() { bool _is = ( opts["sqlite-db-recreate"] || opts["sqlite-db-create"] ) ? true : false; return _is; } auto sqlite_delete() { return opts["sqlite-delete"]; } auto sqlite_update() { bool _is = ( opts["sqlite-update"] || opts["sqlite-insert"] ) ? true : false; return _is; } auto sqlite_shared_db_action() { bool _is = ( opts["sqlite-db-recreate"] || opts["sqlite-db-create"] || opts["sqlite-delete"] || opts["sqlite-insert"] || opts["sqlite-update"] ) ? true : false; return _is; } auto text() { return opts["text"]; } auto verbose() { bool _is = ( opts["verbose"] || opts["very-verbose"] ) ? true : false; return _is; } auto very_verbose() { return opts["very-verbose"]; } auto xhtml() { return opts["xhtml"]; } auto section_toc() { return opts["section_toc"]; } auto section_body() { return opts["section_body"]; } auto section_endnotes() { return opts["section_endnotes"]; } auto section_glossary() { return opts["section_glossary"]; } auto section_biblio() { return opts["section_biblio"]; } auto section_bookindex() { return opts["section_bookindex"]; } auto section_blurb() { return opts["section_blurb"]; } auto backmatter() { return opts["backmatter"]; } auto skip_output() { return opts["skip-output"]; } auto languages_set() { return settings["lang"].split(","); } auto output_dir_set() { return settings["output-dir"]; } auto sqlite_filename() { return settings["sqlite-filename"]; } auto parallelise() { bool _is = ( opts["parallelise"]) ? true : false; _is = ( sqlite_shared_db_action ) ? false : true; return _is; } auto parallelise_subprocesses() { return opts["parallelise-subprocesses"]; } auto output_task_scheduler() { int[] schedule; if (pod) { schedule ~= outTask.pod; } if (source) { schedule ~= outTask.source; } if (sqlite_discrete) { schedule ~= outTask.sqlite; } if (epub) { schedule ~= outTask.epub; } if (html_scroll) { schedule ~= outTask.html_scroll; } if (html_seg) { schedule ~= outTask.html_seg; } if (html_stuff) { schedule ~= outTask.html_stuff; } return schedule.sort().uniq; } auto abstraction() { bool _is = ( opts["abstraction"] || concordance || epub || html || manifest || pod || source || sqlite_discrete || sqlite_delete || sqlite_update ) ? true : false; return _is; } } auto _opt_action = OptActions(); auto _env = [ "pwd" : environment["PWD"], "home" : environment["HOME"], ]; auto _manifest_start = PodManifest!()(""); auto _manifest_matter = PathMatters!()(_opt_action, _env, ""); auto _manifests = [ _manifest_matter ]; foreach(arg; args[1..$]) { _manifest_start = PodManifest!()(arg); if (arg.match(rgx.flag_action)) { flag_action ~= " " ~ arg; // flags not taken by getopt } else if ( !(arg.match(rgx.src_pth_sst_or_ssm)) && _manifest_start.pod_manifest_file_with_path && _opt_action.abstraction ) { string contents_location_raw_; string contents_location_; string sisudoc_txt_ = _manifest_start.pod_manifest_file_with_path; enforce( exists(sisudoc_txt_)!=0, "file not found: «" ~ sisudoc_txt_ ~ "»" ); if (exists(sisudoc_txt_)) { try { if (exists(sisudoc_txt_)) { contents_location_raw_ = sisudoc_txt_.readText; } } catch (ErrnoException ex) { } catch (FileException ex) { // Handle errors } if (contents_location_raw_.match(rgx.pod_content_location)) { // (file name followed by language codes \n)+ foreach (m; contents_location_raw_.matchAll(rgx.pod_content_location)) { foreach (n; m.captures[2].matchAll(rgx.language_codes)) { contents_location_ ~= "media/text/" ~ n.captures[1].to!string ~ "/" ~ m.captures[1].to!string ~ "\n"; } } } else { contents_location_ = contents_location_raw_; } } else { writeln("manifest not found: ", sisudoc_txt_); } auto contents_locations_arr = (cast(char[]) contents_location_).split; auto tmp_dir_ = (sisudoc_txt_).dirName.array; foreach (contents_location; contents_locations_arr) { assert(contents_location.match(rgx.src_pth_sst_or_ssm), "not a recognised file: «" ~ contents_location ~ "»" ); auto contents_location_pth_ = (contents_location).to!string; auto lang_rgx_ = regex(r"/(" ~ _opt_action.languages_set.join("|") ~ ")/"); if (_opt_action.languages_set[0] == "all" || (contents_location_pth_).match(lang_rgx_) ) { auto _fns = (((tmp_dir_).chainPath(contents_location_pth_)).array).to!string; _manifest_matter = PathMatters!()(_opt_action, _env, arg, _fns, contents_locations_arr); _manifests ~= _manifest_matter; } } } else if (arg.match(rgx.src_pth_sst_or_ssm)) { if (exists(arg)==0) { writeln("ERROR >> Processing Skipped! File not found: ", arg); } else { _manifest_matter = PathMatters!()(_opt_action, _env, arg, arg); _manifests ~= _manifest_matter; } } else if (arg.match(rgx.src_pth_zip)) { // fns_src ~= arg; // gather input markup source file names for processing } else { // anything remaining, unused arg_unrecognized ~= " " ~ arg; } } if (!(_opt_action.skip_output)) { debug(steps) { writeln("step0 commence → (without processing files)"); } outputHubOp!()(_env, _opt_action); debug(steps) { writeln("- step0 complete"); } } if (_manifests.length > 1 // _manifests[0] initialized dummy element && _opt_action.abstraction) { if (_opt_action.parallelise) { // note cannot parallelise sqlite shared db foreach(manifest; parallel(_manifests[1..$])) { if (!empty(manifest.src.filename)) { scope(success) { if (!(_opt_action.quiet)) { writefln( "%s\n%s", "~ document complete, ok ~", "------------------------------------------------------------------", ); } } scope(failure) { debug(checkdoc) { stderr.writefln( "~ document run failure ~ (%s v%s)\n\t%s\n%s", __VENDOR__, __VERSION__, manifest.src.filename, "------------------------------------------------------------------", ); } } enforce( manifest.src.filename.match(rgx.src_pth_types), "not a sisu markup filename: «" ~ manifest.src.filename ~ "»" ); debug(steps) { writeln("--->\nstepX commence → (document abstraction)"); } auto t = DocReformAbstraction!()(_env, _opt_action, manifest); static assert(!isTypeTuple!(t)); static assert(t.length==2); auto doc_abstraction = t[dAM.abstraction]; auto doc_matters = t[dAM.matters]; debug(steps) { writeln("- stepX complete"); } /+ ↓ debugs +/ if (doc_matters.opt.action.verbose) { DocReformAbstractionSummary!()(doc_abstraction, doc_matters); } /+ ↓ debugs +/ if ((doc_matters.opt.action.debug_do) || (doc_matters.opt.action.verbose) ) { DocReformDebugs!()(doc_abstraction, doc_matters); } /+ ↓ output hub +/ if (!(doc_matters.opt.action.skip_output)) { debug(steps) { writeln("step5 commence → (process outputs)"); } outputHub!()(doc_abstraction, doc_matters); debug(steps) { writeln("- step5 complete"); } } scope(exit) { if (!(_opt_action.quiet)) { writefln( "processed file: %s", manifest.src.filename ); } destroy(manifest); } } else { /+ no recognized filename provided +/ writeln("no recognized filename"); break; // terminate, stop } } } else { foreach(manifest; _manifests[1..$]) { writeln("parallelisation off: actions include sqlite shared db"); if (!empty(manifest.src.filename)) { scope(success) { if (!(_opt_action.quiet)) { writefln( "%s\n%s", "~ document complete, ok ~", "------------------------------------------------------------------", ); } } scope(failure) { debug(checkdoc) { stderr.writefln( "~ document run failure ~ (%s v%s)\n\t%s\n%s", __VENDOR__, __VERSION__, manifest.src.filename, "------------------------------------------------------------------", ); } } enforce( manifest.src.filename.match(rgx.src_pth_types), "not a sisu markup filename: «" ~ manifest.src.filename ~ "»" ); debug(steps) { writeln("--->\nstepX commence → (document abstraction)"); } auto t = DocReformAbstraction!()(_env, _opt_action, manifest); static assert(!isTypeTuple!(t)); static assert(t.length==2); auto doc_abstraction = t[dAM.abstraction]; auto doc_matters = t[dAM.matters]; debug(steps) { writeln("- stepX complete"); } /+ ↓ debugs +/ if (doc_matters.opt.action.verbose) { DocReformAbstractionSummary!()(doc_abstraction, doc_matters); } /+ ↓ debugs +/ if ((doc_matters.opt.action.debug_do) || (doc_matters.opt.action.verbose) ) { DocReformDebugs!()(doc_abstraction, doc_matters); } /+ ↓ output hub +/ if (!(doc_matters.opt.action.skip_output)) { debug(steps) { writeln("step5 commence → (process outputs)"); } outputHub!()(doc_abstraction, doc_matters); debug(steps) { writeln("- step5 complete"); } } scope(exit) { if (!(_opt_action.quiet)) { writefln( "processed file: %s", manifest.src.filename ); } destroy(manifest); } } else { /+ no recognized filename provided +/ writeln("no recognized filename"); break; // terminate, stop } } } } }