You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
14 KiB
324 lines
14 KiB
# -*- tcl -*- |
|
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt |
|
# |
|
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. |
|
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. |
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
# (C) 2023 |
|
# |
|
# @@ Meta Begin |
|
# Application punk::mix::commandset::doc 0.1.0 |
|
# Meta platform tcl |
|
# Meta license <unspecified> |
|
# @@ Meta End |
|
|
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
## Requirements |
|
##e.g package require frobz |
|
|
|
package require punk::path ;# for treefilenames, relative |
|
package require punk::repo |
|
package require punk::docgen ;#inline doctools - generate doctools .man files at src/docgen prior to using kettle to producing .html .md etc |
|
package require punk::mix::cli ;#punk::mix::cli::lib used for kettle_call |
|
#package require punkcheck ;#for path_relative |
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
namespace eval punk::mix::commandset::doc { |
|
namespace export * |
|
|
|
proc _default {} { |
|
puts "documentation subsystem" |
|
puts "commands: doc.build" |
|
puts " build documentation from src/doc to src/embedded using the kettle build tool" |
|
puts "commands: doc.status" |
|
} |
|
|
|
proc build {} { |
|
puts "build docs" |
|
set projectdir [punk::repo::find_project] |
|
if {$projectdir eq ""} { |
|
puts stderr "No current project dir - unable to build docs" |
|
return |
|
} |
|
#user may delete the comment containing "--- punk::docgen::overwrites" and then manually edit, and we won't overwrite |
|
#we still generate output in src/docgen so user can diff and manually update if thats what they prefer |
|
set oldfiles [punk::path::treefilenames -dir $projectdir/src/doc _module_*.man] |
|
foreach maybedoomed $oldfiles { |
|
set fd [open $maybedoomed r] |
|
chan conf $fd -translation binary |
|
set data [read $fd] |
|
close $fd |
|
if {[string match "*--- punk::docgen overwrites *" $data]} { |
|
file delete -force $maybedoomed |
|
} |
|
} |
|
set generated [lib::do_docgen modules] |
|
if {[dict get $generated count] > 0} { |
|
#review |
|
set doclist [dict get $generated docs] |
|
set source_base [dict get $generated base] |
|
set target_base $projectdir/src/doc |
|
foreach dinfo $doclist { |
|
lassign $dinfo module fpath |
|
set relpath [punk::path::relative $source_base $fpath] |
|
set relfolder [file dirname $relpath] |
|
if {$relfolder eq "."} { |
|
set relfolder "" |
|
} |
|
file mkdir [file join $target_base $relfolder] |
|
set target [file join $target_base $relfolder _module_[file tail $fpath]] |
|
puts stderr "target --> $target" |
|
if {![file exists $target]} { |
|
file copy $fpath $target |
|
} |
|
} |
|
} |
|
|
|
if {[file exists $projectdir/src/doc]} { |
|
set original_wd [pwd] |
|
cd $projectdir/src |
|
#---------- |
|
set installer [punkcheck::installtrack new project.new $projectdir/src/.punkcheck] |
|
$installer set_source_target $projectdir/src/doc $projectdir/src/embedded |
|
set event [$installer start_event {-install_step kettledoc}] |
|
#use same virtual id "kettle_build_doc" as project.new - review best way to keep identifiers like this in sync. |
|
$event targetset_init VIRTUAL kettle_build_doc ;#VIRTUAL - since there is no specific target file - and we don't know all the files that will be generated |
|
$event targetset_addsource $projectdir/src/doc ;#whole doc tree is considered the source |
|
#---------- |
|
if {\ |
|
[llength [dict get [$event targetset_source_changes] changed]]\ |
|
} { |
|
$event targetset_started |
|
# -- --- --- --- --- --- |
|
puts stdout "BUILDING DOCS at $projectdir/src/embedded from src/doc" |
|
if {[catch { |
|
if {"::meta" eq [info commands ::meta]} { |
|
puts stderr "There appears to be a leftover ::meta command which is presumed to be from doctools. Destroying object" |
|
::meta destroy |
|
} |
|
punk::mix::cli::lib::kettle_call lib doc |
|
#Kettle doc |
|
|
|
} errM]} { |
|
$event targetset_end FAILED -note "kettle_build_doc failed: $errM" |
|
} else { |
|
$event targetset_end OK |
|
} |
|
# -- --- --- --- --- --- |
|
} else { |
|
puts stderr "No change detected in src/doc" |
|
$event targetset_end SKIPPED |
|
} |
|
$event end |
|
$event destroy |
|
$installer destroy |
|
cd $original_wd |
|
} else { |
|
puts stderr "No doc folder found at $projectdir/src/doc" |
|
} |
|
} |
|
proc status {} { |
|
set projectdir [punk::repo::find_project] |
|
if {$projectdir eq ""} { |
|
puts stderr "No current project dir - unable to check doc status" |
|
return |
|
} |
|
if {![file exists $projectdir/src/doc]} { |
|
set result "No documentation source found. Expected .man files in doctools format at $projectdir/src/doc" |
|
return $result |
|
} |
|
set original_wd [pwd] |
|
cd $projectdir/src |
|
puts stdout "Testing status of doctools source location $projectdir/src/doc ..." |
|
flush stdout |
|
#---------- |
|
set installer [punkcheck::installtrack new project.new $projectdir/src/.punkcheck] |
|
$installer set_source_target $projectdir/src/doc $projectdir/src/embedded |
|
set event [$installer start_event {-install_step kettledoc}] |
|
#use same virtual id "kettle_build_doc" as project.new - review best way to keep identifiers like this in sync. |
|
$event targetset_init QUERY kettle_build_doc ;#usually VIRTUAL - since there is no specific target file - and we don't know all the files that will be generated - but here we use QUERY to ensure no writes to .punkcheck |
|
set last_completion [$event targetset_last_complete] |
|
|
|
if {[llength $last_completion]} { |
|
#adding a source causes it to be checksummed |
|
$event targetset_addsource $projectdir/src/doc ;#whole doc tree is considered the source |
|
#---------- |
|
set changeinfo [$event targetset_source_changes] |
|
if {\ |
|
[llength [dict get $changeinfo changed]]\ |
|
} { |
|
puts stdout "changed" |
|
puts stdout $changeinfo |
|
} else { |
|
puts stdout "No changes detected in $projectdir/src/doc tree" |
|
} |
|
} else { |
|
#no previous completion-record for this target - must assume changed - no need to trigger checksumming |
|
puts stdout "No existing record of doc build in .punkcheck. Assume it needs to be rebuilt." |
|
} |
|
|
|
|
|
$event destroy |
|
$installer destroy |
|
|
|
cd $original_wd |
|
} |
|
proc validate {args} { |
|
set argd [punk::args::get_dict { |
|
@id -id ::punk::mix::commandset::doc::validate |
|
-- -type none -optional 1 -help "end of options marker --" |
|
-individual -type boolean -default 1 |
|
@values -min 0 -max -1 |
|
patterns -default {*.man} -type any -multiple 1 |
|
} $args] |
|
set opt_individual [tcl::dict::get $argd opts -individual] |
|
set patterns [tcl::dict::get $argd values patterns] |
|
|
|
|
|
#todo - run and validate punk::docgen output |
|
set projectdir [punk::repo::find_project] |
|
if {$projectdir eq ""} { |
|
puts stderr "No current project dir - unable to check doc status" |
|
return |
|
} |
|
if {![file exists $projectdir/src/doc]} { |
|
set result "No documentation source found. Expected .man files in doctools format at $projectdir/src/doc" |
|
return $result |
|
} |
|
set original_wd [pwd] |
|
set docroot $projectdir/src/doc |
|
cd $docroot |
|
|
|
if {!$opt_individual && "*.man" in $patterns} { |
|
if {[catch { |
|
dtplite validate $docroot |
|
} errM]} { |
|
puts stderr "commandset::doc::validate failed for projectdir '$projectdir'" |
|
puts stderr "docroot '$docroot'" |
|
puts stderr "dtplite error was: $errM" |
|
} |
|
} else { |
|
foreach p $patterns { |
|
set treefiles [punk::path::treefilenames $p] |
|
foreach path $treefiles { |
|
puts stdout "dtplite validate $path" |
|
dtplite validate $path |
|
} |
|
} |
|
} |
|
|
|
#punk::mix::cli::lib::kettle_call lib validate-doc |
|
|
|
cd $original_wd |
|
} |
|
|
|
namespace eval collection { |
|
variable pkg |
|
set pkg punk::mix::commandset::doc |
|
|
|
namespace export * |
|
namespace path [namespace parent] |
|
|
|
} |
|
|
|
namespace eval lib { |
|
variable pkg |
|
set pkg punk::mix::commandset::doc |
|
proc do_docgen {{project_subpath modules}} { |
|
#Extract doctools comments from source code |
|
set projectdir [punk::repo::find_project] |
|
set output_base [file join $projectdir src docgen] |
|
set codesource_path [file join $projectdir $project_subpath] |
|
if {![file isdirectory $codesource_path]} { |
|
puts stderr "WARNING punk::mix::commandset::doc unable to find codesource_path $codesource_path during do_docgen - skipping inline doctools generation" |
|
return |
|
} |
|
if {[file isdirectory $output_base]} { |
|
if {[catch { |
|
file delete -force $output_base |
|
}]} { |
|
error "do_docgen failed to delete existing output base folder: $output_base" |
|
} |
|
} |
|
file mkdir $output_base |
|
|
|
set matched_paths [punk::path::treefilenames -dir $codesource_path -antiglob_paths {**/mix/templates/** **/project_layouts/** **/decktemplates/** **/_aside **/_aside/**} *.tm] |
|
set count 0 |
|
set newdocs [list] |
|
set docgen_header_comments "" |
|
append docgen_header_comments {[comment {--- punk::docgen generated from inline doctools comments ---}]} \n |
|
append docgen_header_comments {[comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}]} \n |
|
append docgen_header_comments {[comment {--- punk::docgen overwrites this file ---}]} \n |
|
foreach fullpath $matched_paths { |
|
puts stdout "do_docgen processing: $fullpath" |
|
set doctools [punk::docgen::get_doctools_comments $fullpath] |
|
if {$doctools ne ""} { |
|
set fname [file tail $fullpath] |
|
set mod_tail [file rootname $fname] |
|
set relpath [punk::path::relative $codesource_path [file dirname $fullpath]] |
|
if {$relpath eq "."} { |
|
set relpath "" |
|
} |
|
set tailsegs [file split $relpath] |
|
set module_fullname [join $tailsegs ::]::$mod_tail |
|
set target_docname $fname.man |
|
set this_outdir [file join $output_base $relpath] |
|
|
|
if {[string length $fname] > 99} { |
|
#output needs to be tarballed to do checksum change tests in a reasonably straightforward and not-too-terribly slow way. |
|
#hack - review. Determine exact limit - test if tcllib tar fixed or if it's a limit of the particular tar format |
|
#work around tcllib tar filename length limit ( somewhere around 100?) This seems to be a limit on the length of a particular segment in the path.. not whole path length? |
|
#this case only came up because docgen used to path munge to long filenames - but left because we know there is a limit and renaming fixes it - even if it's ugly - but still allows doc generation. |
|
#review - if we're checking fname - should also test length of whole path and determine limits for tar |
|
package require md5 |
|
if {[package vsatisfies [package present md5] 2- ] } { |
|
set md5opt "-hex" |
|
} else { |
|
set md5opt "" |
|
} |
|
set target_docname [md5::md5 {*}$md5opt [encoding convertto utf-8 $fullpath]]_overlongfilename.man |
|
puts stderr "WARNING - overlong file name - renaming $fullpath" |
|
puts stderr " to [file dirname $fullpath]/$target_docname" |
|
} |
|
|
|
file mkdir $this_outdir |
|
puts stdout "saving [string length $doctools] bytes of doctools output from file $relpath/$fname" |
|
set outfile [file join $this_outdir $target_docname] |
|
set fd [open $outfile w] |
|
fconfigure $fd -translation binary |
|
puts -nonewline $fd $docgen_header_comments$doctools |
|
close $fd |
|
incr count |
|
lappend newdocs [list $module_fullname $outfile] |
|
} |
|
} |
|
return [list count $count docs $newdocs base $output_base] |
|
} |
|
|
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
## Ready |
|
package provide punk::mix::commandset::doc [namespace eval punk::mix::commandset::doc { |
|
variable pkg punk::mix::commandset::doc |
|
variable version |
|
set version 0.1.0 |
|
}] |
|
return |