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.
- checksums.yaml +15 -0
- data/bin/dor-indexer +108 -0
- data/bin/dor-indexerd +73 -0
- data/bin/nokogiri +19 -0
- data/bin/rake +19 -0
- data/bin/ruby_noexec_wrapper +14 -0
- data/bin/solrizer +19 -0
- data/bin/solrizerd +19 -0
- data/config/certs/README +1 -0
- data/config/config_defaults.yml +62 -0
- data/config/dev_console_env.rb.example +67 -0
- data/config/predicate_mappings.yml +55 -0
- data/lib/dor-services.rb +152 -19
- data/lib/dor/config.rb +133 -35
- data/lib/dor/datastreams/administrative_metadata_ds.rb +84 -0
- data/lib/dor/datastreams/content_metadata_ds.rb +337 -0
- data/lib/dor/datastreams/datastream_spec_solrizer.rb +18 -0
- data/lib/dor/datastreams/default_object_rights_ds.rb +52 -0
- data/lib/dor/datastreams/desc_metadata_ds.rb +39 -0
- data/lib/{datastreams → dor/datastreams}/embargo_metadata_ds.rb +25 -20
- data/lib/{datastreams → dor/datastreams}/events_ds.rb +14 -9
- data/lib/dor/datastreams/identity.xsl +8 -0
- data/lib/dor/datastreams/identity_metadata_ds.rb +112 -0
- data/lib/dor/datastreams/role_metadata_ds.rb +51 -0
- data/lib/dor/datastreams/simple_dublin_core_ds.rb +45 -0
- data/lib/dor/datastreams/version_metadata_ds.rb +214 -0
- data/lib/dor/datastreams/workflow_definition_ds.rb +113 -0
- data/lib/dor/datastreams/workflow_ds.rb +103 -0
- data/lib/dor/exceptions.rb +0 -1
- data/lib/dor/migrations/content_metadata_ds/change_content_type.rb +7 -0
- data/lib/dor/migrations/identifiable/assert_adminPolicy.rb +9 -0
- data/lib/dor/migrations/identifiable/fix_model_assertions.rb +13 -0
- data/lib/dor/migrations/identifiable/record_remediation.rb +18 -0
- data/lib/dor/migrations/identifiable/uriify_augmented_contentlocation_refs.rb +18 -0
- data/lib/dor/migrations/identifiable/uriify_contentlocation_refs.rb +18 -0
- data/lib/dor/migrations/processable/unify_workflows.rb +17 -0
- data/lib/dor/migrations/versionable/add_missing_version_md.rb +9 -0
- data/lib/dor/models/admin_policy_object.rb +16 -0
- data/lib/dor/models/assembleable.rb +14 -0
- data/lib/dor/models/collection.rb +14 -0
- data/lib/dor/models/contentable.rb +227 -0
- data/lib/dor/models/describable.rb +194 -0
- data/lib/dor/models/discoverable.rb +66 -0
- data/lib/dor/models/editable.rb +267 -0
- data/lib/dor/models/embargoable.rb +97 -0
- data/lib/dor/models/eventable.rb +12 -0
- data/lib/dor/models/governable.rb +162 -0
- data/lib/dor/models/identifiable.rb +211 -0
- data/lib/dor/models/item.rb +44 -0
- data/lib/dor/models/itemizable.rb +66 -0
- data/lib/dor/{mods2dc.xslt → models/mods2dc.xslt} +39 -12
- data/lib/dor/models/preservable.rb +50 -0
- data/lib/dor/models/processable.rb +229 -0
- data/lib/dor/models/publishable.rb +74 -0
- data/lib/dor/models/set.rb +12 -0
- data/lib/dor/models/shelvable.rb +27 -0
- data/lib/dor/models/upgradable.rb +74 -0
- data/lib/dor/models/versionable.rb +94 -0
- data/lib/dor/models/workflow_object.rb +54 -0
- data/lib/dor/services/cleanup_service.rb +47 -0
- data/lib/dor/services/digital_stacks_service.rb +55 -0
- data/lib/dor/services/merge_service.rb +96 -0
- data/lib/dor/{metadata_handlers → services/metadata_handlers}/catalog_handler.rb +0 -2
- data/lib/dor/{metadata_handlers → services/metadata_handlers}/mdtoolkit_handler.rb +0 -2
- data/lib/dor/{metadata_service.rb → services/metadata_service.rb} +1 -3
- data/lib/dor/services/registration_service.rb +181 -0
- data/lib/dor/services/sdr_ingest_service.rb +181 -0
- data/lib/dor/services/search_service.rb +131 -0
- data/lib/dor/services/suri_service.rb +32 -0
- data/lib/dor/services/technical_metadata_service.rb +226 -0
- data/lib/dor/{tei2dc.xslt → services/tei2dc.xslt} +0 -0
- data/lib/dor/utils/ng_tidy.rb +37 -0
- data/lib/dor/utils/predicate_patch.rb +23 -0
- data/lib/dor/utils/solr_doc_helper.rb +9 -0
- data/lib/dor/utils/utc_date_field_mapper.rb +7 -0
- data/lib/dor/version.rb +3 -0
- data/lib/dor/workflow/document.rb +131 -0
- data/lib/dor/workflow/graph.rb +166 -0
- data/lib/dor/workflow/process.rb +99 -0
- data/lib/gsearch/demoFoxmlToSolr.xslt +340 -122
- data/lib/tasks/dor.rake +39 -0
- metadata +494 -384
- data/lib/datastreams/content_metadata_ds.rb +0 -12
- data/lib/datastreams/identity_metadata_ds.rb +0 -28
- data/lib/datastreams/ng_tidy.rb +0 -19
- data/lib/datastreams/simple_dublin_core_ds.rb +0 -23
- data/lib/datastreams/workflow_definition_ds.rb +0 -105
- data/lib/datastreams/workflow_ds.rb +0 -16
- data/lib/dor/admin_policy_object.rb +0 -11
- data/lib/dor/base.rb +0 -81
- data/lib/dor/cleanup_service.rb +0 -32
- data/lib/dor/digital_stacks_service.rb +0 -82
- data/lib/dor/druid_utils.rb +0 -41
- data/lib/dor/embargo.rb +0 -41
- data/lib/dor/item.rb +0 -141
- data/lib/dor/provenance_metadata_service.rb +0 -65
- data/lib/dor/registration_service.rb +0 -87
- data/lib/dor/rsolr.rb +0 -27
- data/lib/dor/sdr_ingest_service.rb +0 -117
- data/lib/dor/search_service.rb +0 -86
- data/lib/dor/suri_service.rb +0 -37
- data/lib/dor/workflow_object.rb +0 -13
- data/lib/dor/workflow_service.rb +0 -111
- data/lib/xml_models/foxml.rb +0 -261
- data/lib/xml_models/identity_metadata/dublin_core.rb +0 -119
- data/lib/xml_models/identity_metadata/identity_metadata.rb +0 -288
File without changes
|
@@ -0,0 +1,37 @@
|
|
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
|
20
|
+
|
21
|
+
class Nokogiri::XML::Document
|
22
|
+
|
23
|
+
def prettify
|
24
|
+
xslt = Nokogiri::XSLT <<-EOC
|
25
|
+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
26
|
+
<xsl:output omit-xml-declaration="yes" indent="yes"/>
|
27
|
+
<xsl:template match="node()|@*">
|
28
|
+
<xsl:copy>
|
29
|
+
<xsl:apply-templates select="node()|@*"/>
|
30
|
+
</xsl:copy>
|
31
|
+
</xsl:template>
|
32
|
+
</xsl:stylesheet>
|
33
|
+
EOC
|
34
|
+
xslt.transform(self).to_xml
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Monkey patch ActiveFedora::RelsExtDatastream.short_predicate to
|
2
|
+
# create missing mappings on the fly.
|
3
|
+
|
4
|
+
module ActiveFedora
|
5
|
+
class RelsExtDatastream
|
6
|
+
def self.short_predicate(predicate)
|
7
|
+
# for this regex to short-circuit correctly, namespaces must be sorted into descending order by length
|
8
|
+
if match = /^(#{Predicates.predicate_mappings.keys.sort.reverse.join('|')})(.+)$/.match(predicate.to_str)
|
9
|
+
namespace = match[1]
|
10
|
+
predicate = match[2]
|
11
|
+
ns_mapping = Predicates.predicate_mappings[namespace] ||= {}
|
12
|
+
pred = ns_mapping.invert[predicate]
|
13
|
+
if pred.nil?
|
14
|
+
pred = predicate.underscore.to_sym
|
15
|
+
ns_mapping[pred] = predicate
|
16
|
+
end
|
17
|
+
pred
|
18
|
+
else
|
19
|
+
raise "Unable to parse predicate: #{predicate}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module SolrDocHelper
|
2
|
+
|
3
|
+
def add_solr_value(solr_doc, field_name, value, field_type = :default, index_types = [:searchable])
|
4
|
+
index_types.each { |index_type|
|
5
|
+
::Solrizer::Extractor.insert_solr_field_value(solr_doc, ::ActiveFedora::SolrService.solr_name(field_name, field_type, index_type), value)
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
data/lib/dor/version.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
module Dor
|
2
|
+
module Workflow
|
3
|
+
class Document
|
4
|
+
include SolrDocHelper
|
5
|
+
include OM::XML::Document
|
6
|
+
|
7
|
+
set_terminology do |t|
|
8
|
+
t.root(:path => 'workflow')
|
9
|
+
t.repository(:path=>{:attribute => "repository"})
|
10
|
+
t.workflowId(:path=>{:attribute => "id"})
|
11
|
+
t.process {
|
12
|
+
t.name_(:path=>{:attribute=>"name"})
|
13
|
+
t.status(:path=>{:attribute=>"status"})
|
14
|
+
t.timestamp(:path=>{:attribute=>"datetime"})#, :data_type => :date)
|
15
|
+
t.elapsed(:path=>{:attribute=>"elapsed"})
|
16
|
+
t.lifecycle(:path=>{:attribute=>"lifecycle"})
|
17
|
+
t.attempts(:path=>{:attribute=>"attempts"}, :index_as => [:not_searchable])
|
18
|
+
}
|
19
|
+
end
|
20
|
+
@@definitions={}
|
21
|
+
def initialize node
|
22
|
+
self.ng_xml = Nokogiri::XML(node)
|
23
|
+
end
|
24
|
+
#is this an incomplete workflow with steps that have a priority > 0
|
25
|
+
def expedited?
|
26
|
+
processes.any? { |proc| !proc.completed? && proc.priority.to_i > 0 }
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Integer] value of the first > 0 priority. Defaults to 0
|
30
|
+
def priority
|
31
|
+
processes.map {|proc| proc.priority.to_i }.detect(0) {|p| p > 0}
|
32
|
+
end
|
33
|
+
|
34
|
+
def active?
|
35
|
+
processes.any? { |proc| !proc.version }
|
36
|
+
end
|
37
|
+
|
38
|
+
def definition
|
39
|
+
@definition ||= begin
|
40
|
+
if @@definitions.has_key? self.workflowId.first
|
41
|
+
@@definitions[self.workflowId.first]
|
42
|
+
else
|
43
|
+
wfo = Dor::WorkflowObject.find_by_name(self.workflowId.first)
|
44
|
+
wf_def=wfo ? wfo.definition : nil
|
45
|
+
@@definitions[self.workflowId.first] = wf_def
|
46
|
+
wf_def
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def graph(parent=nil, dir=nil)
|
52
|
+
wf_definition = self.definition
|
53
|
+
result = wf_definition ? Workflow::Graph.from_processes(wf_definition.repo, wf_definition.name, self.processes, parent) : nil
|
54
|
+
unless result.nil?
|
55
|
+
result['rankdir'] = dir || 'TB'
|
56
|
+
end
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
def [](value)
|
61
|
+
self.processes.find { |p| p.name == value }
|
62
|
+
end
|
63
|
+
|
64
|
+
def processes
|
65
|
+
#if the workflow service didnt return any processes, dont return any processes from the reified wf
|
66
|
+
if ng_xml.search("/workflow/process").length == 0
|
67
|
+
return []
|
68
|
+
end
|
69
|
+
@processes ||= if self.definition
|
70
|
+
self.definition.processes.collect do |process|
|
71
|
+
node = ng_xml.at("/workflow/process[@name = '#{process.name}']")
|
72
|
+
process.update!(node,self) unless node.nil?
|
73
|
+
process
|
74
|
+
end
|
75
|
+
else
|
76
|
+
self.find_by_terms(:workflow, :process).collect do |x|
|
77
|
+
pnode = Dor::Workflow::Process.new(self.repository, self.workflowId, {})
|
78
|
+
pnode.update!(x,self)
|
79
|
+
pnode
|
80
|
+
end.sort_by(&:datetime)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_solr(solr_doc=Hash.new, *args)
|
85
|
+
wf_name = self.workflowId.first
|
86
|
+
repo=self.repository.first
|
87
|
+
add_solr_value(solr_doc, 'wf', wf_name, :string, [:facetable])
|
88
|
+
add_solr_value(solr_doc, 'wf_wps', wf_name, :string, [:facetable])
|
89
|
+
add_solr_value(solr_doc, 'wf_wsp', wf_name, :string, [:facetable])
|
90
|
+
status = processes.empty? ? 'empty' : (processes.all?(&:completed?) ? 'completed' : 'active')
|
91
|
+
errors = processes.select(&:error?).count
|
92
|
+
add_solr_value(solr_doc, 'workflow_status', [wf_name,status,errors,repo].join('|'), :string, [:displayable])
|
93
|
+
|
94
|
+
processes.each do |process|
|
95
|
+
if process.status.present?
|
96
|
+
#add a record of the robot having operated on this item, so we can track robot activity
|
97
|
+
if process.date_time and process.status and (process.status == 'completed' || process.status == 'error')
|
98
|
+
add_solr_value(solr_doc, "wf_#{wf_name}_#{process.name}", process.date_time+'Z', :date)
|
99
|
+
end
|
100
|
+
add_solr_value(solr_doc, 'wf_error', "#{wf_name}:#{process.name}:#{process.error_message}", :string, [:facetable,:displayable]) if process.error_message #index the error message without the druid so we hopefully get some overlap
|
101
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}", :string, [:facetable])
|
102
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.status}:#{process.name}", :string, [:facetable])
|
103
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}", :string, [:facetable])
|
104
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.status}", :string, [:facetable])
|
105
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}", :string, [:facetable])
|
106
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}", :string, [:facetable])
|
107
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.status}:#{wf_name}:#{process.name}", :string, [:facetable])
|
108
|
+
if process.state != process.status
|
109
|
+
add_solr_value(solr_doc, 'wf_wsp', "#{wf_name}:#{process.state}:#{process.name}", :string, [:facetable])
|
110
|
+
add_solr_value(solr_doc, 'wf_wps', "#{wf_name}:#{process.name}:#{process.state}", :string, [:facetable])
|
111
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}", :string, [:facetable])
|
112
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}", :string, [:facetable])
|
113
|
+
add_solr_value(solr_doc, 'wf_swp', "#{process.state}:#{wf_name}:#{process.name}", :string, [:facetable])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
solr_doc['wf_wps_facet'].uniq! if solr_doc['wf_wps_facet']
|
119
|
+
solr_doc['wf_wsp_facet'].uniq! if solr_doc['wf_wsp_facet']
|
120
|
+
solr_doc['wf_swp_facet'].uniq! if solr_doc['wf_swp_facet']
|
121
|
+
solr_doc['workflow_status'].uniq! if solr_doc['workflow_status']
|
122
|
+
|
123
|
+
solr_doc
|
124
|
+
end
|
125
|
+
|
126
|
+
def inspect
|
127
|
+
"#<#{self.class.name}:#{self.object_id}>"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'graphviz'
|
2
|
+
|
3
|
+
module Dor
|
4
|
+
module Workflow
|
5
|
+
class Graph
|
6
|
+
|
7
|
+
FILL_COLORS = { 'waiting' => "white", 'ready' => "white", 'error' => "#8B0000", 'blocked' => "white", 'completed' => "darkgreen", 'unknown' => "#CFCFCF" }
|
8
|
+
TEXT_COLORS = { 'waiting' => "black", 'ready' => "black", 'error' => "white", 'blocked' => "#8B0000", 'completed' => "white", 'unknown' => "black" }
|
9
|
+
PATTERNS = { 'waiting' => "diagonals", 'ready' => "filled", 'error' => "filled", 'blocked' => "diagonals", 'completed' => "filled", 'unknown' => "filled" }
|
10
|
+
RESERVED_KEYS = ['repository','name']
|
11
|
+
|
12
|
+
attr_reader :repo, :name, :processes, :graph, :root
|
13
|
+
|
14
|
+
def self.from_config(name, config, parent = nil)
|
15
|
+
wf = self.new(config['repository'], name, parent)
|
16
|
+
config.keys.each { |p| wf.add_process(p.to_s) unless RESERVED_KEYS.include?(p) }
|
17
|
+
config.keys.each { |p|
|
18
|
+
if wf.processes[p]
|
19
|
+
Array(config[p]['prerequisite']).each { |prereq|
|
20
|
+
prereq.sub!(/^#{config['repository']}:#{name}:/e,'')
|
21
|
+
if wf.processes[prereq]
|
22
|
+
wf.processes[p].depends_on(wf.processes[prereq])
|
23
|
+
else
|
24
|
+
wf.processes[p].depends_on(wf.add_process(prereq).set_status('external'))
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
}
|
29
|
+
wf.finish
|
30
|
+
return wf
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.from_processes(repo, name, processes, parent = nil)
|
34
|
+
wf = self.new(repo, name, parent)
|
35
|
+
processes.each { |p|
|
36
|
+
wf.add_process(p.name).status = p.state || 'unknown'
|
37
|
+
}
|
38
|
+
processes.each { |p|
|
39
|
+
p.prerequisite.each { |prereq|
|
40
|
+
prereq.sub!(/^#{repo}:#{name}:/e,'')
|
41
|
+
if wf.processes[prereq]
|
42
|
+
wf.processes[p.name].depends_on(wf.processes[prereq])
|
43
|
+
else
|
44
|
+
wf.processes[p.name].depends_on(wf.add_process(prereq).set_status('external'))
|
45
|
+
end
|
46
|
+
}
|
47
|
+
}
|
48
|
+
wf.finish
|
49
|
+
return wf
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(repo, name, parent = nil)
|
53
|
+
@repo = repo
|
54
|
+
@name = name
|
55
|
+
if parent.nil?
|
56
|
+
@graph = GraphViz.new(qname)
|
57
|
+
@root = self.add_nodes(name)
|
58
|
+
else
|
59
|
+
@graph = parent.subgraph(qname)
|
60
|
+
@root = parent.add_nodes(name)
|
61
|
+
end
|
62
|
+
@graph[:truecolor => true]
|
63
|
+
@root.shape = 'plaintext'
|
64
|
+
@processes = {}
|
65
|
+
end
|
66
|
+
|
67
|
+
def qname
|
68
|
+
[@repo,@name].join(':')
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_process(name, external = false)
|
72
|
+
pqname = name.split(/:/).length == 3 ? name : [qname,name].join(':')
|
73
|
+
p = Process.new(self, pqname, name)
|
74
|
+
@processes[name] = p
|
75
|
+
return p
|
76
|
+
end
|
77
|
+
|
78
|
+
def finish
|
79
|
+
@processes.values.each do |process|
|
80
|
+
process.node.fontname = 'Helvetica'
|
81
|
+
if process.id =~ %r{^#{qname}} and process.prerequisites.length == 0
|
82
|
+
(@root << process.node)[:arrowhead => 'none', :arrowtail => 'none', :dir => 'both', :style => 'invisible']
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
@root.fontname = 'Helvetica'
|
87
|
+
return self
|
88
|
+
end
|
89
|
+
|
90
|
+
def inspect
|
91
|
+
"#{self.to_s[0..-2]} #{repo}:#{name} (#{processes.keys.join(', ')})>"
|
92
|
+
end
|
93
|
+
|
94
|
+
def method_missing(sym,*args)
|
95
|
+
if @graph.respond_to?(sym)
|
96
|
+
@graph.send(sym,*args)
|
97
|
+
else
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Process
|
103
|
+
|
104
|
+
attr_reader :name, :status, :node, :prerequisites
|
105
|
+
|
106
|
+
def initialize(graph, id, name)
|
107
|
+
@name = name
|
108
|
+
@graph = graph
|
109
|
+
@node = @graph.add_nodes(id)
|
110
|
+
@node.shape = 'box'
|
111
|
+
@node.label = name
|
112
|
+
@prerequisites = []
|
113
|
+
self.set_status('unknown')
|
114
|
+
end
|
115
|
+
|
116
|
+
def id
|
117
|
+
@node.id
|
118
|
+
end
|
119
|
+
|
120
|
+
def status=(s)
|
121
|
+
@status = s
|
122
|
+
if s == 'external'
|
123
|
+
@node.fillcolor = "gray"
|
124
|
+
@node.fontcolor = "black"
|
125
|
+
@node.style = "dashed"
|
126
|
+
else
|
127
|
+
@node.fillcolor = FILL_COLORS[s] || "yellow"
|
128
|
+
@node.fontcolor = TEXT_COLORS[s]
|
129
|
+
@node.style = PATTERNS[s]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def set_status(s)
|
134
|
+
self.status = s
|
135
|
+
return self
|
136
|
+
end
|
137
|
+
|
138
|
+
def depends_on(*processes)
|
139
|
+
wf1 = self.id.split(/:/)[0..1].join(':')
|
140
|
+
processes.each { |process|
|
141
|
+
wf2 = process.id.split(/:/)[0..1].join(':')
|
142
|
+
edge = (process.node << @node)
|
143
|
+
edge.dir = 'both'
|
144
|
+
edge.arrowhead = 'none'
|
145
|
+
edge.arrowtail = 'none'
|
146
|
+
if (wf1 != wf2)
|
147
|
+
edge.style = 'dashed'
|
148
|
+
end
|
149
|
+
self.prerequisites << process
|
150
|
+
}
|
151
|
+
return self
|
152
|
+
end
|
153
|
+
|
154
|
+
def same_as(process)
|
155
|
+
@node = process.node
|
156
|
+
end
|
157
|
+
|
158
|
+
def all_prerequisites
|
159
|
+
prerequisites.collect { |p| p.all_prerequisites + [p.name] }.flatten.uniq
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Dor
|
2
|
+
module Workflow
|
3
|
+
class Process
|
4
|
+
attr_reader :owner, :repo, :workflow
|
5
|
+
|
6
|
+
def initialize(repo, workflow, attrs)
|
7
|
+
@workflow = workflow
|
8
|
+
@repo = repo
|
9
|
+
if attrs.is_a? Nokogiri::XML::Node
|
10
|
+
init_from_node(attrs)
|
11
|
+
else
|
12
|
+
@attrs = attrs
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def init_from_node(node)
|
17
|
+
@attrs = {
|
18
|
+
'name' => node['name'],
|
19
|
+
'sequence' => node['sequence'] ? node['sequence'].to_i : nil,
|
20
|
+
'status' => node['status'], # TODO see how this affects argo
|
21
|
+
'lifecycle' => node['lifecycle'],
|
22
|
+
'label' => node.at_xpath('label/text()').to_s,
|
23
|
+
'batch_limit' => node['batch-limit'] ? node['batch-limit'].to_i : nil,
|
24
|
+
'error_limit' => node['error-limit'] ? node['error-limit'].to_i : nil,
|
25
|
+
'prerequisite' => node.xpath('prereq').collect { |p|
|
26
|
+
repo = (p['repository'].nil? or p['repository'] == @repo) ? nil : p['repository']
|
27
|
+
wf = (p['workflow'].nil? or p['workflow'] == @workflow) ? nil : p['workflow']
|
28
|
+
[repo,wf,p.text.to_s].compact.join(':')
|
29
|
+
},
|
30
|
+
'priority' => node['priority'] ? node['priority'].to_i : 0
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def name ; @attrs['name'] ; end
|
35
|
+
def sequence ; @attrs['sequence'] ; end
|
36
|
+
def lifecycle ; @attrs['lifecycle'] ; end
|
37
|
+
def label ; @attrs['label'] ; end
|
38
|
+
def batch_limit ; @attrs['batch_limit'] ; end
|
39
|
+
def error_limit ; @attrs['error_limit'] ; end
|
40
|
+
def error_message ; @attrs['errorMessage'] ; end
|
41
|
+
def prerequisite ; @attrs['prerequisite'] ; end
|
42
|
+
def status ; @attrs['status'] ; end
|
43
|
+
def note ; @attrs['note'] ; end
|
44
|
+
def version ; @attrs['version'] ; end
|
45
|
+
def priority ; @attrs['priority'] ; end
|
46
|
+
def completed? ; self.status == 'completed' ; end
|
47
|
+
def error? ; self.status == 'error' ; end
|
48
|
+
def waiting? ; self.status == 'waiting' ; end
|
49
|
+
def date_time ;@attrs['datetime'] ; end
|
50
|
+
|
51
|
+
def archived?
|
52
|
+
return true if(@attrs['archived'] =~ /true$/i)
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
def ready?
|
57
|
+
self.waiting? and (not self.prerequisite.nil?) and self.prerequisite.all? { |pr| (prq = self.owner[pr]) && prq.completed? }
|
58
|
+
end
|
59
|
+
|
60
|
+
def blocked?
|
61
|
+
self.waiting? and (not self.prerequisite.nil?) and self.prerequisite.any? { |pr| (prq = self.owner[pr]) && (prq.error? or prq.blocked?) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def state
|
65
|
+
if blocked?
|
66
|
+
'blocked'
|
67
|
+
elsif ready?
|
68
|
+
'ready'
|
69
|
+
else
|
70
|
+
status
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def attempts
|
75
|
+
@attrs['attempts'].to_i
|
76
|
+
end
|
77
|
+
|
78
|
+
def datetime
|
79
|
+
@attrs['datetime'] ? Time.parse(@attrs['datetime']) : nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def elapsed
|
83
|
+
@attrs['elapsed'].nil? ? nil : @attrs['elapsed'].to_f
|
84
|
+
end
|
85
|
+
|
86
|
+
def update!(info, new_owner=nil)
|
87
|
+
@owner = new_owner unless new_owner.nil?
|
88
|
+
if info.is_a? Nokogiri::XML::Node
|
89
|
+
info = Hash[info.attributes.collect { |k,v| [k,v.value] }]
|
90
|
+
end
|
91
|
+
@attrs.merge! info
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_hash
|
95
|
+
@attrs.reject { |k,v| v.nil? or v == 0 or (v.respond_to?(:empty?) and v.empty?) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|