Browse Source

Remove resources.

Stefano Cossu 5 days ago
parent
commit
379e9585d3
4 changed files with 89 additions and 9 deletions
  1. 1 1
      doc/roadmap.md
  2. 40 8
      src/repo.lua
  3. 34 0
      src/util/pkar.lua
  4. 14 0
      src/util/watcher.lua

+ 1 - 1
doc/roadmap.md

@@ -55,7 +55,7 @@ usage and opportunities for expanding adoption in relevant areas.
     - ✓ Option to regenerate site after submission
     - ✓ Option to clean up sources & LL on success
   - ❏ Submission report
-  -  Deleting resources
+  -  Deleting resources
 - ✓ Proper collection handling
   - ✓ Dedicated template
   - ✓ Link to markdown doc for presentation page

+ 40 - 8
src/repo.lua

@@ -65,17 +65,18 @@ M.store_updates = function(tmp_gr, s)
 end
 
 
---[[ Dump the whole archive RDF to a file stream.
+--[[--
+Dump the whole archive RDF to a file stream.
 
-    The result is a software-agnostic RDF representation of the metadata
-    (Turtle) compressed with GZip. The ores data folder can be backed up via
-    OS-level file operations.
+The result is a software-agnostic RDF representation of the metadata
+(Turtle) compressed with GZip. The ores data folder can be backed up via
+OS-level file operations.
 
-    The restore() function, combined with a copy of
-    the ores folder, shall create a fully functional repo.
+The restore() function, combined with a copy of
+the ores folder, shall create a fully functional repo.
 
-    TODO configuration backup is not yet implemented and should be included for
-    a completely self-sufficient backup.
+TODO configuration backup is not yet implemented and should be included for
+a completely self-sufficient backup.
 ]]
 M.dump = function(fpath, codec)
     local fh = assert(io.open(fpath, "wb"))
@@ -83,4 +84,35 @@ M.dump = function(fpath, codec)
 end
 
 
+--[[--
+Remove a single resource, and optionally its members.
+If a resource is not found, no triples are removed.
+
+@tparam id Resource ID in the shortened URI form, `par:<ID>`
+@tparam boolean members Whether to delete all members of this resource (with
+the `has_member` relationship) and, recursively, their members.
+
+@return table Set of IDs of resources removed.
+]]
+M.remove = function(id, members)
+    local s = term.new_iriref_ns(id)
+    local del_ids = {}
+    local function _remove(id, members)
+        if members then
+            local mds = repo.gr:term_set(
+                s, triple.POS_S,
+                model.id_to_uri.has_member, triple.POS_P
+            )
+            for m_uri in mds:iter() do _remove(m_uri, true) end
+        end
+        if (
+            M.gr:remove(s) > 0  -- Remove outbound
+            or gr:remove(nil, nil, s) > 0  -- Remove inbound
+        ) then del_ids[id] = true end
+    end
+
+    return del_ids
+end
+
+
 return M

+ 34 - 0
src/util/pkar.lua

@@ -61,6 +61,40 @@ deposit = cli.command {
     end
 }
 
+
+remove = cli.command {
+    "Remove a list of resources.",
+
+    cli.positional "path" {
+        "Path of the delete list file or input stream. It must contain \z
+        one ID per line, in the short URI format (`par:<ID>'). If not \z
+        provided or `-', it is set to standard input.",
+        type = cli.string,
+        default = "-",
+    },
+
+    cli.flag "m,members" {
+        "Remove the resource members recursively.",
+        type = cli.boolean,
+        default = false,
+    },
+
+    function(args)
+        if args.path == "-" then args.path = nil end
+        local ct = 0
+        for id in io.lines(args.path) do
+            if #id > 0 then  -- skip blank lines.
+                io.write("Deleting: " .. id .. "\n")
+                local del_ids = repo.remove(id, args.members)
+                for _ in pairs(del_ids) do ct = ct + 1 end
+            end
+        end
+
+        io.write("Deleted " .. ct .. " resources.\n")
+    end
+}
+
+
 gen_site = cli.command {
     "Generate a static site from the archive.",
 

+ 14 - 0
src/util/watcher.lua

@@ -54,6 +54,11 @@ cli.program {
         type = cli.boolean,
     },
 
+    cli.flag "r,del-members" {
+        "Remove resource members recursively.",
+        type = cli.boolean,
+    },
+
     cli.flag "c,cleanup" {
         "Remove laundry list and SIP after successful submission.",
         type = cli.boolean,
@@ -88,6 +93,15 @@ cli.program {
                     require "socket".sleep(3)
                     logger:info(cpid .. ": complete.")
                 end, "r")
+            elseif ev.name:find("pkar_remove.*") then
+                logger:info("Detected new remove list file: ", ev.name)
+                posix.spawn(function()
+                    for id in io.lines(ev.name) do
+                        if #id > 0 then
+                            local del_ids = repo.remove(id, args.del_members)
+                        end
+                    end
+                end, "r")
             end
         end)