libis-tools 1.0.5-java

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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +40 -0
  6. data/Gemfile +7 -0
  7. data/README.md +202 -0
  8. data/Rakefile +11 -0
  9. data/bin/libis_tool +5 -0
  10. data/lib/libis-tools.rb +1 -0
  11. data/lib/libis/tools.rb +25 -0
  12. data/lib/libis/tools/assert.rb +52 -0
  13. data/lib/libis/tools/checksum.rb +106 -0
  14. data/lib/libis/tools/cli/cli_helper.rb +189 -0
  15. data/lib/libis/tools/cli/reorg.rb +416 -0
  16. data/lib/libis/tools/command.rb +133 -0
  17. data/lib/libis/tools/command_line.rb +23 -0
  18. data/lib/libis/tools/config.rb +147 -0
  19. data/lib/libis/tools/config_file.rb +85 -0
  20. data/lib/libis/tools/csv.rb +38 -0
  21. data/lib/libis/tools/deep_struct.rb +71 -0
  22. data/lib/libis/tools/extend/array.rb +16 -0
  23. data/lib/libis/tools/extend/empty.rb +7 -0
  24. data/lib/libis/tools/extend/hash.rb +147 -0
  25. data/lib/libis/tools/extend/kernel.rb +25 -0
  26. data/lib/libis/tools/extend/ostruct.rb +3 -0
  27. data/lib/libis/tools/extend/roo.rb +91 -0
  28. data/lib/libis/tools/extend/string.rb +94 -0
  29. data/lib/libis/tools/extend/struct.rb +29 -0
  30. data/lib/libis/tools/extend/symbol.rb +8 -0
  31. data/lib/libis/tools/logger.rb +130 -0
  32. data/lib/libis/tools/mets_dnx.rb +61 -0
  33. data/lib/libis/tools/mets_file.rb +504 -0
  34. data/lib/libis/tools/mets_objects.rb +547 -0
  35. data/lib/libis/tools/parameter.rb +372 -0
  36. data/lib/libis/tools/spreadsheet.rb +196 -0
  37. data/lib/libis/tools/temp_file.rb +42 -0
  38. data/lib/libis/tools/thread_safe.rb +31 -0
  39. data/lib/libis/tools/version.rb +5 -0
  40. data/lib/libis/tools/xml_document.rb +583 -0
  41. data/libis-tools.gemspec +55 -0
  42. data/spec/assert_spec.rb +65 -0
  43. data/spec/checksum_spec.rb +68 -0
  44. data/spec/command_spec.rb +90 -0
  45. data/spec/config_file_spec.rb +83 -0
  46. data/spec/config_spec.rb +113 -0
  47. data/spec/csv_spec.rb +159 -0
  48. data/spec/data/test-headers.csv +2 -0
  49. data/spec/data/test-headers.tsv +2 -0
  50. data/spec/data/test-noheaders.csv +1 -0
  51. data/spec/data/test-noheaders.tsv +1 -0
  52. data/spec/data/test.data +9 -0
  53. data/spec/data/test.xlsx +0 -0
  54. data/spec/data/test.xml +8 -0
  55. data/spec/data/test.yml +2 -0
  56. data/spec/data/test_config.yml +15 -0
  57. data/spec/deep_struct_spec.rb +138 -0
  58. data/spec/logger_spec.rb +165 -0
  59. data/spec/mets_file_spec.rb +223 -0
  60. data/spec/parameter_container_spec.rb +152 -0
  61. data/spec/parameter_spec.rb +148 -0
  62. data/spec/spec_helper.rb +29 -0
  63. data/spec/spreadsheet_spec.rb +1820 -0
  64. data/spec/temp_file_spec.rb +76 -0
  65. data/spec/test.xsd +20 -0
  66. data/spec/thread_safe_spec.rb +64 -0
  67. data/spec/xmldocument_spec.rb +421 -0
  68. data/test/test_helper.rb +7 -0
  69. data/test/webservices/test_ca_item_info.rb +59 -0
  70. data/test/webservices/test_ca_search.rb +35 -0
  71. metadata +437 -0
@@ -0,0 +1,547 @@
1
+ require 'libis/tools/thread_safe'
2
+ require 'cgi'
3
+
4
+ module Libis
5
+ module Tools
6
+ # noinspection RubyResolve
7
+ class MetsFile
8
+
9
+ # Generic module that provides code shortcuts for the {Representation}, {Div} and {File} classes.
10
+ module MetsObject
11
+
12
+ # Take a hash and set class instance attributes.
13
+ # @param [Hash] hash Hash with <attribute_name>, <attribute_value> pairs.
14
+ def set_from_hash(hash)
15
+ hash.each { |key, value| send "#{key}=", value if respond_to?(key) }
16
+ end
17
+
18
+ # Default initializer
19
+ def initialize
20
+ @id = 0
21
+ end
22
+
23
+ # Sets the unique id for the instance
24
+ def set_id(id)
25
+ @id = id
26
+ end
27
+
28
+ def id
29
+ @id
30
+ end
31
+
32
+ # Convert structure to String. Can be used for debugging to show what is stored.
33
+ def to_s
34
+ "#{self.class}:\n" +
35
+ self.instance_variables.map do |var|
36
+ v = self.instance_variable_get(var)
37
+ v = "#{v.class}-#{v.id}" if v.is_a? MetsObject
38
+ v = v.map do |x|
39
+ x.is_a?(MetsObject) ? "#{x.class}-#{x.id}" : x.to_s
40
+ end.join(',') if v.is_a? Array
41
+ " - #{var.to_s.gsub(/^@/, '')}: #{v}"
42
+ end.join("\n")
43
+ end
44
+
45
+ end
46
+
47
+ # Container class for creating a representation in the METS.
48
+ class Representation
49
+ include MetsObject
50
+
51
+ # The currently allowed attributes on this class. The attributes will typically be used in {DnxSection}s.
52
+ attr_accessor :label, :preservation_type, :usage_type, :representation_code, :entity_type, :access_right_id,
53
+ :user_a, :user_b, :user_c,
54
+ :group_id, :priority, :order,
55
+ :digital_original, :content, :context, :hardware, :carrier, :original_name,
56
+ :preservation_levels, :env_dependencies, :hardware_ids, :software_ids,
57
+ :hardware_infos, :software_infos, :relationship_infos, :environments,
58
+ :dc_record, :source_metadata
59
+
60
+ # The id that will be used in the XML file to reference this representation.
61
+ def xml_id
62
+ "rep#{@id}"
63
+ end
64
+
65
+ # This method creates the appropriate {DnxSection}s based on what attributes are filled in.
66
+ def amd
67
+ dnx = {}
68
+ tech_data = []
69
+ # General characteristics
70
+ data = {
71
+ preservationType: preservation_type,
72
+ usageType: usage_type,
73
+ DigitalOriginal: digital_original,
74
+ label: label,
75
+ representationEntityType: entity_type,
76
+ contentType: content,
77
+ contextType: context,
78
+ hardwareUsed: hardware,
79
+ physicalCarrierMedia: carrier,
80
+ deliveryPriority: priority,
81
+ orderingSequence: order,
82
+ RepresentationCode: representation_code,
83
+ RepresentationOriginalName: original_name,
84
+ UserDefinedA: user_a,
85
+ UserDefinedB: user_b,
86
+ UserDefinedC: user_c,
87
+ }.cleanup
88
+ tech_data << GeneralRepCharacteristics.new(data) unless data.empty?
89
+ # Object characteristics
90
+ data = {
91
+ groupID: group_id
92
+ }.cleanup
93
+ tech_data << ObjectCharacteristics.new(data) unless data.empty?
94
+ # Preservation level
95
+ if preservation_levels
96
+ data_list = []
97
+ preservation_levels.each do |preservation_level|
98
+ data = {
99
+ preservationLevelValue: preservation_level[:value],
100
+ preservationLevelRole: preservation_level[:role],
101
+ preservationLevelRationale: preservation_level[:rationale],
102
+ preservationLevelDateAssigned: preservation_level[:date],
103
+ }.cleanup
104
+ data_list << OpenStruct.new(data) unless data.empty?
105
+ end
106
+ tech_data << PreservationLevel.new(array: data_list) unless data_list.empty?
107
+ end
108
+ # Dependencies
109
+ if env_dependencies
110
+ data_list = []
111
+ env_dependencies.each do |dependency|
112
+ data = {
113
+ dependencyName: dependency[:name],
114
+ dependencyIdentifierType1: dependency[:type1],
115
+ dependencyIdentifierValue1: dependency[:value1],
116
+ dependencyIdentifierType2: dependency[:type2],
117
+ dependencyIdentifierValue2: dependency[:value2],
118
+ dependencyIdentifierType3: dependency[:type3],
119
+ dependencyIdentifierValue3: dependency[:value3],
120
+ }.cleanup
121
+ data_list << OpenStruct.new(data) unless data.empty?
122
+ end
123
+ tech_data << EnvironmentDependencies.new(array: data_list) unless data_list.empty?
124
+ end
125
+ # Hardware registry id
126
+ if hardware_ids
127
+ data_list = []
128
+ hardware_ids.each do |id|
129
+ data = {
130
+ registryId: id
131
+ }.cleanup
132
+ data_list << OpenStruct.new(data) unless data.empty?
133
+ end
134
+ tech_data << EnvHardwareRegistry.new(array: data_list) unless data_list.empty?
135
+ end
136
+ # Software registry id
137
+ if software_ids
138
+ data_list = []
139
+ software_ids.each do |id|
140
+ data = {
141
+ registryId: id
142
+ }.cleanup
143
+ data_list << OpenStruct.new(data) unless data.empty?
144
+ end
145
+ tech_data << EnvSoftwareRegistry.new(array: data_list) unless data_list.empty?
146
+ end
147
+ # Hardware
148
+ if hardware_infos
149
+ data_list = []
150
+ hardware_infos.each do |hardware|
151
+ data = {
152
+ hardwareName: hardware[:name],
153
+ hardwareType: hardware[:type],
154
+ hardwareOtherInformation: hardware[:info],
155
+ }.cleanup
156
+ data_list << OpenStruct.new(data) unless data.empty?
157
+ end
158
+ tech_data << EnvironmentHardware.new(array: data_list) unless data_list.empty?
159
+ end
160
+ # Software
161
+ if software_infos
162
+ data_list = []
163
+ software_infos.each do |software|
164
+ data = {
165
+ softwareName: software[:name],
166
+ softwareVersion: software[:version],
167
+ softwareType: software[:type],
168
+ softwareOtherInformation: software[:info],
169
+ softwareDependancy: software[:dependency],
170
+ }.cleanup
171
+ data_list << OpenStruct.new(data) unless data.empty?
172
+ end
173
+ tech_data << EnvironmentSoftware.new(array: data_list) unless data_list.empty?
174
+ end
175
+ # Relationship
176
+ if relationship_infos
177
+ data_list = []
178
+ relationship_infos.each do |relationship|
179
+ data = {
180
+ relationshipType: relationship[:type],
181
+ relationshipSubType: relationship[:subtype],
182
+ relatedObjectIdentifierType1: relationship[:type1],
183
+ relatedObjectIdentifierValue1: relationship[:id1],
184
+ relatedObjectSequence1: relationship[:seq1],
185
+ relatedObjectIdentifierType2: relationship[:type2],
186
+ relatedObjectIdentifierValue2: relationship[:id2],
187
+ relatedObjectSequence2: relationship[:seq2],
188
+ relatedObjectIdentifierType3: relationship[:type3],
189
+ relatedObjectIdentifierValue3: relationship[:id3],
190
+ relatedObjectSequence3: relationship[:seq3],
191
+ }.cleanup
192
+ data_list << OpenStruct.new(data) unless data.empty?
193
+ end
194
+ tech_data << RelationShip.new(array: data_list) unless data_list.empty?
195
+ end
196
+ # Environment
197
+ if environments
198
+ data_list = []
199
+ environments.each do |environment|
200
+ data = {
201
+ environmentCharacteristic: environment[:characteristic],
202
+ environmentPurpose: environment[:purpose],
203
+ environmentNote: environment[:note],
204
+ }.cleanup
205
+ data_list << OpenStruct.new(data) unless data.empty?
206
+ end
207
+ tech_data << Environment.new(array: data_list) unless data_list.empty?
208
+ end
209
+ # Finally assemble technical section
210
+ dnx[:tech] = tech_data unless tech_data.empty?
211
+ # Rights section
212
+ rights_data = []
213
+ data = {
214
+ policyId: access_right_id
215
+ }.cleanup
216
+ rights_data << AccessRightsPolicy.new(data) unless data.empty?
217
+ dnx[:rights] = rights_data unless rights_data.empty?
218
+ # Source metadata
219
+ if source_metadata
220
+ source_metadata.each_with_index do |metadata, i|
221
+ dnx["source-#{metadata[:type].to_s.upcase}-#{i}"] = metadata[:data]
222
+ end
223
+ end
224
+ dnx
225
+ end
226
+
227
+ end
228
+
229
+ # Container class for creating a file in the METS.
230
+ class File
231
+ include MetsObject
232
+
233
+ # The currently allowed attributes on this class. The attributes will typically be used in {DnxSection}s.
234
+ attr_accessor :label, :note, :location, :target_location, :original, :mimetype, :puid, :size, :entity_type,
235
+ :creation_date, :modification_date, :composition_level, :group_id,
236
+ :checksum_MD5, :checksum_SHA1, :checksum_SHA256,:checksum_SHA384,:checksum_SHA512,
237
+ :fixity_type, :fixity_value,
238
+ :preservation_levels, :inhibitors, :env_dependencies, :hardware_ids, :software_ids,
239
+ :signatures, :hardware_infos, :software_infos, :relationship_infos, :environments, :applications,
240
+ :dc_record, :source_metadata, :representation
241
+
242
+ # The id that will be used in the XML file to reference this file.
243
+ def xml_id
244
+ "fid#{@id}"
245
+ end
246
+
247
+ # The id that will be used for the group in the XML file.
248
+ def make_group_id
249
+ "grp#{group_id rescue @id}"
250
+ end
251
+
252
+ # The file's name as it was originally.
253
+ def orig_name
254
+ ::File.basename(location)
255
+ end
256
+
257
+ # The file's original directory.
258
+ def orig_path
259
+ ::File.dirname(location)
260
+ end
261
+
262
+ # The full path where the file is copied
263
+ def target
264
+ if target_location.nil?
265
+ return "#{xml_id}#{::File.extname(location)}"
266
+ end
267
+ target_location
268
+ end
269
+
270
+ def target_name
271
+ ::File.basename(target)
272
+ end
273
+
274
+ def target_path
275
+ ::File.dirname(target)
276
+ end
277
+
278
+ # This method creates the appropriate {DnxSection}s based on what attributes are filled in.
279
+ def amd
280
+ dnx = {}
281
+ tech_data = []
282
+ # General File charateristics
283
+ data = {
284
+ label: label,
285
+ note: note,
286
+ fileCreationDate: creation_date,
287
+ fileModificationDate: modification_date,
288
+ FileEntityType: entity_type,
289
+ compositionLevel: composition_level,
290
+ # fileLocationType: 'FILE',
291
+ fileLocation: location,
292
+ fileOriginalName: CGI.escape(original || target_name).gsub('+', '%20'),
293
+ fileOriginalPath: target_path,
294
+ # fileOriginalID: URI.encode(location),
295
+ # fileExtension: ::File.extname(orig_name),
296
+ fileMIMEType: mimetype,
297
+ fileSizeBytes: size,
298
+ # formatLibraryId: puid
299
+ }.cleanup
300
+ tech_data << GeneralFileCharacteristics.new(data) unless data.empty?
301
+ # Fixity
302
+ %w'MD5 SHA1 SHA256 SHA384 SHA512'.each do |checksum_type|
303
+ if (checksum = self.send("checksum_#{checksum_type}"))
304
+ data = {
305
+ fixityType: checksum_type,
306
+ fixityValue: checksum,
307
+ }.cleanup
308
+ tech_data << FileFixity.new(data) unless data.empty?
309
+ end
310
+ end
311
+ # Object characteristics
312
+ data = {
313
+ groupID: make_group_id
314
+ }.cleanup
315
+ tech_data << ObjectCharacteristics.new(data) unless data.empty?
316
+ # Preservation level
317
+ if preservation_levels
318
+ data_list = []
319
+ preservation_levels.each do |preservation_level|
320
+ data = {
321
+ preservationLevelValue: preservation_level[:value],
322
+ preservationLevelRole: preservation_level[:role],
323
+ preservationLevelRationale: preservation_level[:rationale],
324
+ preservationLevelDateAssigned: preservation_level[:date],
325
+ }.cleanup
326
+ data_list << OpenStruct.new(data) unless data.empty?
327
+ end
328
+ tech_data << PreservationLevel.new(array: data_list) unless data_list.empty?
329
+ end
330
+ # Inhibitor
331
+ if inhibitors
332
+ data_list = []
333
+ inhibitors.each do |inhibitor|
334
+ data = {
335
+ inhibitorType: inhibitor[:type],
336
+ inhibitorTarget: inhibitor[:target],
337
+ inhibitorKey: inhibitor[:key],
338
+ }.cleanup
339
+ data_list << OpenStruct.new(data) unless data.empty?
340
+ end
341
+ tech_data << Inhibitors.new(array: data_list) unless data_list.empty?
342
+ end
343
+ # Dependencies
344
+ if env_dependencies
345
+ data_list = []
346
+ env_dependencies.each do |dependency|
347
+ data = {
348
+ dependencyName: dependency[:name],
349
+ dependencyIdentifierType1: dependency[:type1],
350
+ dependencyIdentifierValue1: dependency[:value1],
351
+ dependencyIdentifierType2: dependency[:type2],
352
+ dependencyIdentifierValue2: dependency[:value2],
353
+ dependencyIdentifierType3: dependency[:type3],
354
+ dependencyIdentifierValue3: dependency[:value3],
355
+ }.cleanup
356
+ data_list << OpenStruct.new(data) unless data.empty?
357
+ end
358
+ tech_data << EnvironmentDependencies.new(array: data_list) unless data_list.empty?
359
+ end
360
+ # Hardware registry id
361
+ if hardware_ids
362
+ data_list = []
363
+ hardware_ids.each do |id|
364
+ data = {
365
+ registryId: id
366
+ }.cleanup
367
+ data_list << OpenStruct.new(data) unless data.empty?
368
+ end
369
+ tech_data << EnvHardwareRegistry.new(array: data_list) unless data_list.empty?
370
+ end
371
+ # Software registry id
372
+ if software_ids
373
+ data_list = []
374
+ software_ids.each do |id|
375
+ data = {
376
+ registryId: id
377
+ }.cleanup
378
+ data_list << OpenStruct.new(data) unless data.empty?
379
+ end
380
+ tech_data << EnvSoftwareRegistry.new(array: data_list) unless data_list.empty?
381
+ end
382
+ # Singatures
383
+ if signatures
384
+ data_list = []
385
+ signatures.each do |signature|
386
+ data = {
387
+ signatureInformationEncoding: signature[:encoding],
388
+ signer: signature[:signer],
389
+ signatureMethod: signature[:method],
390
+ signatureValue: signature[:value],
391
+ signatureValidationRules: signature[:rules],
392
+ signatureProperties: signature[:properties],
393
+ }.cleanup
394
+ data_list << OpenStruct.new(data) unless data.empty?
395
+ end
396
+ tech_data << SignatureInformation.new(array: data_list) unless data_list.empty?
397
+ end
398
+ # Hardware
399
+ if hardware_infos
400
+ data_list = []
401
+ hardware_infos.each do |hardware|
402
+ data = {
403
+ hardwareName: hardware[:name],
404
+ hardwareType: hardware[:type],
405
+ hardwareOtherInformation: hardware[:info],
406
+ }.cleanup
407
+ data_list << OpenStruct.new(data) unless data.empty?
408
+ end
409
+ tech_data << EnvironmentHardware.new(array: data_list) unless data_list.empty?
410
+ end
411
+ # Software
412
+ if software_infos
413
+ data_list = []
414
+ software_infos.each do |software|
415
+ data = {
416
+ softwareName: software[:name],
417
+ softwareVersion: software[:version],
418
+ softwareType: software[:type],
419
+ softwareOtherInformation: software[:info],
420
+ softwareDependancy: software[:dependency],
421
+ }.cleanup
422
+ data_list << OpenStruct.new(data) unless data.empty?
423
+ end
424
+ tech_data << EnvironmentSoftware.new(array: data_list) unless data_list.empty?
425
+ end
426
+ # Relationship
427
+ if relationship_infos
428
+ data_list = []
429
+ relationship_infos.each do |relationship|
430
+ data = {
431
+ relationshipType: relationship[:type],
432
+ relationshipSubType: relationship[:subtype],
433
+ relatedObjectIdentifierType1: relationship[:type1],
434
+ relatedObjectIdentifierValue1: relationship[:id1],
435
+ relatedObjectSequence1: relationship[:seq1],
436
+ relatedObjectIdentifierType2: relationship[:type2],
437
+ relatedObjectIdentifierValue2: relationship[:id2],
438
+ relatedObjectSequence2: relationship[:seq2],
439
+ relatedObjectIdentifierType3: relationship[:type3],
440
+ relatedObjectIdentifierValue3: relationship[:id3],
441
+ relatedObjectSequence3: relationship[:seq3],
442
+ }.cleanup
443
+ data_list << OpenStruct.new(data) unless data.empty?
444
+ end
445
+ tech_data << RelationShip.new(array: data_list) unless data_list.empty?
446
+ end
447
+ # Environment
448
+ if environments
449
+ data_list = []
450
+ environments.each do |environment|
451
+ data = {
452
+ environmentCharacteristic: environment[:characteristic],
453
+ environmentPurpose: environment[:purpose],
454
+ environmentNote: environment[:note],
455
+ }.cleanup
456
+ data_list << OpenStruct.new(data) unless data.empty?
457
+ end
458
+ tech_data << Environment.new(array: data_list) unless data_list.empty?
459
+ end
460
+ # Application
461
+ if applications
462
+ data_list = []
463
+ applications.each do |application|
464
+ data = {
465
+ creatingApplicationName: application[:name],
466
+ creatingApplicationVersion: application[:version],
467
+ dateCreatedByApplication: application[:date],
468
+ }.cleanup
469
+ data_list << OpenStruct.new(data) unless data.empty?
470
+ end
471
+ tech_data << CreatingApplication.new(array: data_list) unless data_list.empty?
472
+ end
473
+ # Finally assemble technical section
474
+ dnx[:tech] = tech_data unless tech_data.empty?
475
+ dnx
476
+ end
477
+
478
+ end
479
+
480
+ # Container class for creating a division in the METS.
481
+ class Div
482
+ include MetsObject
483
+ include Libis::Tools::ThreadSafe
484
+
485
+ attr_accessor :label
486
+
487
+ # The id that will be used in the XML file to reference this division.
488
+ def xml_id
489
+ "div-#{@id}"
490
+ end
491
+
492
+ # All items stored in the current division
493
+ def children
494
+ files + divs
495
+ end
496
+
497
+ # All file items stored in the current division
498
+ def files
499
+ self.mutex.synchronize do
500
+ @files ||= Array.new
501
+ end
502
+ end
503
+
504
+ # All division items stored in the current division
505
+ def divs
506
+ self.mutex.synchronize do
507
+ @divs ||= Array.new
508
+ end
509
+ end
510
+
511
+ # Add an item ({File} or {Div}) to the current division
512
+ def <<(obj)
513
+ self.mutex.synchronize do
514
+ case obj
515
+ when File
516
+ files << obj
517
+ when Div
518
+ divs << obj
519
+ else
520
+ raise RuntimeError, "Child object type not supported: #{obj.class}"
521
+ end
522
+ end
523
+ end
524
+
525
+ end
526
+
527
+ # Container class for creating a structmap in the METS.
528
+ class Map
529
+ include MetsObject
530
+
531
+ # The representation this structmap is for
532
+ attr_accessor :representation
533
+ # The top division in the structmap
534
+ attr_accessor :div
535
+ # Is the structmap Logical (true) or Physical(false)?
536
+ attr_accessor :is_logical
537
+
538
+ # The id that will be used in the XML file to reference this structmap.
539
+ def xml_id
540
+ "smap-#{@id}"
541
+ end
542
+
543
+ end
544
+
545
+ end
546
+ end
547
+ end