dor-services 2.2.4 → 4.4.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +15 -0
  2. data/bin/dor-indexer +108 -0
  3. data/bin/dor-indexerd +73 -0
  4. data/bin/nokogiri +19 -0
  5. data/bin/rake +19 -0
  6. data/bin/ruby_noexec_wrapper +14 -0
  7. data/bin/solrizer +19 -0
  8. data/bin/solrizerd +19 -0
  9. data/config/certs/README +1 -0
  10. data/config/config_defaults.yml +62 -0
  11. data/config/dev_console_env.rb.example +67 -0
  12. data/config/predicate_mappings.yml +55 -0
  13. data/lib/dor-services.rb +152 -19
  14. data/lib/dor/config.rb +133 -35
  15. data/lib/dor/datastreams/administrative_metadata_ds.rb +84 -0
  16. data/lib/dor/datastreams/content_metadata_ds.rb +337 -0
  17. data/lib/dor/datastreams/datastream_spec_solrizer.rb +18 -0
  18. data/lib/dor/datastreams/default_object_rights_ds.rb +52 -0
  19. data/lib/dor/datastreams/desc_metadata_ds.rb +39 -0
  20. data/lib/{datastreams → dor/datastreams}/embargo_metadata_ds.rb +25 -20
  21. data/lib/{datastreams → dor/datastreams}/events_ds.rb +14 -9
  22. data/lib/dor/datastreams/identity.xsl +8 -0
  23. data/lib/dor/datastreams/identity_metadata_ds.rb +112 -0
  24. data/lib/dor/datastreams/role_metadata_ds.rb +51 -0
  25. data/lib/dor/datastreams/simple_dublin_core_ds.rb +45 -0
  26. data/lib/dor/datastreams/version_metadata_ds.rb +214 -0
  27. data/lib/dor/datastreams/workflow_definition_ds.rb +113 -0
  28. data/lib/dor/datastreams/workflow_ds.rb +103 -0
  29. data/lib/dor/exceptions.rb +0 -1
  30. data/lib/dor/migrations/content_metadata_ds/change_content_type.rb +7 -0
  31. data/lib/dor/migrations/identifiable/assert_adminPolicy.rb +9 -0
  32. data/lib/dor/migrations/identifiable/fix_model_assertions.rb +13 -0
  33. data/lib/dor/migrations/identifiable/record_remediation.rb +18 -0
  34. data/lib/dor/migrations/identifiable/uriify_augmented_contentlocation_refs.rb +18 -0
  35. data/lib/dor/migrations/identifiable/uriify_contentlocation_refs.rb +18 -0
  36. data/lib/dor/migrations/processable/unify_workflows.rb +17 -0
  37. data/lib/dor/migrations/versionable/add_missing_version_md.rb +9 -0
  38. data/lib/dor/models/admin_policy_object.rb +16 -0
  39. data/lib/dor/models/assembleable.rb +14 -0
  40. data/lib/dor/models/collection.rb +14 -0
  41. data/lib/dor/models/contentable.rb +227 -0
  42. data/lib/dor/models/describable.rb +194 -0
  43. data/lib/dor/models/discoverable.rb +66 -0
  44. data/lib/dor/models/editable.rb +267 -0
  45. data/lib/dor/models/embargoable.rb +97 -0
  46. data/lib/dor/models/eventable.rb +12 -0
  47. data/lib/dor/models/governable.rb +162 -0
  48. data/lib/dor/models/identifiable.rb +211 -0
  49. data/lib/dor/models/item.rb +44 -0
  50. data/lib/dor/models/itemizable.rb +66 -0
  51. data/lib/dor/{mods2dc.xslt → models/mods2dc.xslt} +39 -12
  52. data/lib/dor/models/preservable.rb +50 -0
  53. data/lib/dor/models/processable.rb +229 -0
  54. data/lib/dor/models/publishable.rb +74 -0
  55. data/lib/dor/models/set.rb +12 -0
  56. data/lib/dor/models/shelvable.rb +27 -0
  57. data/lib/dor/models/upgradable.rb +74 -0
  58. data/lib/dor/models/versionable.rb +94 -0
  59. data/lib/dor/models/workflow_object.rb +54 -0
  60. data/lib/dor/services/cleanup_service.rb +47 -0
  61. data/lib/dor/services/digital_stacks_service.rb +55 -0
  62. data/lib/dor/services/merge_service.rb +96 -0
  63. data/lib/dor/{metadata_handlers → services/metadata_handlers}/catalog_handler.rb +0 -2
  64. data/lib/dor/{metadata_handlers → services/metadata_handlers}/mdtoolkit_handler.rb +0 -2
  65. data/lib/dor/{metadata_service.rb → services/metadata_service.rb} +1 -3
  66. data/lib/dor/services/registration_service.rb +181 -0
  67. data/lib/dor/services/sdr_ingest_service.rb +181 -0
  68. data/lib/dor/services/search_service.rb +131 -0
  69. data/lib/dor/services/suri_service.rb +32 -0
  70. data/lib/dor/services/technical_metadata_service.rb +226 -0
  71. data/lib/dor/{tei2dc.xslt → services/tei2dc.xslt} +0 -0
  72. data/lib/dor/utils/ng_tidy.rb +37 -0
  73. data/lib/dor/utils/predicate_patch.rb +23 -0
  74. data/lib/dor/utils/solr_doc_helper.rb +9 -0
  75. data/lib/dor/utils/utc_date_field_mapper.rb +7 -0
  76. data/lib/dor/version.rb +3 -0
  77. data/lib/dor/workflow/document.rb +131 -0
  78. data/lib/dor/workflow/graph.rb +166 -0
  79. data/lib/dor/workflow/process.rb +99 -0
  80. data/lib/gsearch/demoFoxmlToSolr.xslt +340 -122
  81. data/lib/tasks/dor.rake +39 -0
  82. metadata +494 -384
  83. data/lib/datastreams/content_metadata_ds.rb +0 -12
  84. data/lib/datastreams/identity_metadata_ds.rb +0 -28
  85. data/lib/datastreams/ng_tidy.rb +0 -19
  86. data/lib/datastreams/simple_dublin_core_ds.rb +0 -23
  87. data/lib/datastreams/workflow_definition_ds.rb +0 -105
  88. data/lib/datastreams/workflow_ds.rb +0 -16
  89. data/lib/dor/admin_policy_object.rb +0 -11
  90. data/lib/dor/base.rb +0 -81
  91. data/lib/dor/cleanup_service.rb +0 -32
  92. data/lib/dor/digital_stacks_service.rb +0 -82
  93. data/lib/dor/druid_utils.rb +0 -41
  94. data/lib/dor/embargo.rb +0 -41
  95. data/lib/dor/item.rb +0 -141
  96. data/lib/dor/provenance_metadata_service.rb +0 -65
  97. data/lib/dor/registration_service.rb +0 -87
  98. data/lib/dor/rsolr.rb +0 -27
  99. data/lib/dor/sdr_ingest_service.rb +0 -117
  100. data/lib/dor/search_service.rb +0 -86
  101. data/lib/dor/suri_service.rb +0 -37
  102. data/lib/dor/workflow_object.rb +0 -13
  103. data/lib/dor/workflow_service.rb +0 -111
  104. data/lib/xml_models/foxml.rb +0 -261
  105. data/lib/xml_models/identity_metadata/dublin_core.rb +0 -119
  106. data/lib/xml_models/identity_metadata/identity_metadata.rb +0 -288
@@ -1,12 +0,0 @@
1
- class ContentMetadataDS < ActiveFedora::NokogiriDatastream
2
-
3
- def public_xml
4
- result = self.ng_xml.clone
5
- result.xpath('/contentMetadata/resource[not(file[(@deliver="yes" or @publish="yes")])]').each { |n| n.remove }
6
- result.xpath('/contentMetadata/resource/file[not(@deliver="yes" or @publish="yes")]').each { |n| n.remove }
7
- result.xpath('/contentMetadata/resource/file').xpath('@preserve|@shelve|@publish|@deliver').each { |n| n.remove }
8
- result.xpath('/contentMetadata/resource/file/checksum').each { |n| n.remove }
9
- result
10
- end
11
-
12
- end
@@ -1,28 +0,0 @@
1
- class IdentityMetadataDS < ActiveFedora::NokogiriDatastream
2
-
3
- set_terminology do |t|
4
- t.root(:path=>"identityMetadata", :xmlns => '')
5
- t.objectId(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
6
- t.objectType(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
7
- t.objectLabel(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
8
- t.citationCreator(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
9
- t.sourceId(:index_as=>[:searchable, :displayable, :facetable, :sortable], :attributes=>{:type=>"source"}, :required=>:true, :type=>:string, :namespace_prefix => nil )
10
- t.otherId(:index_as=>[:searchable, :displayable, :facetable, :sortable], :attributes=>{:type=>"name"}, :required=>:true, :type=>:string, :namespace_prefix => nil )
11
- t.agreementId(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
12
- t.tag(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
13
- t.citationTitle(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
14
- t.objectCreator(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
15
- t.adminPolicy(:index_as=>[:searchable, :displayable, :facetable, :sortable], :required=>:true, :type=>:string, :namespace_prefix => nil )
16
- end
17
-
18
- def self.xml_template
19
- builder = Nokogiri::XML::Builder.new do |xml|
20
- xml.identityMetadata {
21
- xml.citationTitle
22
- xml.objectCreator
23
- }
24
- end
25
- return builder.doc
26
- end #self.xml_template
27
-
28
- end #class
@@ -1,19 +0,0 @@
1
- class Nokogiri::XML::Text
2
-
3
- def normalize
4
- self.content =~ /\S/ ? self.content.gsub(/\s+/,' ').strip : self.content
5
- end
6
-
7
- def normalize!
8
- self.content = self.normalize
9
- end
10
-
11
- end
12
-
13
- class Nokogiri::XML::Node
14
-
15
- def normalize_text!
16
- self.xpath('//text()').each { |t| t.normalize! }
17
- end
18
-
19
- end
@@ -1,23 +0,0 @@
1
- class SimpleDublinCoreDs < ActiveFedora::NokogiriDatastream
2
-
3
- set_terminology do |t|
4
- t.root(:path=>"dc", :xmlns=>"http://www.openarchives.org/OAI/2.0/oai_dc/", :schema=>"http://cosimo.stanford.edu/standards/oai_dc/v2/oai_dc.xsd", :namespace_prefix => 'oai_dc')
5
- t.title(:index_as=>[:searchable, :displayable, :facetable, :sortable], :xmlns => "http://purl.org/dc/elements/1.1/", :namespace_prefix => 'dc')
6
- t.creator(:index_as=>[:searchable, :displayable, :facetable, :sortable], :xmlns => "http://purl.org/dc/elements/1.1/", :namespace_prefix => 'dc')
7
- t.identifier(:index_as=>[:searchable, :displayable, :sortable], :xmlns => "http://purl.org/dc/elements/1.1/", :namespace_prefix => 'dc')
8
- end
9
-
10
- def self.xml_template
11
- builder = Nokogiri::XML::Builder.new do |xml|
12
- xml.dc(:xmlns=>"http://www.openarchives.org/OAI/2.0/oai_dc/",
13
- 'xmlns:dc'=>'http://purl.org/dc/elements/1.1/') {
14
- xml['dc'].title
15
- xml['dc'].creator
16
- xml['dc'].identifier
17
- }
18
- end
19
-
20
- return builder.doc
21
- end
22
-
23
- end
@@ -1,105 +0,0 @@
1
- class WorkflowProcess
2
-
3
- def initialize(workflow, node)
4
- @workflow = workflow
5
- @node = node
6
- end
7
-
8
- def name
9
- @node['name']
10
- end
11
-
12
- def sequence
13
- @node['sequence']
14
- end
15
-
16
- def lifecycle
17
- @node['lifecycle']
18
- end
19
-
20
- def label
21
- @node.at_xpath('label/text()').to_s
22
- end
23
-
24
- def prerequisites
25
- @node.xpath('prereq').collect do |p|
26
- if (p['repository'].nil? and p['workflow'].nil?) or (p['repository'] == workflow.repository and p['workflow'] == workflow.name)
27
- p.text.to_s
28
- else
29
- [(p['repository'] or workflow.repository),(p['workflow'] or workflow.name),p.text.to_s].join(':')
30
- end
31
- end
32
- end
33
-
34
- end
35
-
36
- class WorkflowDefinitionDs < ActiveFedora::NokogiriDatastream
37
-
38
- define_template :process do |builder,workflow,name,seq,label,lifecycle,prereqs|
39
- attrs = {:name => name}
40
- attrs[:sequence] = seq unless seq.nil?
41
- attrs[:lifecycle] = lifecycle unless lifecycle.nil?
42
- builder.process(attrs) do |node|
43
- prereqs.each do |prereq|
44
- (repo,wf,prereq_name) = prereq.split(/:/)
45
- if prereq_name.nil?
46
- prereq_name = repo
47
- repo = nil
48
- end
49
- if (repo == workflow.repository and wf = workflow.name)
50
- repo = nil
51
- wf = nil
52
- end
53
- attrs = (repo.nil? and wf.nil?) ? {} : { :repository => repo, :workflow => wf }
54
- node.prereq(attrs) { node.text prereq_name }
55
- end
56
- end
57
- end
58
-
59
- def add_process(name, seq, label, lifecycle, prereqs)
60
- add_child_node(ng_xml.at_xpath('/workflow'), :process, self, name, seq, label, lifecycle, prereqs)
61
- end
62
-
63
- def processes
64
- ng_xml.xpath('/workflow/process').collect do |node|
65
- WorkflowProcess.new(self, node)
66
- end
67
- end
68
-
69
- def name
70
- ng_xml.at_xpath('/workflow/@id').to_s
71
- end
72
-
73
- def repository
74
- ng_xml.at_xpath('/workflow/@repository').to_s
75
- end
76
-
77
- def configuration
78
- result = {
79
- 'repository' => repository,
80
- 'name' => name
81
- }
82
- processes.each_pair do |process_name,process|
83
- result[process_name] = {
84
- 'prerequisites' => process.prerequisites.collect { |p| p.name }
85
- }
86
- end
87
- end
88
-
89
- def configuration=(hash)
90
- ng_xml = Nokogiri::XML(%{<workflow id="#{hash['name']}" repository="#{hash['repository']}"/>})
91
- i = 0
92
- hash.each_pair do |k,v|
93
- if v.is_a?(Hash)
94
- add_process(k,i+=1,nil,nil,v['prerequisite'])
95
- end
96
- end
97
- end
98
-
99
- def to_yaml
100
- s = StringIO.new('')
101
- YAML.dump(self.configuration, s)
102
- s.string
103
- end
104
-
105
- end
@@ -1,16 +0,0 @@
1
- class WorkflowDs < ActiveFedora::NokogiriDatastream
2
-
3
- set_terminology do |t|
4
- t.root(:path=>"workflow", :xmlns => '', :namespace_prefix => nil)
5
- t.workflowId(:path=>{:attribute => "id"}, :index_as => [:displayable, :facetable])
6
- t.process(:path=>'process', :namespace_prefix => nil) {
7
- t._name(:path=>{:attribute=>"name"}, :index_as => [:displayable, :facetable, :sortable])
8
- t.status(:path=>{:attribute=>"status"}, :index_as => [:displayable, :facetable, :sortable])
9
- t.timestamp(:path=>{:attribute=>"datetime"}, :index_as => [:searchable, :sortable])
10
- t.elapsed(:path=>{:attribute=>"elapsed"})
11
- t.lifecycle(:path=>{:attribute=>"lifecycle"}, :index_as => [:displayable, :facetable, :sortable])
12
- t.attempts(:path=>{:attribute=>"attempts"})
13
- }
14
- end
15
-
16
- end
@@ -1,11 +0,0 @@
1
- module Dor
2
-
3
- class AdminPolicyObject < Base
4
-
5
- has_metadata :name => "administrativeMetadata", :type => ActiveFedora::NokogiriDatastream
6
- has_metadata :name => "roleMetadata", :type => ActiveFedora::NokogiriDatastream
7
- has_metadata :name => "defaultObjectRights", :type => ActiveFedora::NokogiriDatastream
8
-
9
- end
10
-
11
- end
@@ -1,81 +0,0 @@
1
- require 'active_fedora'
2
- require 'datastreams/identity_metadata_ds'
3
- require 'datastreams/simple_dublin_core_ds'
4
- require 'datastreams/workflow_ds'
5
- require 'dor/suri_service'
6
-
7
- module Dor
8
-
9
- class Base < ::ActiveFedora::Base
10
-
11
- attr_reader :workflows
12
-
13
- has_metadata :name => "DC", :type => SimpleDublinCoreDs
14
- has_metadata :name => "RELS-EXT", :type => ActiveFedora::RelsExtDatastream
15
- has_metadata :name => "identityMetadata", :type => IdentityMetadataDS
16
-
17
- # Make a random (and harmless) API-M call to get gsearch to reindex the object
18
- def self.touch(*pids)
19
- client = Dor::Config.fedora.client
20
- pids.collect { |pid|
21
- response = client["objects/#{pid}/datastreams/DC?dsState=A&ignoreContent=true"].put('', :content_type => 'text/xml')
22
- response.code
23
- }
24
- end
25
-
26
- def self.get_foxml(pid, interpolate_refs = false)
27
- foxml = Nokogiri::XML(Dor::Config.fedora.client["objects/#{pid}/objectXML"].get)
28
- if interpolate_refs
29
- external_refs = foxml.xpath('//foxml:contentLocation[contains(@REF,"/workflows/")]')
30
- external_refs.each do |ref|
31
- begin
32
- external_doc = Nokogiri::XML(RestClient.get(ref['REF']))
33
- external_root = external_doc.root
34
- ref.replace('<foxml:xmlContent/>').first.add_child(external_doc.root)
35
- external_root.traverse { |node| node.namespace = nil }
36
- rescue
37
- ref.remove
38
- end
39
- end
40
- end
41
- return foxml
42
- end
43
-
44
- def initialize(attrs = {})
45
- unless attrs[:pid]
46
- attrs = attrs.merge!({:pid=>Dor::SuriService.mint_id})
47
- @new_object=true
48
- else
49
- @new_object = attrs[:new_object] == false ? false : true
50
- end
51
- @inner_object = Fedora::FedoraObject.new(attrs)
52
- @datastreams = {}
53
- @workflows = {}
54
- configure_defined_datastreams
55
- end
56
-
57
- def identity_metadata
58
- if self.datastreams.has_key?('identityMetadata')
59
- IdentityMetadata.from_xml(self.datastreams['identityMetadata'].content)
60
- else
61
- nil
62
- end
63
- end
64
-
65
- # Self-aware datastream builders
66
- def build_datastream(datastream, force = false)
67
- ds = datastreams[datastream]
68
- if force or ds.new_object? or (ds.content.to_s.empty?)
69
- proc = "build_#{datastream}_datastream".to_sym
70
- content = self.send(proc, ds)
71
- ds.save
72
- end
73
- return ds
74
- end
75
-
76
- def reindex
77
- Dor::SearchService.reindex(self.pid)
78
- end
79
-
80
- end
81
- end
@@ -1,32 +0,0 @@
1
- require 'fileutils'
2
- require 'lyber-utils'
3
-
4
- module Dor
5
- class CleanupService
6
- Config.declare(:cleanup) do
7
- local_workspace_root '/dor/workspace'
8
- local_export_home '/dor/export'
9
- end
10
-
11
- # Delete all workspace and export entities for the druid
12
- # @param [LyberCore::Robots::WorkItem]
13
- def self.cleanup(dor_item)
14
- druid = dor_item.pid
15
- workspace_dir = Druid.new(druid).path(Config.cleanup.local_workspace_root)
16
- self.remove_entry(workspace_dir)
17
- bag_dir = File.join(Config.cleanup.local_export_home, druid)
18
- self.remove_entry(bag_dir)
19
- tarfile = "#{bag_dir}.tar"
20
- self.remove_entry(tarfile)
21
- end
22
-
23
- # Deleta a filesystem entry
24
- # @param [String]
25
- def self.remove_entry(entry)
26
- FileUtils.remove_entry(entry) if File.exist?(entry)
27
- end
28
-
29
-
30
- end
31
-
32
- end
@@ -1,82 +0,0 @@
1
- require 'tempfile'
2
- require 'systemu'
3
-
4
- module Dor
5
- class DigitalStacksService
6
-
7
- Config.declare(:stacks) do
8
- document_cache_storage_root nil
9
- document_cache_host nil
10
- document_cache_user nil
11
-
12
- storage_root '/stacks'
13
- host nil
14
- user nil
15
-
16
- local_workspace_root '/dor'
17
- end
18
-
19
- # TODO copied from lyber-core, but didn't want to create circular dependency for between gems for this one method
20
- # Executes a system command in a subprocess.
21
- # The method will return stdout from the command if execution was successful.
22
- # The method will raise an exception if if execution fails.
23
- # The exception's message will contain the explaination of the failure.
24
- # @param [String] command the command to be executed
25
- # @return [String] stdout from the command if execution was successful
26
- def self.execute(command)
27
- status, stdout, stderr = systemu(command)
28
- if (status.exitstatus != 0)
29
- raise stderr
30
- end
31
- return stdout
32
- rescue
33
- msg = "Command failed to execute: [#{command}] caused by <STDERR =\n#{stderr.split($/).join("\n")}>"
34
- msg << "\nSTDOUT =\n#{stdout.split($/).join("\n")}" if (stdout && (stdout.length > 0))
35
- raise msg
36
- end
37
-
38
- def self.druid_tree(druid)
39
- Druid.new(druid).path
40
- rescue
41
- nil
42
- end
43
-
44
- def self.transfer_to_document_store(id, content, filename)
45
- path = self.druid_tree(id)
46
- raise "Invalid druid: #{id}" if(path.nil?)
47
-
48
- # create the remote directory in the document cache
49
- remote_document_cache_dir = File.join(Config.stacks.document_cache_storage_root, path)
50
- command = "ssh #{Config.stacks.document_cache_user}@#{Config.stacks.document_cache_host} mkdir -p #{remote_document_cache_dir}"
51
- self.execute(command)
52
-
53
- # create a temp file containing the content and copy the contents to the remote document cache
54
- Tempfile.open(filename) do |tf|
55
- tf.write(content)
56
- tf.flush
57
- command = "scp \"#{tf.path}\" #{Config.stacks.document_cache_user}@#{Config.stacks.document_cache_host}:#{remote_document_cache_dir}/#{filename}"
58
- self.execute(command)
59
- end
60
- end
61
-
62
- def self.shelve_to_stacks(id, files)
63
- path = self.druid_tree(id)
64
- raise "Invalid druid: #{id}" if(path.nil?)
65
-
66
- # create the remote directory on the digital stacks
67
- remote_storage_dir = File.join(Config.stacks.storage_root, path)
68
- command = "ssh #{Config.stacks.user}@#{Config.stacks.host} mkdir -p #{remote_storage_dir}"
69
- self.execute(command)
70
-
71
- # copy the contents for the given object from the local workspace directory to the remote directory
72
- local_storage_dir = File.join(Config.stacks.local_workspace_root, path)
73
- files.each do |file|
74
- command = "scp \"#{local_storage_dir}/#{file}\" #{Config.stacks.user}@#{Config.stacks.host}:#{remote_storage_dir}"
75
- self.execute(command)
76
- end
77
- end
78
-
79
- end
80
-
81
- end
82
-
@@ -1,41 +0,0 @@
1
- class Druid
2
- attr_accessor :druid
3
-
4
- DRUID_PATTERN = /^(?:druid:)?([a-z]{2})(\d{3})([a-z]{2})(\d{4})$/
5
- def initialize(druid)
6
- if druid !~ DRUID_PATTERN
7
- raise ArgumentError, "Invalid DRUID: #{druid}"
8
- end
9
- @druid = druid
10
- end
11
-
12
- def id
13
- @druid.scan(/^(?:druid:)?(.+)$/).flatten.last
14
- end
15
-
16
- def tree
17
- @druid.scan(DRUID_PATTERN).flatten
18
- end
19
-
20
- def path(base=nil)
21
- File.join(*([base,tree].compact))
22
- end
23
-
24
- def mkdir(base)
25
- FileUtils.mkdir_p(path(base))
26
- end
27
-
28
- def rmdir(base)
29
- parts = tree
30
- while parts.length > 0
31
- dir = File.join(base, *parts)
32
- begin
33
- FileUtils.rm(File.join(dir,'.DS_Store'), :force => true)
34
- FileUtils.rmdir(dir)
35
- rescue Errno::ENOTEMPTY
36
- break
37
- end
38
- parts.pop
39
- end
40
- end
41
- end