Replaces the custom app generator in earlier versions of TEI Publisher. The idea is to create a more powerful tool for creating, updating and maintaining a custom application. jinks
- can not only create new custom applications, but also reconfigure them at a later time
- uses a hierarchy of application profiles targeted at specific use cases. A profile can extend or build upon other profiles
- profiles can be modular, i.e. contribute only one feature
- detects local changes to files and leaves them untouched
- comes with its own templating module, which can also process plain-text files (XQuery, CSS etc.)
The core concept of jinks is the profile. Profiles can extend and import each other. We distinguish three different kinds of profiles:
A blueprint is a complete template for an application targeted at a specific use case like a monography, correspondance edition, dictionary etc. An application generated from a blueprint is fully functional.
A feature is a functional sub-profile to be imported into another profile. It adds specific functionality, e.g. docker configuration, additional visualizations or pages etc.
A theme is a customization of a base profile, changing mainly the look and feel, e.g. modify images, fonts or colors according to a corporate identity.
Each profile has a subcollection under profiles
and must contain at least one configuration file, config.json
, which defines all the variables to be used in templated files.
The config.json
must define a property named id
with a unique, valid URI. This is the URI under which eXist's package manager will later install the application package.
It may also specify a property extends
, which should contain the names of one or more profiles to extend. TEI Publisher apps will in general extend the base profile, which installs the required files shared by all custom TP applications.
The extension process works as follows:
- jinks creates a merged configuration, assembled from the configurations of all profiles in the extension hierarchy
- it calls the write action on every profile in sequence
The profile may also include an XQuery module called setup.xql
. If present, jinks will inspect the functions defined in this module, searching for functions with the annotations %generator:prepare
and %generator:write
. They represent different stages in the generation process:
%generator:prepare
: receives the merged configuration map - including all changes applied by previous calls to prepare - and may return a modified map. Use this to compute and set custom properties needed by your profile%generator:write
: performs the actual installation%generator:after-write
is called after the application has been updated (or installed if it was not generated before)
%generator:write
receives the merged configuration as parameter $context
. It should use the functions of the cpy
module to copy or write files into the target collection, given by the property $context?target
. The source, i.e. the collection containing the profile's source, is available in $context?source
.
%generator:after-write
receives the target collection in which the application is installed as first parameter, the current context as second.
If no setup.xql
is present or no %generator:write
function is defined, the default action is to call
cpy:copy-collection($context)
which boils down to copying everything contained in the profile's source folder into the target destination.
The cpy:copy-collection
function will automatically process any file containing .tpl
in its name as a template, which means the contents will be expanded through the templating module using the current configuration.
For the time being, we provide a basic web interface for jinks, which allows you to select a profile, see its full configuration (with inherited profile configurations merged together), and generate a custom app.
Convenient configuration forms will be added later once the basic profiles reach a more stable state.
After installing the jinks application package via the dashboard, open http://localhost:8080/exist/apps/tei-publisher-jinks/api.html in your browser. The /api/generator/{profile}
provides the main API entry point.
The main entry point into jinks is provided by the module modules/generator.xql
, which exposes the function:
declare function generator:process($profile as xs:string, $settings as map(*)?, $config as map(*)?)
where the parameters are as follows:
$profile
: the name of the profile to apply$settings
: general settings to control the generator$config
: user-supplied configuration, which will overwrite the config.json in the profile
The function will return a map with the properties: conflicts
and config
, where the first contains a list of resources which were modified by the user since the last run and were therefore not overwritten (see below). config
shows the merged configuration used during the run.
When creating a new custom application, the profile (and its sub-profiles) will copy or write all required files into a temporary collection, package it up as an eXist application xar, and finally install it into eXist.
Once the application has been installed, users may call the manager again with a modified configuration. The manager detects that an app with the same URI does already exist and by default applies the changes to the existing app collection only. The overwrite
property, which can be passed in the settings
parameter to generator:process
, determines how updates are handled:
- default: target files are not overwritten unless there's a new incoming version with different content
- update: the target file will always be overwritten by the incoming version even if the content has not changed
- all: the entire application is rebuilt from the profile and reinstalled into eXist
Unless overwrite=all
, jinks will never overwrite files which have been changed by the user since they were installed from the profile. To track changes, an SHA-256 key is computed for every file and stored in the .generator.json
file in the target app.
Conflicting files will be reported by the generator:process
function.