diff --git a/demo/northwind-traders/categories/unesco-mappings.ttl b/demo/northwind-traders/categories/unesco-mappings.ttl
index 849d80e6..05d8e126 100644
--- a/demo/northwind-traders/categories/unesco-mappings.ttl
+++ b/demo/northwind-traders/categories/unesco-mappings.ttl
@@ -1,6 +1,6 @@
# Mappings between Northwind product categories and UNESCO Thesaurus concepts.
# Each category doubles as a skos:Concept, which makes the SKOS mapping relations
-# applicable and lets the SKOS package render the categories as concepts.
+# applicable and lets the Taxonomy Editor package render the categories as concepts.
# Import this file with an RDF import (see the documentation) - .ldhignore keeps
# it out of ldh push, and install.sh does not import it.
diff --git a/demo/northwind-traders/employees/employee_territories.csv b/demo/northwind-traders/employees/employee_territories.csv
index 2188e0a8..84c94a8f 100644
--- a/demo/northwind-traders/employees/employee_territories.csv
+++ b/demo/northwind-traders/employees/employee_territories.csv
@@ -1,50 +1,50 @@
-employeeID,territoryID
-1,06897
-1,19713
-2,01581
-2,01730
-2,01833
-2,02116
-2,02139
-2,02184
-2,40222
-3,30346
-3,31406
-3,32859
-3,33607
-4,20852
-4,27403
-4,27511
-5,02903
-5,07960
-5,08837
-5,10019
-5,10038
-5,11747
-5,14450
-6,85014
-6,85251
-6,98004
-6,98052
-6,98104
-7,60179
-7,60601
-7,80202
-7,80909
-7,90405
-7,94025
-7,94105
-7,95008
-7,95054
-7,95060
-8,19428
-8,44122
-8,45839
-8,53404
-9,03049
-9,03801
-9,48075
-9,48084
-9,48304
-9,55113
-9,55439
+employeeID,lastName,territoryID
+1,Davolio,06897
+1,Davolio,19713
+2,Fuller,01581
+2,Fuller,01730
+2,Fuller,01833
+2,Fuller,02116
+2,Fuller,02139
+2,Fuller,02184
+2,Fuller,40222
+3,Leverling,30346
+3,Leverling,31406
+3,Leverling,32859
+3,Leverling,33607
+4,Peacock,20852
+4,Peacock,27403
+4,Peacock,27511
+5,Buchanan,02903
+5,Buchanan,07960
+5,Buchanan,08837
+5,Buchanan,10019
+5,Buchanan,10038
+5,Buchanan,11747
+5,Buchanan,14450
+6,Suyama,85014
+6,Suyama,85251
+6,Suyama,98004
+6,Suyama,98052
+6,Suyama,98104
+7,King,60179
+7,King,60601
+7,King,80202
+7,King,80909
+7,King,90405
+7,King,94025
+7,King,94105
+7,King,95008
+7,King,95054
+7,King,95060
+8,Callahan,19428
+8,Callahan,44122
+8,Callahan,45839
+8,Callahan,53404
+9,Dodsworth,03049
+9,Dodsworth,03801
+9,Dodsworth,48075
+9,Dodsworth,48084
+9,Dodsworth,48304
+9,Dodsworth,55113
+9,Dodsworth,55439
diff --git a/demo/northwind-traders/employees/employee_territories.rq b/demo/northwind-traders/employees/employee_territories.rq
index a89f38bd..aaa51f32 100644
--- a/demo/northwind-traders/employees/employee_territories.rq
+++ b/demo/northwind-traders/employees/employee_territories.rq
@@ -1,15 +1,22 @@
+PREFIX dct:
PREFIX schema:
CONSTRUCT
{
GRAPH ?graph
{
+ # the employee's title, exactly as employees.rq writes it (the CSV carries the last name for that
+ # alone): the two imports run concurrently, and whichever reaches an employee's document first
+ # creates it, which a document without a dct:title cannot be
+ ?graph dct:title ?lastName .
+
?employee schema:areaServed ?territory
}
}
WHERE
{
?employee_territory <#employeeID> ?employeeID ;
+ <#lastName> ?lastName ;
<#territoryID> ?territoryID .
BIND(uri(concat(str($base), "employees/")) AS ?container)
diff --git a/demo/northwind-traders/orders/order_details.rq b/demo/northwind-traders/orders/order_details.rq
index 45331142..89f8e7e0 100644
--- a/demo/northwind-traders/orders/order_details.rq
+++ b/demo/northwind-traders/orders/order_details.rq
@@ -7,7 +7,10 @@ CONSTRUCT
{
GRAPH ?graph
{
- ?graph foaf:topic ?orderItem, ?listPrice .
+ # the order's title, exactly as orders.rq writes it: the two imports run concurrently, and whichever
+ # reaches an order's document first creates it, which a document without a dct:title cannot be
+ ?graph dct:title ?orderID ;
+ foaf:topic ?orderItem, ?listPrice .
?order schema:orderedItem ?orderItem .
@@ -45,7 +48,9 @@ WHERE
BIND(uri(concat(str($base), "orders/", encode_for_uri(?orderID), "/")) AS ?graph)
BIND(uri(concat(str(?graph), "#this")) AS ?order)
- BIND(uri(concat(str(?graph), "#", STRUUID())) AS ?orderItem)
+ # a line is identified by its order and product (an order has at most one line per product), so re-running
+ # the import writes the same resources rather than minting a second copy of every line
+ BIND(uri(concat(str(?graph), "#", sha1(concat(?orderID, "/", ?productID)))) AS ?orderItem)
BIND(uri(concat(str(?orderItem), "-list-price")) AS ?listPrice)
BIND(uri(concat(str($base), "products/", encode_for_uri(?productID), "/#this")) AS ?product)
BIND (STRDT(?unitPrice, xsd:float) AS ?price)
diff --git a/docs/reference/administration/packages.ttl b/docs/reference/administration/packages.ttl
index 71363520..a6558420 100644
--- a/docs/reference/administration/packages.ttl
+++ b/docs/reference/administration/packages.ttl
@@ -30,8 +30,10 @@
Package structure
-
Each package consists of two files:
+
Each package is a descriptor document with two files under it:
+ - Descriptor — the
lds:Package resource
+ - The document the package URI resolves to, describing the package itself. In the LinkedDataHub-Apps repository it is the RDF file beside the package's folder, so editor/taxonomy.ttl is the document published at editor/taxonomy/ — see Package metadata.
- ns.ttl — Package ontology
- An RDF ontology file that imports the external vocabulary using
owl:imports and attaches views to properties using ldh:view (forward relationships) or ldh:inverseView (inverse relationships). Views are typically ldh:View resources with SPARQL queries that render related data for property values.
- XSLT stylesheet — named by
ac:stylesheet
@@ -39,10 +41,14 @@
Package files are organized in the LinkedDataHub-Apps repository, where the directory path is the package URI — a package under packages/a/b/ is published at https://packages.linkeddatahub.com/a/b/, so a path carries as many segments as the grouping needs:
packages/
-├── editor/
-│ └── taxonomy/
-│ ├── ns.ttl # Ontology with views
-│ └── skos.xsl # XSLT stylesheet
+├── root.ttl # the registry's own document
+├── editor.ttl # the "Editors" container document
+└── editor/
+ ├── taxonomy.ttl # the package descriptor, published at editor/taxonomy/
+ └── taxonomy/
+ ├── ns.ttl # ontology with views, published at editor/taxonomy/ns/
+ └── skos.xsl # XSLT stylesheet, uploaded into the package document
+
The registry is published with ldh push, which is what pairs each name.ttl with the name/ folder holding its children — so the ontology's document URL is ns/, not ns.ttl.
The ontology is always ns.ttl; the stylesheet filename is not a convention, it is whatever the package's ac:stylesheet names. The taxonomy editor is named for what it does and its stylesheet for the vocabulary it speaks.
@@ -50,33 +56,50 @@
Package metadata is published as Linked Data that resolves from the package URI (e.g. https://packages.linkeddatahub.com/editor/taxonomy/#this).
A package descriptor is an instance of the lds:Package class with these properties:
- rdfs:label
+ dct:title
- Human-readable package name
dct:description
- Package description and purpose
+ dct:creator
+ - Who publishes the package (optional)
lds:ontology
- - The package ontology URI (LDT vocabulary)
+ - The package ontology URI (LinkedDataHub dataspaces vocabulary)
ac:stylesheet
- - The package stylesheet URI (AtomGraph Client vocabulary)
+ - The package stylesheet URI (AtomGraph Client vocabulary). Not written by hand in the registry: the stylesheet is uploaded when the package is published, and the reference is added afterwards, naming that upload — so a changed stylesheet gets a new URI instead of changing under the dataspaces that already imported it.
Example package metadata:
-
@prefix lds: <https://w3id.org/atomgraph/linkeddatahub/dataspaces#> .
-@prefix ac: <https://w3id.org/atomgraph/client#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+ @prefix lds: <https://w3id.org/atomgraph/linkeddatahub/dataspaces#> .
@prefix dct: <http://purl.org/dc/terms/> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix dh: <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#> .
-<https://packages.linkeddatahub.com/editor/taxonomy/#this> a lds:Package ;
- rdfs:label "Taxonomy Editor" ;
+<> a dh:Container ;
+ dct:title "Taxonomy" ;
+ foaf:primaryTopic <#this> .
+
+<#this> a lds:Package ;
+ dct:title "Taxonomy Editor" ;
dct:description "Taxonomy editing on SKOS, with custom templates" ;
- lds:ontology <https://raw.githubusercontent.com/AtomGraph/LinkedDataHub-Apps/master/packages/editor/taxonomy/ns.ttl#> ;
- ac:stylesheet <https://raw.githubusercontent.com/AtomGraph/LinkedDataHub-Apps/master/packages/editor/taxonomy/skos.xsl> .
+ dct:creator <https://atomgraph.com/#company> ;
+ lds:ontology <ns/#> .
+
The URIs are relative to the descriptor's own document, so the registry serves the ontology it names and the package carries no reference to where its sources are kept.
+
Package ontology
-
The package ontology file contains two parts:
+
The package ontology file describes the document the registry serves it as, and the ontology inside that document in two parts:
Vocabulary import
Imports the external vocabulary using owl:imports. See the Ontologies reference for ontology management details.
-
<https://raw.githubusercontent.com/AtomGraph/LinkedDataHub-Apps/master/packages/editor/taxonomy/ns.ttl#> a owl:Ontology ;
+ <> a dh:Item ;
+ dct:title "Taxonomy Editor ontology" ;
+ foaf:primaryTopic <#> .
+
+<#> a owl:Ontology ;
owl:imports <http://www.w3.org/2004/02/skos/core> .
Property views
SPARQL-based views attached to properties from the imported vocabulary:
@@ -175,8 +198,12 @@ WHERE {}
Creating custom packages
Developers can create custom packages for their own domain vocabularies. The process has four steps.
Write package ontology
-
Create ns.ttl with vocabulary import and views:
-
<https://raw.githubusercontent.com/you/repo/master/packages/schema.org/ns.ttl#> a owl:Ontology ;
+ Create ns.ttl describing both the document the registry serves it as and the ontology inside it, with the vocabulary import and the views:
+ <> a dh:Item ;
+ dct:title "Schema.org ontology" ;
+ foaf:primaryTopic <#> .
+
+<#> a owl:Ontology ;
owl:imports <https://schema.org/> .
# Attach view to a property
@@ -192,17 +219,31 @@ schema:knows ldh:view :PersonKnows .
WHERE { GRAPH ?graph { $about schema:knows ?person } }
ORDER BY ?person
\"\"\" .
+
+
warning
+
+
The dct:title on <> is not optional. A write is held to the constraints of the document as it will be written, and a LinkedDataHub document must be titled, so an ns.ttl that describes only the ontology is refused 422 Unprocessable Entity when it is pushed.
+
+
Write XSLT stylesheet
Create the stylesheet — name the file for the vocabulary it covers — with XSLT templates using system modes like ac:*, ldh:* and xhtml:*. See the Stylesheets reference for template customization patterns.
<xsl:template match="schema:knows" mode="ac:PropertyEditor"/>
- Publish package metadata as Linked Data at your package URI:
- <https://packages.linkeddatahub.com/schema.org/#this> a lds:Package ;
- rdfs:label "Schema.org Package" ;
+ Publish the descriptor as Linked Data at your package URI, naming the ontology beside it:
+ <> a dh:Container ;
+ dct:title "Schema.org" ;
+ foaf:primaryTopic <#this> .
+
+<#this> a lds:Package ;
+ dct:title "Schema.org Package" ;
dct:description "Schema.org vocabulary support" ;
- lds:ontology <https://raw.githubusercontent.com/you/repo/master/packages/schema.org/ns.ttl#> ;
- ac:stylesheet <https://raw.githubusercontent.com/you/repo/master/packages/schema.org/schema.xsl> .
- Ensure the metadata contains lds:ontology and ac:stylesheet properties pointing to the package resources.
+ lds:ontology <ns/#> .
+ Then upload the stylesheet into the package document and add ac:stylesheet naming that upload, which is where a registry published with ldh push gets it:
+ package="https://packages.example.com/schema.org/"
+
+upload=$(ldh add file --title schema.xsl --file schema.xsl "$package")
+echo "INSERT { <${package}#this> <https://w3id.org/atomgraph/client#stylesheet> <$upload> } WHERE { }" | ldh patch "$package"
+ A dataspace importing the package dereferences its descriptor, ontology and stylesheet anonymously, so all three have to be readable without a certificate.
Test installation
Declare the ldh:import triple in a test dataspace's settings document — see Management for the command.
@@ -210,7 +251,7 @@ schema:knows ldh:view :PersonKnows .
Available packages
Published packages resolve from packages.linkeddatahub.com; their sources live in the
LinkedDataHub-Apps repository, where each package directory
- contains the package ontology (ns.ttl) and the stylesheet its ac:stylesheet names.
+ contains the package ontology (ns.ttl) and its stylesheet, with the descriptor in the RDF file beside that directory.
- Taxonomy Editor
- Taxonomy editing on SKOS: a concept tree beside the content, hierarchy views in both assertion directions, and constructors and constraints for concepts, schemes and collections. Package URI:
https://packages.linkeddatahub.com/editor/taxonomy/#this
diff --git a/docs/reference/configuration.ttl b/docs/reference/configuration.ttl
index aebbee22..58003850 100644
--- a/docs/reference/configuration.ttl
+++ b/docs/reference/configuration.ttl
@@ -187,6 +187,8 @@ HOST=ec2-54-235-229-141.compute-1.amazonaws.com
Defaults to true.
- MAX_CONTENT_LENGTH
- Maximum allowed request body size (nginx has a separate setting for this). Defaults to 2097152.
+ - HTTP_MAX_THREADS
+ - Maximum request threads on Tomcat's plain HTTP connector, the one the proxy forwards to. Defaults to Tomcat's own 200. Beyond capacity it bounds how many server-side renders can be in flight against each other: a render calls back into this same connector through the proxy for the page's labels, so it holds one thread while it waits for another to answer — see the HTTP client pool.
@@ -217,12 +219,32 @@ HOST=ec2-54-235-229-141.compute-1.amazonaws.com
Socket (read) timeout — how long to wait for data on an established connection. Defaults to 120000.
CLIENT_CONNECT_TIMEOUT
Connection timeout — how long to wait to establish a connection. Defaults to 10000.
+ CONNECTION_REQUEST_TIMEOUT
+ How long a request waits for a free connection from the pool before it gives up. Defaults to 30000; left unset the underlying client waits indefinitely, and a thread parked on the pool never comes back on its own.
+ CLIENT_SELF_REQUEST_TIMEOUT
+ Connect and read timeout for requests the platform makes to its own URLs, such as a server-side render fetching its labels from the dataspace's /sparql and /ns. Those are answered by the platform's own request threads, so a wait that is too long lets a burst of renders hold every thread waiting on each other; after this bound the render gives up on the label. Defaults to 5000.
CLIENT_CONNECTION_TIME_TO_LIVE
Maximum lifetime of a pooled connection before it is closed. Defaults to 300000.
CLIENT_VALIDATE_AFTER_INACTIVITY
Idle time after which a pooled connection is validated before reuse. Defaults to 10000.
+
+
HTTP client pool
+
The size of the connection pool those clients share. Both are passed as servlet parameters rather than as CATALINA_OPTS system properties.
+
+ - MAX_CONN_PER_ROUTE
+ - Maximum pooled connections per host. Defaults to 200.
+ - MAX_TOTAL_CONN
+ - Maximum pooled connections in total. Defaults to 400.
+
+
+
warning
+
+
Keep MAX_CONN_PER_ROUTE at least as large as HTTP_MAX_THREADS. A request the platform makes to its own URL holds a pooled connection for as long as it waits for one of the same Tomcat's threads to answer it, so a pool smaller than the connector queues those calls behind each other and a burst of renders drains one bounded wait at a time. The image's defaults are sized to each other; changing one means changing the other.
+
+
+
Varnish services
diff --git a/packages/README.md b/packages/README.md
index 619a2ec7..ae24907b 100644
--- a/packages/README.md
+++ b/packages/README.md
@@ -16,8 +16,8 @@ packages/
/
The directory path is the package URI: a package under `packages/a/b/` is published at
`https://packages.linkeddatahub.com/a/b/`, so a path may carry as many segments as the grouping
-needs. The stylesheet filename is not a convention — it is whatever the package's `ac:stylesheet`
-names.
+needs. A package folder holds one `.xsl` file, and `install.sh` makes it the package's `ac:stylesheet`;
+its name is not a convention.
Package metadata is Linked Data that resolves from the package URI (e.g., `https://packages.linkeddatahub.com/editor/taxonomy/#this`).
@@ -42,21 +42,32 @@ which `ldh push` PUTs to `https://packages.linkeddatahub.com/editor/taxonomy/`:
```turtle
@prefix lds: .
-@prefix ac: .
@prefix dct: .
<#this> a lds:Package ;
dct:title "Taxonomy Editor" ;
dct:description "Turns a dataspace into a taxonomy editor: ..." ;
- lds:ontology ;
- ac:stylesheet .
+ lds:ontology .
```
-`lds:ontology ` is registry-relative: the same push PUTs `ns.ttl` as the `ns/` document beside the
-descriptor, so the ontology is served by the registry itself. `ac:stylesheet` is the raw file in this
-repository, on the branch the registry was published from — a branch tip, not a release, so a push to
-that branch changes the rendering of every dataspace that imports the package next time it
-materializes the copy (see [What the Declaration Does](#what-the-declaration-does)).
+`lds:ontology ` is registry-relative: the same push PUTs `ns.ttl` as the `ns/` document beside the
+descriptor, so the ontology is served by the registry itself. It names the ontology IRI that `ns.ttl`
+declares (`<#>` resolved against the `ns/` document), not the document URL: the imports closure keys
+graphs by ontology IRI, and a descriptor naming the document loads it a second time under the IRI,
+which fails with "Another graph with name ... is already in the hierarchy".
+
+The descriptor in this repository has no `ac:stylesheet`. The push uploads the package's `.xsl` file into
+the package document as `text/xsl`, and `install.sh` then adds the reference to that upload, whose URI it
+computes from the same file:
+
+```turtle
+
+ ac:stylesheet .
+```
+
+An upload's URI is the SHA-1 of its content, so the published reference names exactly the stylesheet
+that was published with it, and a changed stylesheet gets a new URI rather than changing under the
+dataspaces that already copied it (see [What the Declaration Does](#what-the-declaration-does)).
**Note**: Uses standard `lds:ontology` and `ac:stylesheet` properties instead of inventing new ones.
@@ -172,7 +183,7 @@ next request, and lives in the running dataspace's context dataset. Declaring th
From the next request onwards, the server resolves it:
-1. **Resolves the package description** from the package URI. Bundled descriptions and cached graphs
+1. **Resolves the package description** from the package URI. Cached graphs
come from the graph repository; other URIs are dereferenced over HTTP.
2. **Materializes the package ontology** (`lds:ontology`) as a document under the admin dataspace's
`ontologies/` container, named after the package path — `ontologies/editor-taxonomy/` for the
@@ -213,9 +224,12 @@ vocabulary stays in the dataspace, and may not display or validate correctly wit
1. Create directory: `packages//`, naming it for what the package does
2. Write `ns.ttl` with vocabulary and property views (using `ldh:view` or `ldh:inverseView`)
-3. Write the stylesheet with XSLT templates (using system modes like `ac:*`, `ldh:*`, `xhtml:*`, etc.), naming the file for the vocabulary it covers
-4. Publish package metadata as Linked Data at `https://packages.linkeddatahub.com//#this`
-5. Ensure the metadata contains `lds:ontology` and `ac:stylesheet` properties pointing to the package resources
+3. Write the stylesheet with XSLT templates (using system modes like `ac:*`, `ldh:*`, `xhtml:*`, etc.), naming the file for the vocabulary it covers; it is the only `.xsl` file in the folder
+4. Describe the package in `packages/.ttl` as `<#this>`, the `foaf:primaryTopic` of the document, with an `lds:ontology`
+ naming the ontology IRI `ns.ttl` declares; leave `ac:stylesheet` out, `install.sh` adds it
+5. List the package in the catalog, `root.ttl`, as an `rdfs:member` of the registry root with the same
+ `dct:title` and `dct:description` as its descriptor: the settings modal and `ldh packages list` read
+ the catalog, not the descriptors
## Vocabulary Reference
diff --git a/packages/editor/taxonomy.ttl b/packages/editor/taxonomy.ttl
index 4db89d9b..460c24cb 100644
--- a/packages/editor/taxonomy.ttl
+++ b/packages/editor/taxonomy.ttl
@@ -1,6 +1,5 @@
@prefix lds: .
@prefix ldh: .
-@prefix ac: .
@prefix rdf: .
@prefix dh: .
@prefix dct: .
@@ -25,8 +24,7 @@
dct:title "Taxonomy Editor" ;
dct:description "Turns a dataspace into a taxonomy editor: SKOS concepts, schemes and collections gain a concept tree beside the content, hierarchy views that read both assertion directions, and constructors and constraints that keep a concept labelled and in a scheme." ;
dct:creator ;
- lds:ontology ;
- ac:stylesheet .
+ lds:ontology .
a foaf:Organization ;
foaf:name "AtomGraph" ;
diff --git a/packages/editor/taxonomy/ns.ttl b/packages/editor/taxonomy/ns.ttl
index 11ee744e..9c4560b9 100644
--- a/packages/editor/taxonomy/ns.ttl
+++ b/packages/editor/taxonomy/ns.ttl
@@ -7,10 +7,18 @@
@prefix spin: .
@prefix dct: .
@prefix skos: .
+@prefix dh: .
+@prefix foaf: .
+
+# the document the registry serves this file as (ns/), which is what the package's lds:ontology dereferences to
+
+<> a dh:Item ;
+ dct:title "Taxonomy Editor ontology" ;
+ foaf:primaryTopic : .
: a owl:Ontology ;
owl:imports ;
- rdfs:label "SKOS package ontology".
+ rdfs:label "Taxonomy Editor ontology".
# Concept
diff --git a/packages/install.sh b/packages/install.sh
index a3268c97..817e2bd0 100755
--- a/packages/install.sh
+++ b/packages/install.sh
@@ -1,12 +1,16 @@
#!/usr/bin/env bash
-# Publishes the package registry onto a LinkedDataHub instance with the ldh CLI: makes it public and
-# pushes the document tree, whose folders are the package URIs. A dataspace importing a package
-# dereferences its descriptor, ontology and stylesheet anonymously, so the registry must be readable
-# without a certificate.
+# Publishes the package registry onto a LinkedDataHub instance with the ldh CLI: makes it public,
+# pushes the document tree, whose folders are the package URIs, and uploads each package's stylesheet
+# into its package document. A dataspace importing a package dereferences its descriptor, ontology and
+# stylesheet anonymously, so the registry must be readable without a certificate.
+#
+# A descriptor carries no ac:stylesheet in this repository: the push uploads the package's .xsl file into
+# the package document, as text/xsl, at {base}uploads/{SHA-1 of its content}, so the reference is added
+# here, from the same file, and a changed stylesheet cannot leave a descriptor pointing at the previous one.
#
# Reads LDH_BASE, LDH_CERT_FILE, LDH_CERT_PASSWORD and optionally LDH_PROXY; `make install` prompts
-# for them. Re-running converges: PUT replaces each document. make-public is a POST and adds another
-# authorization per run.
+# for them. Re-running converges: PUT replaces each document and the stylesheet reference is added back
+# to it. make-public is a POST and adds another authorization per run.
set -euo pipefail
app_dir="$(cd "$(dirname "$0")" && pwd)"
@@ -18,3 +22,13 @@ ldh admin make-public
ldh_app_step "Pushing package descriptors and files"
ldh push --dir "$app_dir" "$LDH_BASE"
+
+ldh_app_step "Declaring package stylesheets"
+# a package is the folder its stylesheet is in, e.g. editor/taxonomy/skos.xsl -> ${LDH_BASE}editor/taxonomy/#this
+(cd "$app_dir" && find . -name '*.xsl' -not -path './.*' | sed 's|^\./||' | sort) | while read -r stylesheet; do
+ package_doc="${LDH_BASE}$(dirname "$stylesheet")/"
+ upload="${LDH_BASE}uploads/$(shasum -a 1 "$app_dir/$stylesheet" | cut -d' ' -f1)"
+ printf "Declaring %s as the stylesheet of %s#this\n" "$upload" "$package_doc"
+ echo "INSERT { <${package_doc}#this> <${upload}> } WHERE { }" |
+ ldh patch "$package_doc"
+done
diff --git a/packages/root.ttl b/packages/root.ttl
new file mode 100644
index 00000000..786e77c0
--- /dev/null
+++ b/packages/root.ttl
@@ -0,0 +1,27 @@
+@prefix def: .
+@prefix ldh: .
+@prefix rdf: .
+@prefix rdfs: .
+@prefix dct: .
+
+# The package catalog. The dataspace settings modal and `ldh packages list` read this document and
+# offer each rdfs:member, labelled with the dct:title and dct:description given here, so a new
+# package is listed by adding it below with the same title and description as its descriptor.
+
+<> a def:Root ;
+ dct:title "LinkedDataHub packages" ;
+ dct:description "Catalog of packages available for LinkedDataHub applications" ;
+ rdfs:member ;
+ rdf:_1 <#content> ;
+ rdf:_2 <#select-children> .
+
+<#content> a ldh:XHTML ;
+ rdf:value """
+
Packages add a vocabulary to a dataspace together with the views, forms and templates that render it. A dataspace imports one from its settings.
+
"""^^rdf:XMLLiteral .
+
+<#select-children> a ldh:Object ;
+ rdf:value ldh:ChildrenView .
+
+ dct:title "Taxonomy Editor" ;
+ dct:description "Turns a dataspace into a taxonomy editor: SKOS concepts, schemes and collections gain a concept tree beside the content, hierarchy views that read both assertion directions, and constructors and constraints that keep a concept labelled and in a scheme." .