Переглянути джерело

Separate base and override configurations for core schemata.

Stefano Cossu 3 днів тому
батько
коміт
13c0394984

+ 1 - 0
README.md

@@ -105,6 +105,7 @@ luarocks path >> ~/.bashrc
 cd ../
 git clone https://github.com/scossu/Penlight.git
 cd Penlight
+git checkout clonetree
 luarocks build --local
 cd ../pocket_archive
 ```

+ 2 - 1
config/app.lua

@@ -4,7 +4,8 @@ local plpath = require "pl.path"
 
 local ROOT = os.getenv("PKAR_ROOT")
 if not ROOT then
-    print(
+    io.output(io.stderr)
+    io.write(
         "PKAR_ROOT environment variable is not set.\n" ..
         "Data will be written to a TEMPORARY location that " ..
         "may NOT SURVIVE a reboot!"

+ 5 - 8
config/model/schema/collection.lua

@@ -2,16 +2,13 @@ return {
     core = true,
 
     properties = {
-        pref_rep = {
-            uri = "pas:hasPreferredRepresentation",
-            label = "Preferred representation",
-            description = "Preferred representation. Used to generate \z
-                a thumbnail (for a visual item) or sample (for non-visual \z
-                materials such as audio).",
+        long_description = {
+            uri = "pas:longDescription",
+            label = "Long description",
+            description = "Text document in Markdown format with a detailed \z
+                description of the collection.",
             type = "resource",
             range = {file = true},
         },
     }
 }
-
-

+ 0 - 0
src/core_schema/anything.lua → core_schema/anything.lua


+ 0 - 0
src/core_schema/artifact.lua → core_schema/artifact.lua


+ 4 - 0
src/core_schema/brick.lua → core_schema/brick.lua

@@ -26,12 +26,14 @@ return {
             uri = "pas:first",
             label = "First child",
             type = "resource",
+            system = true,
         },
         next = {
             uri = "pas:next",
             label = "Next sibling",
             type = "resource",
             max_cardinality = 1,
+            system = true,
         },
         ref = {
             uri = "pas:ref",
@@ -39,11 +41,13 @@ return {
             description = "The actual resource the brick refers to.",
             type = "resource",
             max_cardinality = 1,
+            system = true,
         },
         has_member = {
             uri = "pas:hasMember",
             label = "Member",
             type = "resource",
+            system = true,
         },
     }
 }

+ 17 - 0
core_schema/collection.lua

@@ -0,0 +1,17 @@
+return {
+    uri = "pas:Collection",
+    label = "Collection",
+    broader = "brick",
+
+    properties = {
+        pref_rep = {
+            uri = "pas:hasPreferredRepresentation",
+            label = "Preferred representation",
+            description = "Preferred representation. Used to generate \z
+                a thumbnail (for a visual item) or sample (for non-visual \z
+                materials such as audio).",
+            type = "resource",
+            range = {file = true},
+        },
+    }
+}

+ 0 - 0
src/core_schema/file.lua → core_schema/file.lua


+ 18 - 7
doc/content_model_manual.md

@@ -4,14 +4,25 @@
 
 For a generic introduction to content modeling in Pocket Archive, see
 the [content modeling primer](./content_model_primer.md)
-## Predefined content types
 
-Pocket Archive ships with some predefined content types. For some very simple
-archives, this may be enough to get started with little or no customization.
-For a setup which needs to define more numerous or complex content types in a
-more articulated way, additional types can be defined. Please look at the
-[default model configuration](../config/model/typedef) files that come with
-Pocket Archive. 
+## Core schema and predefined content types
+
+Some content types are considered part of the core functionality of Pocket
+Archive. These are defined by the configurations in `core_schema` which comes
+with the Pocket Archive installation and should not be altered. These core
+types include the foundational types, such as `Anything`, `Artifact`, `File`,
+etc.
+
+The core types are extensible in the user configuration by adding properties to
+them. A configuration that extends a core schema MUST have the `core` attribute
+set to `true` and no other top-level attribute set, except for `properties`.
+
+Pocket Archive ships with a sample configuration including extensions of core
+content types. For some very simple archives, this may be enough to get started
+with little or no customization.  For a setup which needs to define more
+numerous or complex content types in a more articulated way, additional types
+can be defined. Please look at the [default model
+configuration](../config/model/schema) files that come with Pocket Archive. 
 
 Each *type definition* is encoded in a configuration file defining a single
 content category type. One doesn't have to define all possible types in detail.

+ 1 - 1
pocket_archive-scm-1.rockspec

@@ -57,5 +57,5 @@ build = {
         pkar = "src/util/pkar.lua",
         pkar_watch = "src/util/watcher.lua",
     }},
-    copy_directories = {"config", "doc", "templates"},
+    copy_directories = {"config", "core_schema", "doc", "templates"},
 }

+ 0 - 16
src/core_schema/collection.lua

@@ -1,16 +0,0 @@
-return {
-    core = true,
-
-    properties = {
-        long_description = {
-            uri = "pas:longDescription",
-            label = "Long description",
-            description = "Text document in Markdown format with a detailed \z
-                description of the collection.",
-            type = "resource",
-            range = {file = true},
-        },
-    }
-}
-
-

+ 39 - 12
src/model.lua

@@ -1,3 +1,4 @@
+local datafile = require "datafile"
 local dir = require "pl.dir"
 local path = require "pl.path"
 
@@ -44,7 +45,12 @@ end
 
 
 -- Parameters that do not get inherited.
-local NO_INHERIT = {abstract = true}
+local NO_INHERIT = {
+    abstract = true,
+    core = true,
+    description = true,
+}
+
 local MODEL_PATH = path.join(pkar.config_path, "model")
 
 local gen_config = dofile(path.join(MODEL_PATH, "generation.lua"))
@@ -62,10 +68,16 @@ end
 local function parse_model(mod_id)
     local hierarchy = {}
 
-    local function traverse(mod_id)
+    local function traverse(mod_id, core)
         logger:debug("traversing: " .. mod_id)
-        local model = dofile(path.join(
-                MODEL_PATH, "typedef", mod_id .. ".lua"))
+        local schema_path = path.join(MODEL_PATH, "schema", mod_id .. ".lua")
+        -- If core is true, or if the schema is not found in the user config,
+        -- look at the core schema.
+        if core or not path.isfile(schema_path) then
+            schema_path = datafile.path(
+                "core_schema/" .. mod_id .. ".lua")
+        end
+        local model = dofile(schema_path)
         -- Merge separate generator config
         model.gen = gen_config[mod_id]
         --model.id = mod_id
@@ -82,15 +94,18 @@ local function parse_model(mod_id)
 
         table.insert(hierarchy, 1, model)
 
-        if model.broader then traverse(model.broader) end
+        if model.broader then traverse(model.broader)
+        elseif model.core then traverse(mod_id, true) end
     end
     traverse(mod_id)
 
     local lineage = {}  -- Ordered lineage of types, from ancestor to leaf.
     local types = {}  -- Set of all types.
     for _, mod in ipairs(hierarchy) do
-        table.insert(lineage, mod.id)
-        types[mod.id] = true
+        if not mod.core then
+            table.insert(lineage, mod.id)
+            types[mod.id] = true
+        end
     end
 
     local function merge(src, dest)
@@ -119,17 +134,29 @@ end
 local function setup_model()
     -- Temp store (set) for property names.
     local all_pnames = {}
+
     -- Collect all type names from config file names.
     for _, fpath in ipairs(dir.getfiles(
-                path.join(MODEL_PATH, "typedef"), "*.lua")) do
+                path.join(MODEL_PATH, "schema"), "*.lua")) do
         local mname = path.basename(fpath):gsub(".lua$", "")
-        local typedef = parse_model(mname)
+        M.types[mname] = true
+    end
+    -- Add core schemata that were not extended by user config.
+    for _, fpath in ipairs(
+        dir.getfiles(datafile.path("core_schema"), "*.lua"
+    )) do
+        local mname = path.basename(fpath):gsub(".lua$", "")
+        M.types[mname] = true
+    end
+
+    for mname in pairs(M.types) do
+        local schema = parse_model(mname)
 
-        -- Store parsed typedef configurations.
-        M.types[mname] = typedef
+        -- Store parsed schema configurations.
+        M.types[mname] = schema
 
         -- Store unique prop names.
-        for pn in pairs(typedef.properties or NT) do
+        for pn in pairs(schema.properties or NT) do
             if not no_ll_pnames[pn] then all_pnames[pn] = true end
         end
     end

+ 1 - 1
src/submission.lua

@@ -163,7 +163,7 @@ local function generate_sip(ll_path)
     -- Infer structure from paths and row ordering.
     for i, v in ipairs(sip) do
         local rmod = model.types[v.content_type]
-        --dbg.assert(v.source_path)
+        --require "debugger".assert(rmod)
         local fpath = path.join(sip.root_path, v.source_path)
         --dbg.assert(rmod)
         v.has_member = v.has_member or {}

+ 2 - 0
src/util/pkar.lua

@@ -19,6 +19,8 @@ local sub = require "pocket_archive.submission"
 
 cli.locale "en_US"  -- TODO set with multilingual support.
 
+io.output(io.stdout)
+
 init = cli.command {
     "Initialize a new Pocket Archive store.",