From 8df299dc69ade4484b1167a8fa293c291fbb8a4a Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Wed, 22 Apr 2026 13:57:17 -0400 Subject: include .ssp document abstraction in source pod - When --source/--pod is used, automatically generate the .ssp document abstraction and bundle it into the pod at media/abstraction/{doc_uid}.{lang}.ssp - This makes show_abstraction implicitly true when source_or_pod is active, so the .ssp file is generated before the pod assembler runs (abstraction runs before outputHub, and source_or_pod is the first task in outputHub). - Changes: paths_source.d: Add abstraction_root() path helper to _PodPaths struct, following the same pattern as image_root(). Produces paths like pod/media/abstraction/ for both zpod (inside zip) and filesystem_open_zpod (open directory). source_pod.d: - Create media/abstraction/ directory in podArchive_directory_tree - Bundle .ssp file in pod_zipMakeReady: reads from the abstraction output directory, copies to open pod directory, adds to zip archive, computes SHA-256 digest - Write .ssp digest in zipArchiveDigest alongside sstm and ssi digests spine.d: Make show_abstraction() return true when source_or_pod is active (previously only returned true for explicit --show-abstraction flag). - The .ssp is always included when building pods - no exclusion flag for this experimental feature to keep things simple. Not generated for non-pod outputs (--text, --html, etc.) unless --show-abstraction is explicitly passed. - Tested against all 35 sample documents - zero failures. Co-Authored-By: Anthropic Claude Opus 4.6 (1M context) --- org/default_paths.org | 14 ++++++++++++++ org/out_src_pod.org | 36 ++++++++++++++++++++++++++++++++++++ org/spine.org | 2 +- src/sisudoc/io_in/paths_source.d | 14 ++++++++++++++ src/sisudoc/io_out/source_pod.d | 36 ++++++++++++++++++++++++++++++++++++ src/sisudoc/spine.d | 2 +- 6 files changed, 102 insertions(+), 2 deletions(-) diff --git a/org/default_paths.org b/org/default_paths.org index 60621e2..958acfd 100644 --- a/org/default_paths.org +++ b/org/default_paths.org @@ -895,6 +895,20 @@ template spinePathsPods() { } return _pods(); } + auto abstraction_root(string fn_src) { + auto pod_root_ = pod_root(fn_src); + auto pth_1_ = ((media_root(fn_src).zpod.chainPath("abstraction")).asNormalizedPath).array; + auto pth_2_ = ((media_root(fn_src).filesystem_open_zpod.chainPath("abstraction")).asNormalizedPath).array; + struct _pods { + auto zpod() { + return pth_1_; + } + auto filesystem_open_zpod() { + return pth_2_; + } + } + return _pods(); + } auto image_root(string fn_src) { auto pod_root_ = pod_root(fn_src); auto pth_1_ = ((media_root(fn_src).zpod.chainPath("image")).asNormalizedPath).array; diff --git a/org/out_src_pod.org b/org/out_src_pod.org index 5af10de..3062d1e 100644 --- a/org/out_src_pod.org +++ b/org/out_src_pod.org @@ -145,6 +145,36 @@ auto pod_zipMakeReady(M,P,S)(M doc_matters, P pths_pod, S _st) { } } } + } { // bundle abstraction .ssp file + import sisudoc.io_out.paths_output; + auto out_pth = spineOutPaths!()(doc_matters.output_path, doc_matters.src.language); + string abstraction_dir = ((out_pth.output_base.chainPath("abstraction")).asNormalizedPath).array; + string ssp_filename = doc_matters.src.doc_uid_out ~ ".ssp"; + string fn_src_in = ((abstraction_dir.chainPath(ssp_filename)).asNormalizedPath).array.to!string; + auto fn_src_out_pod_zip_base + = pths_pod.abstraction_root(doc_matters.src.filename).zpod.to!string + ~ "/" ~ ssp_filename; + auto fn_src_out_filesystem + = pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod.to!string + ~ "/" ~ ssp_filename; + if (exists(fn_src_in)) { + debug(io) { writeln("(io debug) src out found: ", fn_src_in); } + { // take DIGEST write to pod file digests.txt + auto data = (cast(byte[]) (fn_src_in).read); + _digests[doc_matters.src.language]["ssp"] ~= data.sha256Of.toHexString + ~ "::" ~ data.length.to!string ~ " - " ~ ssp_filename ~ "\n"; + } + if (doc_matters.opt.action.source_or_pod) { + fn_src_in.copy(fn_src_out_filesystem); + } + if (doc_matters.opt.action.source_or_pod) { + zip = podArchive("file_path_text", fn_src_in, fn_src_out_pod_zip_base, zip); + } + } else { + if (doc_matters.opt.action.debug_do_pod && doc_matters.opt.action.vox_gt_2) { + writeln("WARNING (io) src out NOT found (abstraction): ", fn_src_in); + } + } } { // bundle dr_document_make auto fn_src_in = ((doc_matters.src.is_pod) ? doc_matters.src.conf_dir_path @@ -388,6 +418,9 @@ void podArchive_directory_tree(M,P)(M doc_matters, P pths_pod) { // create direc if (!exists(pths_pod.css(doc_matters.src.filename).filesystem_open_zpod)) { pths_pod.css(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; } + if (!exists(pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod)) { + pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; + } if (!exists(pths_pod.image_root(doc_matters.src.filename).filesystem_open_zpod)) { pths_pod.image_root(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; } @@ -506,6 +539,9 @@ void zipArchiveDigest(M,F,D)(M doc_matters, F fn_pod, D _digests) { // if (doc_matters.opt.action.vox_gt_2) { writeln(_digests[_lang]["ssi"]); } f.writeln(_digests[_lang]["ssi"]); } + if (("ssp" in _digests[_lang]) && (_digests[_lang]["ssp"].length > 0)) { + f.writeln(_digests[_lang]["ssp"]); + } } } if ("shared" in _digests) { diff --git a/org/spine.org b/org/spine.org index abc4b07..e1748e7 100644 --- a/org/spine.org +++ b/org/spine.org @@ -699,7 +699,7 @@ struct OptActions { return opts["show-config"]; } @trusted bool show_abstraction() { - return opts["show-abstraction"]; + return (opts["show-abstraction"] || source_or_pod) ? true : false; } @trusted bool show_abstraction_db() { return opts["show-abstraction-db"]; diff --git a/src/sisudoc/io_in/paths_source.d b/src/sisudoc/io_in/paths_source.d index 9f8ae63..41353ed 100644 --- a/src/sisudoc/io_in/paths_source.d +++ b/src/sisudoc/io_in/paths_source.d @@ -821,6 +821,20 @@ template spinePathsPods() { } return _pods(); } + auto abstraction_root(string fn_src) { + auto pod_root_ = pod_root(fn_src); + auto pth_1_ = ((media_root(fn_src).zpod.chainPath("abstraction")).asNormalizedPath).array; + auto pth_2_ = ((media_root(fn_src).filesystem_open_zpod.chainPath("abstraction")).asNormalizedPath).array; + struct _pods { + auto zpod() { + return pth_1_; + } + auto filesystem_open_zpod() { + return pth_2_; + } + } + return _pods(); + } auto image_root(string fn_src) { auto pod_root_ = pod_root(fn_src); auto pth_1_ = ((media_root(fn_src).zpod.chainPath("image")).asNormalizedPath).array; diff --git a/src/sisudoc/io_out/source_pod.d b/src/sisudoc/io_out/source_pod.d index fa9794b..c77ce45 100644 --- a/src/sisudoc/io_out/source_pod.d +++ b/src/sisudoc/io_out/source_pod.d @@ -114,6 +114,9 @@ template spinePod() { if (!exists(pths_pod.css(doc_matters.src.filename).filesystem_open_zpod)) { pths_pod.css(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; } + if (!exists(pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod)) { + pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; + } if (!exists(pths_pod.image_root(doc_matters.src.filename).filesystem_open_zpod)) { pths_pod.image_root(doc_matters.src.filename).filesystem_open_zpod.mkdirRecurse; } @@ -179,6 +182,36 @@ template spinePod() { } } } + } { // bundle abstraction .ssp file + import sisudoc.io_out.paths_output; + auto out_pth = spineOutPaths!()(doc_matters.output_path, doc_matters.src.language); + string abstraction_dir = ((out_pth.output_base.chainPath("abstraction")).asNormalizedPath).array; + string ssp_filename = doc_matters.src.doc_uid_out ~ ".ssp"; + string fn_src_in = ((abstraction_dir.chainPath(ssp_filename)).asNormalizedPath).array.to!string; + auto fn_src_out_pod_zip_base + = pths_pod.abstraction_root(doc_matters.src.filename).zpod.to!string + ~ "/" ~ ssp_filename; + auto fn_src_out_filesystem + = pths_pod.abstraction_root(doc_matters.src.filename).filesystem_open_zpod.to!string + ~ "/" ~ ssp_filename; + if (exists(fn_src_in)) { + debug(io) { writeln("(io debug) src out found: ", fn_src_in); } + { // take DIGEST write to pod file digests.txt + auto data = (cast(byte[]) (fn_src_in).read); + _digests[doc_matters.src.language]["ssp"] ~= data.sha256Of.toHexString + ~ "::" ~ data.length.to!string ~ " - " ~ ssp_filename ~ "\n"; + } + if (doc_matters.opt.action.source_or_pod) { + fn_src_in.copy(fn_src_out_filesystem); + } + if (doc_matters.opt.action.source_or_pod) { + zip = podArchive("file_path_text", fn_src_in, fn_src_out_pod_zip_base, zip); + } + } else { + if (doc_matters.opt.action.debug_do_pod && doc_matters.opt.action.vox_gt_2) { + writeln("WARNING (io) src out NOT found (abstraction): ", fn_src_in); + } + } } { // bundle dr_document_make auto fn_src_in = ((doc_matters.src.is_pod) ? doc_matters.src.conf_dir_path @@ -475,6 +508,9 @@ template spinePod() { // if (doc_matters.opt.action.vox_gt_2) { writeln(_digests[_lang]["ssi"]); } f.writeln(_digests[_lang]["ssi"]); } + if (("ssp" in _digests[_lang]) && (_digests[_lang]["ssp"].length > 0)) { + f.writeln(_digests[_lang]["ssp"]); + } } } if ("shared" in _digests) { diff --git a/src/sisudoc/spine.d b/src/sisudoc/spine.d index f7b7d66..0598ca7 100755 --- a/src/sisudoc/spine.d +++ b/src/sisudoc/spine.d @@ -503,7 +503,7 @@ string program_name = "spine"; return opts["show-config"]; } @trusted bool show_abstraction() { - return opts["show-abstraction"]; + return (opts["show-abstraction"] || source_or_pod) ? true : false; } @trusted bool show_abstraction_db() { return opts["show-abstraction-db"]; -- cgit v1.2.3