libis-tools 1.0.5-java

Sign up to get free protection for your applications and to get access to all the features.
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