1. The document source layout
Our documentation sources are divided into pathways and lessons,
which are in the subdirectories pathways
and lessons
respectively. A pathway is broadly a concatenation of a chosen
ordered set of lessons (with some other pathway-specific resources
thrown in).
In the following, we’ll use core
as an example
pathway, and simple-data-types
as an example lesson.
1.1. Multiple natural languages
First, we may want to create the course core
in
multiple natural languages, e.g., English (en-us
) or Spanish
(es-mx
). To accommodate this, the source dir pathway/core
has
a langs
subdir, with further subdirs for each natlang that we want:
i.e., en-us
and es-mx
. The source tree thus looks like:
pathway/ `—— core/ `—— langs/ |—— en-us/ `—— es-mx/
We’ll call the pathway/core/langs/en-us
the core
pathway’s
root directory (for the en-us
natlang).
1.2. Multiple proglangs
By default, the programming language associated with a pathway is Pyret.
We may also want to create the courses for our core
pathway for
multiple programming languages, e.g., pyret
and wescheme
. To
accommodate this, we include the file proglang.txt
in the
pathway root directory (pathways/core/langs/en-us/
), and list
in it the various proglangs supported. Thus the contents of
proglang.txt
will look like:
pyret wescheme
Sometimes we have a pathway that has associated with it only a
single proglang, but that proglang is not Pyret. As an example,
consider the pathway shipwrecks
which is defined for the
proglang spreadsheets
. In this case, we still need a
proglang.txt
file containing the single line
spreadsheets
1.3. Pathway narratives
The pathway root directory has a file index.adoc
, which
specifies the pathway narrative. The pathway root also
has a resources/
subdirectory that houses additional
documentation that is specific to teachers. The pathway root may
also contain subdirs for front-matter
, back-matter
, and
images
: the former two add flanking matter to the final
workbook for the pathway’s course, while images
is a convenient
location for image subfiles.
1.4. Lessons associated with a pathway
The pathway root directory has a file lesson-order.txt
listing
the names of the lessons associated with it, in order. These
lessons occur as directories in the lessons/
directory in the
repo top dir.
As with pathways, lessons can be in different natlangs and
proglangs. To accommodate multiple natlangs, each lesson has a
langs
subdir, with subdirs (e.g., en-us
, es-mx
) for the
different natlangs. (This is similar to how we specify multiple
natlangs for pathways.)
lessons/ `—— simple-data-types/ `—— langs/ |—— en-us/ `—— es-mx/
We’ll call lessons/simple-data-types/langs/en-us
the lesson root
directory.
As for pathways, a lesson root directory can contain a
proglang.txt
listing the proglang(s) associatable with it. If
no proglang.txt
is present, the (single) proglang is assumed to
be pyret
.
If more than one proglang is needed, or if the single proglang is
something other than pyret
, list it in proglang.txt
.
1.4.1. Lesson plans
The lesson counterpart to the pathway narrative is the lesson
plan, given as an index.adoc
file in the lesson root
directory.
Here too, an images/
subdir is used
for image subfiles.
1.4.2. Lesson workbook pages
A lesson typically contains a pages/
subdir, which consist of
AsciiDoc sources for the pages in that lesson. The pages/
subdir has a file workbook-pages.txt
, listing all these pages
in order.
A lesson may also contain other subdirs, even within its
pages/
. These may contain files meant for inclusion in the main
pages files.
1.4.3. Adding proglang-specific source
We’ve seen that both pathways and lessons may have proglang.txt
identifying multiple proglangs as vehicles for that
course/lesson. Proglang-specific material is specified in the
source in two ways:
1: We use the directive @ifproglang{pyret}{…}
to specify source fragments
meant for the proglang pyret
.
2: Especially in the pages/
subdirs, we use further subdirs
named for the proglang to add files that would shadow the main
files. Thus for a file pages/abc.adoc
, the file
pages/pyret/abc.adoc
would shadow it for pyret
, and file
pages/wescheme/abc.adoc
would shadow it for wescheme
. If we
provide shadowing files for all relevant proglangs, the main file
doesn’t need to exist.
1.4.4. Solution-mode pages
The pages/
subdir in a lesson contributes to the student
version of the final workbook. However, we also have solutions
workbook that is intended for teachers. We have a
solution-pages/
subdir alongside pages/
, which contains files
that will shadow the similarly named student pages.
1.5. Pathway-independent files
There are also some source files that are not affiliated with any
particular pathway or lesson. These are kept in
shared/langs/en-us/docroot
(and the like, for other natlangs). Chief among these are textbook
descriptions which are .adoc files in the textbooks/
subdir.
2. The distribution layout
The built version of a pathway — called a course — is
created in a subdirectory called courses
under the
distribution
subdir. The built version of a lesson — we’ll
call it the distribution lesson — is similarly created in a
subdir called lessons
, also under the distribution
suddir.
2.1. The distribution subdir
The courses
and lessons
are not direct subdirs of
distribution
, in order to accommodate different versions of
pathways and lessons based on the natlang used. To effect this,
the distribution
has subdirs for each natlang (called en-us
,
es-mx
, etc.), and it is in the courses
and lessons
subdirs of
these that we find the natlang-specific courses and lessons.
Thus, the two natlang versions of the pathway core
are laid out
as follows:
distribution/ |—— en-us/ | `—— courses/ | `—— core/ `—— es-mx/ `—— courses/ `—— core/
Note that we use the same name core
for the two natlang
versions in the distribution. We can do this because they reside
inside two different subtrees distribution/en-us
distribution/es-mx
and thus don’t risk a name clash.
As with pathways, so with lessons: To accommodate multiple
natlangs, the lessons go into the lessons
subdir of their
natlang. E.g., for the lesson simple-data-types
, we have:
distribution/ |—— en-us/ | `—— lessons/ | `—— simple-data-types/ `—— es-mx/ `—— lessons/ `—— simple-data-types/
In the following, we will assume the prevailing natural language is
en-us
, so we will restrict our attention to the
distribution/en-us
subtree. For other natlangs, the setup is exactly the same but in
the appropriate natlang-based subtree.
Also, we will call distribution/en-us/courses/core
the course
root directory (of the English version of the core
pathway).
The dir distribution/en-us/lessons/simple-date-types
is the
distribution lesson root directory (of the English version of the
simple-data-types
lesson).
2.2. Proglang associated with a course
Typically — as seen in the above example — the built names of the pathway and the lesson are the same as their names in the source, but not always.
By default, the programming language associated with a course is
pyret
. This is marked in the course root directory as the 0-length
file .cached/.proglang-pyret
. (I.e.,
distribution/en-us/courses/core/.cached/.proglang-pyret
.)
But we as have seen, a pathway may have a proglang.txt
listing
a different or multiple proglangs.
Thus, for the pathway core
, two different courses are created in
distribution/en-us/courses
. We continue to use the unadorned
pathway name, core
, for the Pyret version. For other proglangs,
the course dir’s name uses the proglang as a hyphenated suffix.
Thus for the WeScheme version, the course is entitled
core-wescheme
. I.e., the two course root directories for core
are
distribution/en-us/courses/core distribution/en-us/courses/core-wescheme
These two directories have their own proglang marker files, i.e.,
.cached/.proglang-pyret
(as before) and
.cached/.proglang-wescheme
.
We often have pathways whose proglang.txt
contains only a single
proglang, but that proglang isn’t Pyret. E.g., the pathway
shipwrecks
whose proglang.txt
contains only spreadsheets
.
In such a case, the built course is simply called shipwrecks
rather than shipwrecks-spreadsheets
, since there is no Pyret
version to distinguish it from.
2.3. Proglang associated with a distribution lesson
As with pathways, lessons can be in different proglangs, also
specified with proglang.txt
. If no proglang.txt
is present,
the (single) proglang is assumed to be pyret
. The distribution
version of the non-Pyret lessons have the proglang as hyphenated
suffix, e.g.,
simple-data-types-wescheme
Again, as with pathways, a proglang-marker file
.cached/.proglang-wesceme
is placed in the distribution lesson
root to identify it as a lesson using wescheme
.
Note that the pathway mentions in its lesson-order.txt
the
lesson names in unadorned form (no proglang suffix). On building, a pathway becomes a
course, and the distribution lessons associated with it are the
right versions corrected for proglang. Thus the pathway core
has simple-data-types
as a constituent lesson. Moving over to
the built distribution
, the course core
(Pyret) includes the lesson
simple-data-types
(Pyret), and the course core-wescheme
includes the lesson simple-data-types-wescheme
.
2.4. The course narrative and other resources
The pathway narrative index.adoc
in the pathway root eventually
will get
converted to index.shtml
in the course root. The various .adoc
files in the front-matter
, back-matter
and resources
subdirs also will get converted to HTML files, with suffix .shtml
at
the top level and .html
at lower depths, i.e., in any pages
and solution-pages
subdirs. However, these HTML conversions
aren’t performed at this time.
2.5. The lesson plan and workbook pages
The lesson plan index.adoc
in the lesson root eventually will
get converted to
index.shtml
in the distribution lesson root.
The .adoc files in the pages/
and solution-pages/
subdirs
along with any .adoc files they include will get converted to .html
files alongside.
2.6. Pathway-independent files
The pathway-independent files in shared/langs/en-us/docroot
are
copied over to distribution/en-us
.
3. The build phases
The build is accomplished in two phases, each a Makefile. Because of the multiplicity of files to keep track of, some generated during the course of the build, the Makefile rules are themselves generated using Makefile functions. However, the input files needed in the second phase are not available until the first phase is completed, hence the need to use a separate Makefile for the two phases.
3.1. The first build phase
The first phase initializes the distribution directory, then copies the lessons and pathways over, adjusting subdirectories, and creating proglang-specific copies as needed. It sets up the temp files that will contain the input date to run various conversions in batch mode. Two specific PDFs, the page-not-found and the bilingual glossary, are requested to start the ball rolling.
3.2. The second build phase
The second phase does the bulk of the conversions. Requests are set up in the batch-input files for passing the various adoc files to the Racket preprocessor, which will create corresponding asc files. These are then converted to html files via a batch call to Asciidoctor.
Different batch files are then used to pick up primitives, the lesson inter-dependencies, and global image and pathway-toc listings, and to add some postprocessing.
Finally the postprocessed HTML files are converted to PDFs, and these are assembled into workbook pages.
4. Rearranging subdirs within the distribution directories
The build process starts by copying (the English versions of) the
pathway directories to distribution/en-us/courses
and the
lesson directories to distribution/en-us/lessons
, sometimes
creating multiple versions, as described in the previous section,
to accommodate multiple proglangs as needed. (The other natlang
versions go the corresponding subdir in distribution
, e.g.,
es-mx
, and their treatment follows a similar route, with
en-us
replaced.)
4.1. Modifying the distribution lesson directory
After copying a pathway into its distribution lesson directory with fixed
proglang, the build process drills down its directories to see if
there are any proglang-specific shadowing subdirectories. These
are named for the proglang, e.g., pyret
, wescheme
, etc. The
contents of the relevant proglang subdir are copied to the
containing directory. All the other proglang subdirs are deleted.
This ensures that all the files in the course directory, at
whatever depth, have content appropriate to its proglang.
Next, if a subdirectory called pages
occurs at any level — typically these are in the front-matter
, back-matter
and
resources
subdirs --, the build ensure that a subdir called
solution-pages
is alongside it. Furthermore, it ensures that
its contents are the same as the pages
subdir, except for such
files that are pre-existent in it (from the repo).
Next the build looks for workbook-pages.txt
inside these
pages
subdir. A sanitized version — removing
comments — of this is placed in
.cached/.workbook-pages.txt.kp
, and an even sparer version — removing landscape/portrait information — is placed in
.cached/.workbook-pages-ls.txt.kp
.
4.2. Modifying the course directory
Course dirs undergo the same modifications above for
proglang and solution-pages. Note here that the subdirs
front-matter
, back-matter
, and resources
may contain
pages/
subdirs with the appropriate workbook-pages.txt
, and
these are mined to get .cached/.workbook-pages.txt.kp
and
.cached/.workbook-pages-ls.txt.kp
as well, just as for the lessons.
5. Batch files for HTML conversion
The next stage of the build creates batch files that enshrine
enough information to the converters. We do not simply drill down
the distribution tree and convert the .adoc files immediately, as
that would be too inefficient, given the converters have
significant startup time. Instead, we create the batch
files in distribution/en-us/.cached
so the conversions can be
done in one go. The names of these batch files are given by the
following environment variables (which are set in the build
makefile):
$ADOCABLES_INPUT $ADOC_INPUT $ADOC_POSTPROC_LESSONPLAN_INPUT $ADOC_POSTPROC_NARRATIVEAUX_INPUT $ADOC_POSTPROC_NARRATIVE_INPUT $ADOC_POSTPROC_RESOURCES_INPUT $ADOC_POSTPROC_PWYINDEP_INPUT $ADOC_POSTPROC_WORKBOOKPAGE_INPUT $PUPPETEER_INPUT $EXERCISE_COLLECTOR_INPUT $COURSES_LIST_FILE $LESSONS_LIST_FILE
(The actual names used are not germane to this discussion.)
$ADOCABLES_INPUT
The $ADOCABLES_INPUT
file has entries for each adoc file that
are given to the Racket preprocessor.
Each entry is of the form:
("<adoc-filename>" #:containing-directory <string> #:dist-root-dir <string> #:lesson-plan <string> #:lesson <string> #:otherdir <boolean> #:resources <boolean> #:solutions-mode? <boolean> #:proglang <string> #:other-proglangs <list> #:narrative <boolean> #:target-pathway <string>)
Not all the keywords are necessary for all the adoc files.
The <adoc-filename>
is the basename of the adoc file. The
#:containing-directory
value is given relative to
distribution/en-us
. The #:dist-root-dir
value is the
pathname of distribution/en-us
relative to the adoc file. These
three values are not optional.
$ADOC_INPUT
This contains a list of .asc
files, which are intermediate
files created by the Racket preprocessor from the .adoc
files
listed in $ADOCABLES_INPUT
before eventual conversion by
AsciiDoctor into HTML.
These .asc
files are always inside a
.cached
subdir co-level with the original .adoc
. The pathnames of
these .asc
files are given relative to distribution/en-us
.
The HTML files created by AsciiDoctor also
reside in the .cached
subdir and go through a postprocessing
phase before moving to the directory above.
$ADOC_POSTPROC_*_INPUT
These are the files
$ADOC_POSTPROC_LESSONPLAN_INPUT $ADOC_POSTPROC_NARRATIVEAUX_INPUT $ADOC_POSTPROC_NARRATIVE_INPUT $ADOC_POSTPROC_RESOURCES_INPUT $ADOC_POSTPROC_PWYINDEP_INPUT $ADOC_POSTPROC_WORKBOOKPAGE_INPUT
These list the names of the HTML files awaiting postprocessing. They are given in six lots, because the type of postprocessing varies for:
-
lesson plan HTML files
-
glossary HTML files in courses
-
pathway narrative HTML files
-
pathway resource HTML files (i.e., pathway files other than the narrative)
-
pathway-independent HTML files (neither lessons nor pathways)
-
workbook HTML files (in the lessons)
The filenames in these files are relative to distribution/en-us
.
$PUPPETEER_INPUT
This is a JSON file containing the list of postprocessed HTML files that are ready to be converted to PDF.
*_LIST_FILE
These are:
$COURSES_LIST_FILE $LESSONS_LIST_FILE
These contain the list of all the courses and lessons
respectively. While they can be obtained by listing the
concerned subdirs in distribution/
, they are used often enough
that it is useful to cache these values.
6. Populating the conversion batch files
6.1. Pathway-independent files
The names of the pathway-independent .adoc files under
distribution/en-us/textbooks
are collected.
The .adoc file, together with its #:containing-directory
and
#:dist-root-dir
value is added to $ADOCABLES_INPUT
.
The .asc file (which sits in the .cached
subdir), pathname
relative to distribution/en-us
is added to $ADOC_INPUT
.
The .html file (not yet postprocessed, sits in .cached
),
pathname relative to distribution/en-us
) is added to
$ADOC_POSTPOC_PWYINDEP_INPUT
.
6.2. Workbook pages
We collect all
the workbook-page .adoc files and add them to
$ADOCABLES_INPUT
. The #:containing-directory
,
#:dist-root-dir
, #:lesson
, #:other-dir
, #:solutions-mode?
and #:proglang
values are included.
#:lesson
is simply the
basename of the distribution lesson.
#:other-dir
is a boolean
identifying if the file is simply meant for inclusion in other
adoc files and not for
full-scale conversion themselves. Such files are located in
subdirs named fragments
, xtra
, or xtras
.
#:solution-mode?
is a boolean set to true only for adoc files
in solution-pages
. Such files contain information meant for
teachers but not students.
The .asc version of the file is added to $ADOC_INPUT
.
The
cached .html version of the file is added ot
$ADOC_POSTPROC_WORKBOOKPAGE_INPUT
.
6.3. Lesson-plan files
We collect all
the lesson-plan .adoc files and add them to
$ADOCABLES_INPUT
. The #:containing-directory
,
#:dist-root-dir
, #:lesson-plan
, #:proglang
,
and #:other-proglangs
values are included.
#:lesson-plan
is simply the
basename of the distribution lesson.
#:other-proglangs
is a list of the other proglangs for which
this lesson is available. This is used to have the lesson plan
include links to the plans for the same lesson in the other
proglangs.
The .asc version of the file is added to $ADOC_INPUT
.
The
cached .html version of the file is added ot
$ADOC_POSTPROC_LESSONPLAN_INPUT
.
6.4. Pathway resource files
Collect all the .adoc files except the narrative file and add
them to $ADOCABLES_INPUT
. Other values included:
#:containing-directory
, #dist-root-dir
, #:other-dir
,
#:resources
, #:target-pathway
, #:solutions-mode?
,
#:proglang
.
#:resources
is set to true.
#:target-pathway
is the (base) name of the course directory
(with the proglang suffix, if any).
The .asc file is added to $ADOC_INPUT
.
The cached .html file is added to
$ADOC_POSTPROC_RESOURCES_INPUT
.
6.5. Pathway narrative files
Collect all the narrative .adoc files in the distribution and add
then to $ADOCABLES_INPUT
. Other values included:
#:containing-directory
, #:dist-root-dir
, #:narrative
,
#:target-pathway
, #:proglang
, #:other-proglangs
.
#:narrative
is set to true.
#:other-proglangs
is the list of other proglangs for which this
course is available, so they can link to each other.
The .asc file is added to $ADOC_INPUT
.
The cached .html file is added to
$ADOC_POSTPROC_NARRATIVE_INPUT
.
We also the .asc file for the pathway glossary (this is generated
by the Racket preprocessor) to $ADOC_INPUT
. Its cached .html
file is added to $ADOC_POSTPROC_NARRATIVEAUX_INPUT
.
7. Converting .adoc to .html
7.1. Racket preprocessor
After all the $ADOC…
batch files have been populated, the
build runs a Racket preprocessor on the entries in
$ADOCABLES_INPUT
to create the .cached/*.asc
files.
This is because the .adoc files created by the curriculum authors
contains some directives in addition to the commands provided by
raw AsciiDoc. A Racket program preprocesses these away to create
a raw AsciiDoc file. This has the extension .asc
and is
situated in a .cached
subdir alongside the .adoc
file penned
by the author.
The additional keyword values provided in the $ADOCABLES_INPUT
enables the Racket preprocessor to correctly address the
different types of .adoc files we have (workbook pages, lesson
plans, narratives, etc.).
A single Racket call is sufficient to process all the entries in
$ADOCABLES_INPUT
.
7.1.1. Primitives used
When processing lesson files (whether lesson plan, work page, or
a file included by them), the primitives found in it are stored
in temp files in .cached
. These become useful when creating
a collective description
of all the courses and lessons.
7.1.2. Exercise files
Special directives — @printable-exercise
,
@opt-printable-exercise
, @handout
— are used to include
files within the lesson directory that are meant to be
exercises. Their names are stored in
.cached/.lesson-exercises.txt.kp
. Again these are useful for
the collective description.
7.2. Calling Asciidoctor
Once the Racket preprocessor done, we have a bunch of
.cached/*.asc
files in the distribution, and the list of these
we have already captured in the file $ADOC_INPUT
.
These files are now ready to be processed by Asciidoctor to produce the corresponding .html.
The asciidoctor
command can take a bunch of input files
as command-line input, so we pass it the contents of
$ADOC_INPUT
.
8. Postprocessing
When the Racket preprocessing and the Asciidoctor runs complete,
we have a bunch of .cached/*.html
files in our distribution
tree. It would be nice if these were all there is to it, but
there is still a bunch of post-processing left. We use the other
$ADOC_POSTPROC_*
files to guide this post-processing.
For starters, the .cached/*.html
files need to go up one
directory, so they sit alongside their source .adoc
files in
the distribution
tree. (We may later choose to delete the .adoc
files before deployment to the website, but that’s a different
matter.) In particular, we need to ensure that the final HTML
file has extension .shtml
when it’s a lesson plan or pathway
doc, either narrative or resources. It is .html
in all other
cases, i.e., workbook pages and pathway-independent files.
The following are the components of the postprocessing:
-
CSS path correction: When Asciidoctor is run on the
.asc
file, it enshrines a pathname forcurriculum.css
. Make it relative to the HTML location. (Unfortunately, Asciidoctor can’t take a relative pathname correctly from command-line when called on files that aren’t in the calling directory.) -
Boilerplate insertion. Include links to various
.css
and.js
files. Sometimes conditionally: Codemirror-related links are included only if the file has tags classedpyret
,racket
, orcircleevalsexp
. -
Nested span and div insertion. Asciidoctor lacks the ability to nest more than one level of div or span with specific classes. The Racket preprocessor embeds markers for these so they go through Asciidoctor verbatim. We can now scan for them and replace them with divs/spans as appropriate.
-
Remove intrusive spans in headers, add self-link to h2’s
-
Create Google-Drive versions
In general, it would be nice to reduce the amount of postprocessing needed. However there are some limitations to how much we can autoinsert during the preprocessing and Asciidoctor-ing phases. View this purely as the unavoidable finishing touch. Hopefully we can reduce this with time.
9. Collective information
The build also creates four files in distribution/en-us
that combine
glossary-type information from all the courses and lessons. They
are: the dependency graph, the images list, the pathway ToCs,
and the bilingual glossary.
9.1. The dependency graph
The lesson dependency graph dependency-graph.js
is generated by the program
make-dependency-graph.lua
. It shows, for each
lesson:
-
its title
-
its description
-
the pages it contains
-
its exercise pages
-
the primitives needed for it
-
its key words
-
its prerequisite lessons
The primitives are generated for each lesson as
.cached/.index-primitives.txt.kp
by the program
collect-primitives.lua
.
Note that the JS file represent the collected information as a JSON object set to a variable. The file itself isn’t JSON. This also holds for the next two JS files described below.
9.2. Images list
A glossary of image information, images.js
, is compiled from the
images/lesson-imags.json
file in each lesson.
9.3. Pathway ToCs
A list of all the courses with their constituent lessons is
generated in pathway-tocs.js
.
9.4. Bilingual glossary
In addition to these JS files, a bilingual glossary
bilingual-glossary.html
is created in distribution/en-us/lib
.
This is a browsable version of the file glossary-terms.rkt
in the
repo.
10. PDFs and Workbooks
A course has six types of workbooks.
Each workbook is a concatenation of pages.
Most of the workbook pages are from the course’s constituent
lessons, and these are listed in the lesson’s
pages/workbook-pages.txt
.
In addition, a course’s workbook may include front and back
matter, which are specified within the pathway dir itself. Some
workbooks may contain exercise pages, which are referred to in
the lesson plan, are present in the lesson’s pages/
dir, but
not listed in its workbook-pages.txt
.
The three student-facing workbooks
are in the workbook/
subdir of the course:
workbook.pdf workbook-long.pdf opt-exercises.pdf
The workbook.pdf
contains the basic lesson pages. The -long
version includes the optional exercises referred to in the lesson
plans. The opt-
version contains just the exercises.
The three teacher-facing workbooks are named similarly but for
the -sols
suffix, and
reside in the resources/protected
subdir, which is
password-protected:
workbook-sols.pdf workbook-long-sols.pdf opt-exercises-sols.pdf
10.1. Creating page PDFs
The script make-pdf.sh
passes the list of HTML files generated in
$PUPPETEER_INPUT
to the Node program html2pdf.js
, creating
the corresponding PDFs.
10.2. Workbooks
The program make-workbook-jsons.lua
scans the course and lesson
dirs for various temp files create the previous portions of the
build to create JSON files that list the constituent PDFs for
each type of workbook.
The script make-books.sh
uses these JSON files to create the
final workbook PDFs.
11. Implementing the build process using Makefile(s)
The build was originally implementated as a long Bash script
build-pathway
, but
following
Issue
467,
has been rewritten as a more maintainable collection of
Makefiles that calls much smaller subroutine-like scripts.
The Makefile
resides at the top dir, and a build is initiated
by calling make
, possibly with the following options:
-
BOOK=yes
to generate the individual and workbook PDFs -
LINKCHECK=yes
to verify all the internal and external links used -
NATLANG=<natlang>
to generate the docs in a language different from the defaulten-us
, e.g.,es-mx
-
SEMESTER=<season>
to identify the season, e.g.,fall
-
YEAR=<year>
to identify the year, e.g.,2023
The top-level Makefile
includes Makefile.all
, which resides
in lib/maker
alongside all the other auxiliary makefiles and
programs used by the make process.
Makefile.all
calls two makefiles in order: Makefile.phase1
and Makefile.phase2
. Both makefiles use make
functions to
create a set of related rules, as the number of rules cannot be
determined beforehand. Furthermore, we use two makefiles to run
two phases of the build, because the sources for the (generated)
rules of the second phase cannot be determined until the first
phase is done. We need only two sequential makefiles.
11.1. make, phase 1
Makefile.phase1
initializes the distribution/
directory, with
subdir en-us/
, which has subdirs lib/
, extlib/
, lessons/
,
courses/
. It also zeroes out the various temp files in
en-us/.cached
, which contain lists of files that will
eventually fed as a batch to various processing scripts. We will
mention these batch files as they come up in the process.
Using generated make rules, distribution/en-us/courses/
is
populated with copies of the pathways, and
distribution/en-us/lessons/
with copies of the lessons. If a
lesson allows multiple proglangs (e.g., pyret
, wescheme
,
codap
, etc.), it is duplicated for each such proglang, with the
proglang added as a suffix, except for pyret
and none
, which
do not get a suffix.
The courses and lessons in the distribution are "massaged" to
create solution-pages/
alongside any pages/
subdirs, and to
move any shadowing files specifically meant for the prevailing
proglang to overwrite files that are generic or meant for other
proglangs. The massaging is done by two external scripts:
massage-distribution-lesson.sh
and massage-course.sh
. Both these
scripts make use of a program collect-workbook-pages.lua
to
identify within each lesson (or lesson-like entity like
front-matter and back-matter in a course) all the pages that are
eligible to go into the workbook — the so-called workbook pages.
After populating (or updating) the en-us/{courses,lessons}
,
Makefile.phase1
collects all the exercises in the lessons
(these are specific exercise directives used in the adoc source
of the lessons). These are placed in .cached/
subdirs in the
individual lesson pages/
.
In addition, phase 1 also takes care of creating the HTML version
of the bilingual glossary file, and adds it to the batch file
$PUPPETEER_INPUT
. $PUPPETEER_INPUT
will eventually contain
all the HTML files that will need to be converted into PDF pages.
11.2. make, phase 2
After phase 1 is done, Makefile.phase2
picks up the next phase.
It identifies the different kinds of .adoc
files (already
copied under {lessons, courses}
in the distribution
, and
creates make rules for converting these to .asc
files using the
Racket-based preprocessor. This is accomplished by updating three
batch files: $ADOCABLES_INPUT
, $ADOC_INPUT
and a third
$ADOC_POSTPROC_*_INPUT
file whose name depends on whether the
adoc
file in question is a lesson plan, a pathway narrative
file, a pathway glossary file, a pathway resources file, a
pathway-independent file, or a workbook page (which can be in
both lessons and pathways).
After these batch files are updated, an external script
run-asciidoctor.sh
converts the files in $ADOCABLES_INPUT
to
their corresponding .asc
(also an asciidoc file), using
adocables-preproc.rkt, an adoc preprocessor written in Racket. It
then uses the $ADOC_INPUT batch file containing the list of .asc’s
as input to Asciidoctor.
A set of .html files results alongside
the .asc’s.
The preprocessing also collects the primitive functions used (if any) in each of the lesson pages, and notes down the lesson prerequisites for each lesson.
If the make var BOOK
is set, the preproc rules include a
further set of rules that add lines to $PUPPETEER_INPUT
, so
that the HTML files posited by the preproc (but only finally
created after the postproc) will also become candidates for PDF
conversion.
This completes the preproc subphase. After it is done, the following bunch of other rules come into play (in no temporal order):
-
The primitives are then consolidated per lesson, using the external script
collect-primitives.lua
. -
The
$ADOC_POSTPROC_*_INPUT
batch files are now used by a postprocessing program,do-postproc.lua
, that creates the final html or shtml file in the correct directory (i.e., alongside the original .adoc files). In addition, Google-drive-ready copies of these (s)html files are also created. -
If the make variable
LINKCHECK
is set, a make rule uses the external scriptdo-link-check.sh
to verify that all the internal and external links used in the documents really do exist. -
An external script
make-pathways-tocs.lua
collects the ToC info for all the courses intoen-us/pathway-tocs.js
.
After the primitive generation rule (1 above) is done, a rule
calls an external script make-dependency-graph.lua
that gathers
the generated info about the lesson primitives and prereqs to
create a global lesson dependency graph in
en-us/dependency-graph.js
.
An external script make-images-js.lua
collects all the image
information from the lessons into a global image glossary at
en-us/images.js
.
After the postproc rule (2 above) is done, if the make variable
BOOK
is set, the batch file $PUPPETEER_INPUT
is used by a Node
program html2pdf.js
to create all the individual page PDFs.
After these individual PDFs are available, and again only if
BOOK
is set, a make rule uses the external program
make-workbook-pages.lua
to go into each course, collects all
its constituent lessons' workbook and exercise pages into six
course-specific list of pages for the six different types of
workbooks. The same rule then calls the Node program
makeWorkbook.js
to create each course’s set of workbook PDFs.
12. Using the Makefile
The Makefile
in the top directory allows to you build the
documentation system. Simply type make
: This creates or updates the
distribution
subdirectory with the various files
needed for the user.
You may also set a small number of environment variables on the
make
command-line to further guide the build. These variable
settings may be combined.
12.1. PDF and workbook generation
By default, make
won’t create the PDF versions of the HTML files, nor the
collections of them that form the various workbooks. PDF and
workbook construction can be time-consuming and so is best
relegated to the final run, when the author is sure that the HTML
conversions have been thoroughly debugged. Once they are, and the
PDFs are desired, request the target book
on the make
command-line, i.e.,
make book
12.2. Link checking
By default, the checking of the various internal and external links in the documents are not checked — because it can be a time-consuming process. (External-link checking is particularly heinous because it takes a long while for each URL probe to return.)
To enable link checking, use the target linkcheck
:
make linkcheck
It is often advisable to do the link check just for its own sake,
and only once in a while,
after the distribution dir is already in place from a previous
make
.
12.3. Making from scratch
To remove a previously made distribution entirely, do
make clean
The next make
— with whatever options you desire — will be on
a fresh slate.
12.4. Deploying to website
To deploy a built distribution to the website, do
make deploy
Deployment is described in more detail in the repo’s README.
13. For users of legacy script build-pathway
Before the Makefile-based system was implemented, builds were
done using a shell
script called build-pathway
. For those familiar with its usage and unable to
let go, a new script build
is provided whose API is similar to
build-pathway
, and which is actually a wrapper that calls the new make
under the hood.
The new name build is used because build-pathway
(singular) would now be a
bit of a misnomer: the underlying make always creates or updates all
pathways (i.e., courses). Nevertheless, for those who really can’t help using
the old name, build-pathway is provided a trivial identity wrapper for
build . Just remember that you cannot supply names of specific
pathways to build:
Such
arguments are ignored with a helpful diagnostic.
|
build
takes the following options:
-
--book
(aka--pdf
,-b
): generates PDFs, both for individuals and the workbooks -
--deploy
: deploys to website. Uses existingdistribution/
, if not, makes it first. May be preceded with settings forSKIPLIB
,SEASON
,YEAR
-
--force
(aka--superforce
,--super-force
,-f
,-F
): builds from scratch, scrubbing any previousdistribution/
-
--help
(aka-h
): displays help and exists -
--link
(aka--verify-links
,-l
): verify all the links in the documentation -
--natlang L
: builds doc for the natural languageL
(default:en-us
)
Options may be combined in any order.
The --help and --version
options overwhelm all other options: they display info but
do not build.
|
Use -fb or -bf for the often useful combination of
--force and --book , used to make a final-cut distribution
including the workbook PDFs after the source has been debugged to
satisfaction.
|
An experimental option --adocjs is provided that tells the
build to use the Node
version of Asciidoctor rather than the Ruby one.
|