With the new paclet functions and documentation tools in Mathematica 13.0 and the problems with workbench, I finally came around to refactoring my paclet (qmritools) and attempted to do the full build via Mathematica. However, I did not succeed.
Some things have been discussed previously (here and here) and I am aware that the PacletTools are still experimental but i still wanted to share my experiences. Maybe someone has a solution or a workaround or a fix.
My paclet contains the main context QMRTools which loads all the sub packages.
In[9]:= << QMRITools`
SetDirectory[NotebookDirectory[]];
FileBaseName /@ FileNames["*.wl", "QMRITools\\kernel"]
QMRITools`$Contexts
Out[11]= {"CardiacTools", "CoilTools", "DenoiseTools", "DixonTools", \
"ElastixTools", "GeneralTools", "GradientTools", "ImportTools", \
"IVIMTools", "JcouplingTools", "MaskingTools", "NiftiTools", \
"PhysiologyTools", "PlottingTools", "ProcessingTools", "QMRITools", \
"ReconstructionTools", "RelaxometryTools", "SimulationTools", \
"SpectroTools", "TaggingTools", "TensorTools", "TractographyTools", \
"VisteTools"}
Out[12]= {"QMRITools`GeneralTools`", "QMRITools`MaskingTools`", \
"QMRITools`NiftiTools`", "QMRITools`ElastixTools`", \
"QMRITools`PlottingTools`", "QMRITools`DixonTools`", \
"QMRITools`IVIMTools`", "QMRITools`DenoiseTools`", \
"QMRITools`CardiacTools`", "QMRITools`RelaxometryTools`", \
"QMRITools`GradientTools`", "QMRITools`TensorTools`", \
"QMRITools`JcouplingTools`", "QMRITools`SpectroTools`", \
"QMRITools`ReconstructionTools`", "QMRITools`TractographyTools`", \
"QMRITools`VisteTools`", "QMRITools`ProcessingTools`", \
"QMRITools`SimulationTools`", "QMRITools`PhysiologyTools`", \
"QMRITools`CoilTools`", "QMRITools`TaggingTools`", \
"QMRITools`ImportTools`"}
In total it has over 600 functions (and options) wich all have ::usage
defined.
In[13]:= functions =
Sort@Flatten[Names[# <> "*"] & /@ QMRITools`$Contexts];
Length[functions]
Out[14]= 647
So to build the paclet the first step is to make all the fucntion and guide pages for which i used the new DocumentaionTools palette.
Notes on Documentation tools "Generate function pages":
- usage text does not end in "." causes error messages during generation of the function pages.
solution: check usage texts for closing periods.
(*Check usage for end in "."*)
DeleteCases[
If[StringTake[Information[#]["Usage"], -1] =!= ".", #] & /@
functions, Null]
- My paclet has over 600 usage texts however it consistantly crashes between 450 and 620 notebooks. The crash is such that mathematica completely crashes, frontend and kernel.
solution: only load half the sub contexts and generate the function pages, then load the other half of the sub contexts and generate those function pages.
- If I add a single function for which I want to generate a function page I don't want to generate all 650 of them in the "Generate function pages" of the documentation palette it is possible to only generate selected pages. However this only allows for the function in the context
QMRITools'*
to be selected and not all the functions in the QMRITools'*'*
. Also this menu automatically fills in the function found in the context. I can imaging this fails with 600+ function and options. In workbench there was the possibility to only select the missing functions.
partial solution: it is easy to find which function pages I am missing with the following code. However it wont allow me to fill in these functions in the menu since they are not in the top level context.
In[15]:= dir =
"QMRITools\\Documentation\\English\\ReferencePages\\Symbols";
missing =
If[! FileExistsQ[FileNameJoin[{dir, #}] <> ".nb"], #, Nothing] & /@
functions
Sort[{#, Intersection[missing, Names[# <> "*"]]} & /@
QMRITools`$Contexts]
Out[16]= {"ADCCalc"}
Out[17]= {{"QMRITools`CardiacTools`", {}}, {"QMRITools`CoilTools`", \
{}}, {"QMRITools`DenoiseTools`", {}}, {"QMRITools`DixonTools`", {}}, \
{"QMRITools`ElastixTools`", {}}, {"QMRITools`GeneralTools`", {}}, \
{"QMRITools`GradientTools`", {}}, {"QMRITools`ImportTools`", {}}, \
{"QMRITools`IVIMTools`", {}}, {"QMRITools`JcouplingTools`", {}}, \
{"QMRITools`MaskingTools`", {}}, {"QMRITools`NiftiTools`", {}}, \
{"QMRITools`PhysiologyTools`", {}}, {"QMRITools`PlottingTools`", {}}, \
{"QMRITools`ProcessingTools`", {}}, \
{"QMRITools`ReconstructionTools`", {}}, \
{"QMRITools`RelaxometryTools`", {}}, {"QMRITools`SimulationTools`", \
{}}, {"QMRITools`SpectroTools`", {}}, {"QMRITools`TaggingTools`", \
{}}, {"QMRITools`TensorTools`", {"ADCCalc"}}, \
{"QMRITools`TractographyTools`", {}}, {"QMRITools`VisteTools`", {}}}

With some workarounds I eventually managed to generate all the function pages such that I can build my paclet using the PacletTools
. However here things get messy and I am not able to build my packlet.
PacletTools:
PacletDocumentationBuild[] also consistently crashes between 400 and 500 function pages build.
PacletDocumentationBuild[ , , "HTML"] also consistently crashes Mathematica between 400 and 500 function pages build.
PacletBuild needs to always rebuild the full documentation. If I have done full documentation build already and only change some function definitions or Asset but no function or guide pages I still have to rebuild the entire documentation.
solution: "manually" copy the changed notebooks or Asset to the build directory and use CreatePacletArchive to pack the Build directory to a packet file. The code below copies all *.wl files and the paclet Extentions to the build folder. This way i can only call PacletDocumentationBuild
when I think it is needed.
Options[ApplicationBuild] = {RebuildDoc -> False,
RebuildHTMLDoc -> False, MakeArchives -> True};
ApplicationBuild[location_?StringQ, opts : OptionsPattern[]] :=
ApplicationBuild[LoadApplicationFolder[location], opts]
ApplicationBuild[pac_, OptionsPattern[]] :=
Block[{location, name, filesApp, filesAppTar, buildDir},
location = pac["Location"];
name = pac["Name"];
buildDir = FileNameJoin[{location, "build", name}];
Print["Building " <> name <> " in location " <> location];
Print[" - Building application"];
filesApp = Prepend[
Flatten[
Select[Normal[
PacletExtensionFiles[pac]], #[[1, 1]] =!= "Documentation" &][[
All, 2]]],
FileNameJoin[{location, "PacletInfo.wl"}]
];
filesAppTar = StringReplace[#, location -> buildDir] & /@ filesApp;
MapThread[(
Quiet@CreateDirectory[DirectoryName[#2]];
CopyFile[#1, #2, OverwriteTarget -> True]
) &, {filesApp, filesAppTar}];
If[OptionValue[RebuildDoc],
Print[" - Rebuilding documentation"];
PacletDocumentationBuild[pac, DirectoryName[buildDir]]
,
Print[" - Not building documentation"];
];
If[OptionValue[RebuildHTMLDoc],
Print[" - Rebuilding html documentation"];
PacletDocumentationBuild[pac, buildDir <> "-html", "HTML"]
,
Print[" - Not building html documentation"];
];
If[OptionValue[MakeArchives],
Print[" - Making paclet and archive"];
CreatePacletArchive[buildDir];
CreateArchive[buildDir,
FileNameJoin[
Append[Drop[FileNameSplit[buildDir], -1],
name <> "-" <> pac["Version"] <> ".zip"]],
OverwriteTarget -> True];
,
Print[" - Not making paclet and archive"];
]]
So in the end I can manage everything to work all the way I want. However, I cannot finish the documentation (and HTML) builds since the Mathematica FrontEnd crashes after processing ~400 files.
