valkyrie 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7439f8be7099e4b54998826abda9222d07226ff7a54fdb868f2ab7d99596fd56
4
- data.tar.gz: 866c57941b2e2604a8d7bd8b013e0b31c07dd909404733cfb7043c61412389ad
3
+ metadata.gz: 3bd57af32d07a78e2ac9a9a1c6217b8b601018413c1a08a67762565f92da91cd
4
+ data.tar.gz: 58e0073f9ef70694e77d016cf08869d90b920f2fca3a7c42e7141289a8b7121d
5
5
  SHA512:
6
- metadata.gz: 89d1857a2f40c0d8c32c6a31a9ff1247e9b8c32aa84e917c77c3d89e6a0cb52c7548802852914ddcf11d9805f3cf0b6784331f937cf9004b18e63ecb27449971
7
- data.tar.gz: 5b143107a9ca53b86c83c5ba884635fb869919a7641c1373324193f9ac918684557177cf2c2519f5d8eeb0420bd48404037da5fb46c84d5a17bda0e4381b72f7
6
+ metadata.gz: 939dbb151e2cb770e9bfbac0cedbfc78a160ace0f3f1c482560659f1a6cd16ad0984ae1eb15caf49d4ef5926f3a01721e032f7c8363ea815e935064eb547f7c0
7
+ data.tar.gz: d2b295e1881cc0d8d45e1c69e6255fab7b5be4d3e277d3e01eaa53498ca7346131ac1c2180d73f675c93b9b4a03d73316b9f6a8256b6b40a7492dda8c088d16a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # v3.3.0 2024-07-03
2
+
3
+ ## Changes since last release
4
+
5
+ * Add support for configurable pairtree IDs in Fedora 6. ([randalldfloyd](https://github.com/randalldfloyd))
6
+
1
7
  # v3.2.0 2024-04-10
2
8
 
3
9
  ## Changes since last release
data/README.md CHANGED
@@ -234,6 +234,39 @@ config. If Fedora requires auth, you can also include that in the URL, e.g.:
234
234
  fedora_version: 5
235
235
  )
236
236
  ```
237
+ #### Pairtree paths in Fedora 4/6
238
+ Fedora 4 and 6.5+ support automatic creation of "pairtree" paths, which means that identifiers are stored in
239
+ a hashed directory structure to avoid excessive child nodes directly in the root node.
240
+
241
+ Unlike Fedora 4 where this is the default behavior, it has to be enabled via options in Fedora 6.5. This is
242
+ done by configuring both the count and length of the pairtree algorithm, so it needs to be configured
243
+ in the Fedora adapters so that both sides match.
244
+
245
+ In the following example, Fedora 6.5 is being started with options to create pairtree paths consisting of
246
+ 4 segments, 2 characters in length:
247
+
248
+ ```angular2html
249
+ CATALINA_OPTS=-Dfcrepo.home=/fcrepo-home ...
250
+ ...
251
+ -Dfcrepo.pid.minter.length=2 -Dfcrepo.pid.minter.count=4
252
+ ```
253
+ For the Fedora metadata/storage adapters to correctly translate identifiers into URI's, they should be initialized
254
+ like:
255
+
256
+ ```angular2html
257
+ Valkyrie::Persistence::Fedora::MetadataAdapter.new(
258
+ connection: ::Ldp::Client.new("http://localhost:8080/fcrepo/rest"),
259
+ fedora_version: 6.5,
260
+ fedora_pairtree_count: 4,
261
+ fedora_pairtree_length: 2
262
+ )
263
+ ```
264
+
265
+ In the configuration above, an ID of `AaBbCcDd` will be created in Fedora under the root node as `/Aa/Bb/Cc/Dd/AaBbCcDd`.
266
+ If count and length correctly match in the Fedora adapters, that same path will be calculated and returned.
267
+
268
+ Note that the configuration above is not required for pairtree paths to work correctly in Fedora 4, and automatic
269
+ pairtree creation is not supported under Fedora 5 or Fedora 6 < 6.5.
237
270
 
238
271
  ## Installing a Development environment
239
272
 
@@ -9,17 +9,23 @@ module Valkyrie::Persistence::Fedora
9
9
  # schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new(title: RDF::URI("http://example.com/title"))
10
10
  # )
11
11
  class MetadataAdapter
12
- attr_reader :connection, :base_path, :schema, :fedora_version
12
+ attr_reader :connection, :base_path, :schema, :fedora_version, :pairtree_count, :pairtree_length
13
13
 
14
14
  # @param [Ldp::Client] connection
15
15
  # @param [String] base_path
16
16
  # @param [Valkyrie::Persistence::Fedora::PermissiveSchema] schema
17
17
  # @param [Integer] fedora_version
18
- def initialize(connection:, base_path: "/", schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new, fedora_version: Valkyrie::Persistence::Fedora::DEFAULT_FEDORA_VERSION)
18
+ # @param [Integer] fedora_pairtree_count
19
+ # @param [Integer] fedora_pairtree_length
20
+ def initialize(connection:, base_path: "/", schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new, # rubocop:disable Metrics/ParameterLists
21
+ fedora_version: Valkyrie::Persistence::Fedora::DEFAULT_FEDORA_VERSION,
22
+ fedora_pairtree_count: 0, fedora_pairtree_length: 0)
19
23
  @connection = connection
20
24
  @base_path = base_path
21
25
  @schema = schema
22
26
  @fedora_version = fedora_version
27
+ @pairtree_count = fedora_pairtree_count
28
+ @pairtree_length = fedora_pairtree_length
23
29
  end
24
30
 
25
31
  # Construct the query service object using this adapter
@@ -58,7 +64,8 @@ module Valkyrie::Persistence::Fedora
58
64
  # @param [RDF::URI] id the Valkyrie ID
59
65
  # @return [RDF::URI]
60
66
  def id_to_uri(id)
61
- prefix = [5, 6].include?(fedora_version) ? "" : "#{pair_path(id)}/"
67
+ prefix = ""
68
+ prefix = "#{pair_path(id)}/" if fedora_version == 4 || (fedora_version >= 6.5 && (pairtree_count * pairtree_length).positive?)
62
69
  RDF::URI("#{connection_prefix}/#{prefix}#{CGI.escape(id.to_s)}")
63
70
  end
64
71
 
@@ -68,7 +75,16 @@ module Valkyrie::Persistence::Fedora
68
75
  # @param [Valkyrie::ID] id the Valkyrie ID
69
76
  # @return [Array<String>]
70
77
  def pair_path(id)
71
- id.to_s.split(/[-\/]/).first.split("").each_slice(2).map(&:join).join("/")
78
+ if fedora_version >= 6.5
79
+ # When configurable, pair the part up to count * length, but only up to a slash
80
+ pair_part = id.to_s[0, pairtree_count * pairtree_length].split(/[\/]/).first
81
+ slice_length = pairtree_length
82
+ else
83
+ # When not configurable, pair the full string, but only up to a dash or slash
84
+ pair_part = id.to_s.split(/[-\/]/).first
85
+ slice_length = 2
86
+ end
87
+ pair_part.split("").each_slice(slice_length).map(&:join).join("/")
72
88
  end
73
89
 
74
90
  def url_prefix
@@ -2,15 +2,26 @@
2
2
  module Valkyrie::Storage
3
3
  # Implements the DataMapper Pattern to store binary data in fedora
4
4
  class Fedora
5
- attr_reader :connection, :base_path, :fedora_version
5
+ attr_reader :connection, :base_path, :fedora_version, :pairtree_count, :pairtree_length, :uri_transformer
6
6
  PROTOCOL = 'fedora://'
7
7
  SLASH = '/'
8
8
 
9
9
  # @param [Ldp::Client] connection
10
- def initialize(connection:, base_path: "/", fedora_version: Valkyrie::Persistence::Fedora::DEFAULT_FEDORA_VERSION)
10
+ # @param [Integer] fedora_pairtree_count
11
+ # @param [Integer] fedora_pairtree_length
12
+ def initialize(connection:, base_path: "/", fedora_version: Valkyrie::Persistence::Fedora::DEFAULT_FEDORA_VERSION,
13
+ fedora_pairtree_count: 0, fedora_pairtree_length: 0)
11
14
  @connection = connection
12
15
  @base_path = base_path
13
16
  @fedora_version = fedora_version
17
+ @pairtree_count = fedora_pairtree_count
18
+ @pairtree_length = fedora_pairtree_length
19
+
20
+ @uri_transformer = if fedora_version >= 6.5 && (pairtree_count * pairtree_length).positive?
21
+ pairtree_resource_uri_transformer
22
+ else
23
+ default_resource_uri_transformer
24
+ end
14
25
  end
15
26
 
16
27
  # @param id [Valkyrie::ID]
@@ -24,7 +35,7 @@ module Valkyrie::Storage
24
35
  def supports?(feature)
25
36
  return true if feature == :versions
26
37
  # Fedora 6 auto versions and you can't delete versions.
27
- return true if feature == :version_deletion && fedora_version != 6
38
+ return true if feature == :version_deletion && fedora_version < 6
28
39
  false
29
40
  end
30
41
 
@@ -44,7 +55,7 @@ module Valkyrie::Storage
44
55
  # @param extra_arguments [Hash] additional arguments which may be passed to other adapters
45
56
  # @return [Valkyrie::StorageAdapter::StreamFile]
46
57
  def upload(file:, original_filename:, resource:, content_type: "application/octet-stream", # rubocop:disable Metrics/ParameterLists
47
- resource_uri_transformer: default_resource_uri_transformer, **_extra_arguments)
58
+ resource_uri_transformer: uri_transformer, **_extra_arguments)
48
59
  identifier = resource_uri_transformer.call(resource, base_url) + '/original'
49
60
  upload_file(fedora_uri: identifier, io: file, content_type: content_type, original_filename: original_filename)
50
61
  # Fedora 6 auto versions, so check to see if there's a version for this
@@ -60,7 +71,7 @@ module Valkyrie::Storage
60
71
  uri = fedora_identifier(id: id)
61
72
  # Fedora 6 has auto versioning, so have to sleep if it's too soon after last
62
73
  # upload.
63
- if fedora_version == 6 && current_version_id(id: id).to_s.split("/").last == Time.current.utc.strftime("%Y%m%d%H%M%S")
74
+ if fedora_version >= 6 && current_version_id(id: id).to_s.split("/").last == Time.current.utc.strftime("%Y%m%d%H%M%S")
64
75
  sleep(0.5)
65
76
  return upload_version(id: id, file: file)
66
77
  end
@@ -102,7 +113,7 @@ module Valkyrie::Storage
102
113
  end
103
114
 
104
115
  def upload_file(fedora_uri:, io:, content_type: "application/octet-stream", original_filename: "default")
105
- sha1 = [5, 6].include?(fedora_version) ? "sha" : "sha1"
116
+ sha1 = fedora_version >= 5 ? "sha" : "sha1"
106
117
  connection.http.put do |request|
107
118
  request.url fedora_uri
108
119
  request.headers['Content-Type'] = content_type
@@ -141,7 +152,7 @@ module Valkyrie::Storage
141
152
  version_id ||= id if id != current_id
142
153
  # No version got passed and we're asking for a current_id, gotta get the
143
154
  # version ID
144
- return perform_find(id: current_id, version_id: (current_version_id(id: id) || :empty)) if version_id.nil?
155
+ return perform_find(id: current_id, version_id: current_version_id(id: id) || :empty) if version_id.nil?
145
156
  Valkyrie::StorageAdapter::StreamFile.new(id: current_id, io: response(id: id), version_id: version_id)
146
157
  end
147
158
 
@@ -211,6 +222,18 @@ module Valkyrie::Storage
211
222
  end
212
223
  end
213
224
 
225
+ def pairtree_resource_uri_transformer
226
+ lambda do |resource, base_url|
227
+ id = CGI.escape(resource.id.to_s)
228
+ return RDF::URI.new(base_url + id) unless (pairtree_count * pairtree_length).positive?
229
+
230
+ pair_part = id.to_s[0, pairtree_count * pairtree_length].split(/[\/]/).first
231
+ slice_length = pairtree_length
232
+ prefix = pair_part.split("").each_slice(slice_length).map(&:join).join("/")
233
+ RDF::URI.new(base_url + "#{prefix}/" + id)
234
+ end
235
+ end
236
+
214
237
  def base_url
215
238
  pre_divider = base_path.starts_with?(SLASH) ? '' : SLASH
216
239
  post_divider = base_path.ends_with?(SLASH) ? '' : SLASH
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Valkyrie
3
- VERSION = "3.2.0"
3
+ VERSION = "3.3.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valkyrie
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trey Pendragon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-07 00:00:00.000000000 Z
11
+ date: 2024-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct