lyber-core 6.1.1 → 7.0.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 +4 -4
- data/README.md +59 -54
- data/lib/lyber_core/boot.rb +81 -0
- data/lib/lyber_core/return_state.rb +17 -18
- data/lib/lyber_core/robot.rb +73 -66
- data/lib/lyber_core/rspec.rb +11 -0
- data/lib/lyber_core/version.rb +5 -0
- data/lib/lyber_core/workflow.rb +14 -4
- data/lib/lyber_core/workflow_client_factory.rb +10 -0
- data/lib/lyber_core.rb +19 -4
- metadata +111 -25
- data/lib/lyber_core/log.rb +0 -105
- data/lib/tasks/rdoc.rake +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9594bf0c91b30860cdc8580d1e7e53b47ab5cbf64b9c7be0738e43e9020d9dc8
|
4
|
+
data.tar.gz: 1e3bfe3e564263ee64b681c38df4c0ca84a3d1b90716b68be4654ac4b23ebbbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dc1ddef3619e90a55e8f1dc8d8b5ce1fdb832fe0f36a1d14ab7be9e0e2ff2ac76753d7822bea43bf44fc33e846e603a6a328b29562bb526ec4a555bf9b323f9
|
7
|
+
data.tar.gz: 881fbd6acd736e7e1c020bd50149436359ac880b0804188662a039e97a70f3fc15e8e7e259b71b3a37d6f56742bb605fa2847f87358759f9e9801e333fb14493
|
data/README.md
CHANGED
@@ -1,31 +1,30 @@
|
|
1
|
-
[](https://circleci.com/gh/sul-dlss/lyber-core/tree/main)
|
2
|
+
[](https://codeclimate.com/github/sul-dlss/lyber-core/test_coverage)
|
3
|
+
[](https://codeclimate.com/github/sul-dlss/lyber-core/maintainability)
|
3
4
|
[](https://badge.fury.io/rb/lyber-core)
|
4
5
|
|
5
6
|
# lyber_core
|
6
7
|
|
7
8
|
## Robot Creation
|
8
9
|
|
9
|
-
Create a class that
|
10
|
+
Create a class that subclasses `LyberCore::Robot`
|
10
11
|
|
11
|
-
* In the initializer, call `super` with the
|
12
|
-
* Your class `#
|
12
|
+
* In the initializer, call `super` with the workflow name, step name
|
13
|
+
* Your class `#perform_work` method will perform the actual work; `druid` is available as an instance variable.
|
13
14
|
|
14
15
|
```ruby
|
15
16
|
module Robots
|
16
17
|
module DorRepo
|
17
18
|
module Accession
|
18
19
|
|
19
|
-
class Shelve
|
20
|
-
include LyberCore::Robot
|
20
|
+
class Shelve < LyberCore::Robot
|
21
21
|
|
22
22
|
def initialize
|
23
|
-
super('
|
23
|
+
super('accessionWF', 'shelve')
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
obj.shelve
|
26
|
+
def perform_work
|
27
|
+
cocina_object.shelve
|
29
28
|
end
|
30
29
|
|
31
30
|
end
|
@@ -42,24 +41,22 @@ module Robots
|
|
42
41
|
module DorRepo
|
43
42
|
module Accession
|
44
43
|
|
45
|
-
class Shelve
|
46
|
-
include LyberCore::Robot
|
44
|
+
class Shelve < LyberCore::Robot
|
47
45
|
|
48
46
|
def initialize
|
49
|
-
super('
|
47
|
+
super('accessionWF', 'shelve')
|
50
48
|
end
|
51
49
|
|
52
|
-
def perform
|
53
|
-
obj = Dor::Item.find(druid)
|
50
|
+
def perform
|
54
51
|
if some_logic_here_to_determine_if_shelving_occurs
|
55
|
-
|
56
|
-
return LyberCore::
|
57
|
-
# return LyberCore::
|
52
|
+
cocina_object.shelve
|
53
|
+
return LyberCore::ReturnState.new(status: 'completed') # set the final state to completed
|
54
|
+
# return LyberCore::ReturnState.new(status: 'completed', note: 'some custom note to pass back to workflow') # set the final state to completed with a custom note
|
58
55
|
|
59
56
|
else
|
60
57
|
# just return skipped if we did nothing
|
61
|
-
return LyberCore::
|
62
|
-
# return LyberCore::
|
58
|
+
return LyberCore::ReturnState.new(status: 'skipped') # set the final state to skipped
|
59
|
+
# return LyberCore::ReturnState.new(status: 'skipped', note: 'some custom note to pass back to workflow') # set the final state to skipped with a custom note
|
63
60
|
end
|
64
61
|
end
|
65
62
|
|
@@ -72,50 +69,58 @@ end
|
|
72
69
|
|
73
70
|
## Robot Environment Setup
|
74
71
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
Create a `config/boot.rb` containing:
|
73
|
+
```
|
74
|
+
require 'rubygems'
|
75
|
+
require 'bundler/setup'
|
76
|
+
Bundler.require(:default)
|
79
77
|
|
80
|
-
|
78
|
+
LyberCore::Boot.up(__dir__)
|
81
79
|
|
82
|
-
|
83
|
-
```ruby
|
84
|
-
require 'robot-controller/tasks'
|
85
|
-
...
|
86
|
-
task :environment do
|
87
|
-
require_relative 'config/boot'
|
88
|
-
end
|
80
|
+
# Any additional robot-specific configuratio.
|
89
81
|
```
|
90
82
|
|
91
|
-
|
92
|
-
|
93
|
-
|
83
|
+
The configuration must include:
|
84
|
+
```
|
85
|
+
redis_url: ~
|
94
86
|
|
87
|
+
workflow:
|
88
|
+
url: http://workflow.example.com/workflow
|
89
|
+
logfile: 'log/workflow_service.log'
|
90
|
+
shift_age: 'weekly'
|
91
|
+
timeout: 60
|
95
92
|
```
|
96
|
-
|
93
|
+
|
94
|
+
And optionally:
|
97
95
|
```
|
96
|
+
# For Dor Services Client
|
97
|
+
dor_services:
|
98
|
+
url: 'https://dor-services-test.stanford.test'
|
99
|
+
token: secret-token
|
98
100
|
|
99
|
-
|
101
|
+
# For Cocina::Models::Mapping::Purl
|
102
|
+
purl_url: 'https://purl-example.stanford.edu'
|
100
103
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
+
# For DruidTools::Druid
|
105
|
+
stacks:
|
106
|
+
local_workspace_root: ~
|
104
107
|
```
|
105
108
|
|
109
|
+
The following environment variables can optionally be set:
|
110
|
+
* ROBOT_ENVIRONMENT
|
111
|
+
* ROBOT_LOG_LEVEL
|
106
112
|
|
107
|
-
##
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
* **1.3** Started to use Dor::Config for workspace configuration
|
113
|
-
* **1.0.0** Factored all Dor::* classes and object models out of lyber-core and into a separate dor-services gem. WARNING: MAY BREAK COMPATIBILITY WITH PREVIOUS DOR-ENABLED CODE.
|
114
|
-
* **0.9.8** Created branch for legacy work "0.9-legacy". Robots can now be configured with fully qualified workflows for prerequisites
|
115
|
-
eg <i>dor:googleScannedBookWF:register-object</i>
|
116
|
-
* **0.9.2** Workflow bug fixes. Last version that supports active-fedora 1.0.7
|
117
|
-
* We recommend that you **DO NOT USE** any version older than these
|
113
|
+
## Robot Testing
|
114
|
+
Include the following in `rspec/spec_helper.rb`:
|
115
|
+
```
|
116
|
+
ENV['ROBOT_ENVIRONMENT'] = 'test'
|
117
|
+
require File.expand_path("#{__dir__}/../config/boot")
|
118
118
|
|
119
|
-
|
119
|
+
include LyberCore::Rspec
|
120
|
+
```
|
120
121
|
|
121
|
-
|
122
|
+
Robots can be invoked with:
|
123
|
+
```
|
124
|
+
test_perform(robot, druid)
|
125
|
+
```
|
126
|
+
to avoid the workflow updates in `perform()`.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The following is required in config/boot.rb
|
4
|
+
# require 'rubygems'
|
5
|
+
# require 'bundler/setup'
|
6
|
+
# Bundler.require(:default)
|
7
|
+
|
8
|
+
# LyberCore::Boot.up(__dir__)
|
9
|
+
|
10
|
+
module LyberCore
|
11
|
+
# Boots up the robot environment, including configuration, logging, clients, and Sidekiq.
|
12
|
+
class Boot
|
13
|
+
def self.up(config_dir)
|
14
|
+
new(config_dir).perform
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(config_dir)
|
18
|
+
@config_dir = config_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def perform
|
22
|
+
boot_config
|
23
|
+
boot_dsa
|
24
|
+
boot_cocina_models
|
25
|
+
boot_sidekiq
|
26
|
+
end
|
27
|
+
|
28
|
+
def environment
|
29
|
+
@environment ||= ENV['ROBOT_ENVIRONMENT'] ||= 'development'
|
30
|
+
end
|
31
|
+
|
32
|
+
def boot_config
|
33
|
+
Config.setup do |config|
|
34
|
+
config.const_name = 'Settings'
|
35
|
+
config.use_env = true
|
36
|
+
config.env_prefix = 'SETTINGS'
|
37
|
+
config.env_separator = '__'
|
38
|
+
end
|
39
|
+
Config.load_and_set_settings(
|
40
|
+
Config.setting_files(File.expand_path(config_dir), environment)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_reader :config_dir
|
47
|
+
|
48
|
+
def robot_root
|
49
|
+
@robot_root ||= File.expand_path("#{config_dir}/..")
|
50
|
+
end
|
51
|
+
|
52
|
+
def robot_log
|
53
|
+
Sidekiq::Logger.new(File.join(robot_root, "log/#{environment}.log")).tap do |log|
|
54
|
+
log.level = Logger::SEV_LABEL.index(ENV.fetch('ROBOT_LOG_LEVEL', nil)) || Logger::INFO
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def boot_dsa
|
59
|
+
return unless Settings.dor_services&.url
|
60
|
+
|
61
|
+
Dor::Services::Client.configure(url: Settings.dor_services.url,
|
62
|
+
token: Settings.dor_services.token,
|
63
|
+
enable_get_retries: true)
|
64
|
+
end
|
65
|
+
|
66
|
+
def boot_cocina_models
|
67
|
+
Cocina::Models::Mapping::Purl.base_url = Settings.purl_url if Settings.purl_url
|
68
|
+
end
|
69
|
+
|
70
|
+
def boot_sidekiq
|
71
|
+
return if environment == 'test'
|
72
|
+
|
73
|
+
Sidekiq.configure_server do |config|
|
74
|
+
config.logger = robot_log
|
75
|
+
config.redis = { url: Settings.redis_url }
|
76
|
+
# For Sidekiq Pro
|
77
|
+
config.super_fetch!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,27 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# this object defines the allowed states robots can optionally return upon completion
|
4
|
-
# if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
|
5
|
-
# it will be used to set the final workflow state for that druid
|
6
3
|
module LyberCore
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
# this object defines the allowed states robots can optionally return upon completion
|
5
|
+
# if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
|
6
|
+
# it will be used to set the final workflow state for that druid
|
7
|
+
class ReturnState
|
8
|
+
attr_reader :status
|
9
|
+
attr_accessor :note
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
self.note = params[:note] || ''
|
17
|
-
end
|
11
|
+
ALLOWED_RETURN_STATES = %w[completed skipped waiting noop].freeze
|
12
|
+
DEFAULT_RETURN_STATE = 'completed'
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def initialize(params = {})
|
15
|
+
self.status = params[:status] || DEFAULT_RETURN_STATE
|
16
|
+
self.note = params[:note] || ''
|
17
|
+
end
|
18
|
+
|
19
|
+
def status=(value)
|
20
|
+
state = value.to_s.downcase
|
21
|
+
raise 'invalid return state' unless ALLOWED_RETURN_STATES.include? state
|
22
22
|
|
23
|
-
|
24
|
-
end
|
23
|
+
@status = state
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
data/lib/lyber_core/robot.rb
CHANGED
@@ -1,112 +1,119 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'benchmark'
|
4
|
-
|
5
3
|
module LyberCore
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
# Base class for all robots.
|
5
|
+
# Subclasses should implement the #perform_work method.
|
6
|
+
class Robot
|
7
|
+
include Sidekiq::Job
|
8
|
+
sidekiq_options retry: 0
|
11
9
|
|
12
|
-
|
13
|
-
# Called by job-manager on derived-class
|
14
|
-
# Instantiate the Robot and call #work with the passed in druid
|
15
|
-
def perform(druid, *context)
|
16
|
-
bot = new
|
17
|
-
bot.work druid, context
|
18
|
-
end
|
19
|
-
end
|
10
|
+
attr_reader :workflow_name, :process, :druid
|
20
11
|
|
21
|
-
|
22
|
-
attr_reader :workflow_name, :process
|
12
|
+
delegate :lane_id, to: :workflow
|
23
13
|
|
24
|
-
def initialize(workflow_name, process
|
25
|
-
Signal.trap('QUIT') { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
|
14
|
+
def initialize(workflow_name, process)
|
26
15
|
@workflow_name = workflow_name
|
27
16
|
@process = process
|
28
|
-
@check_queued_status = check_queued_status
|
29
17
|
end
|
30
18
|
|
31
19
|
def workflow_service
|
32
|
-
|
20
|
+
@workflow_service ||= WorkflowClientFactory.build(logger: logger)
|
21
|
+
end
|
22
|
+
|
23
|
+
def object_client
|
24
|
+
@object_client ||= Dor::Services::Client.object(druid)
|
25
|
+
end
|
26
|
+
|
27
|
+
def cocina_object
|
28
|
+
@cocina_object ||= object_client.find
|
29
|
+
end
|
30
|
+
|
31
|
+
def druid_object
|
32
|
+
@druid_object ||= DruidTools::Druid.new(druid, Settings.stacks.local_workspace_root)
|
33
33
|
end
|
34
34
|
|
35
35
|
# Sets up logging, timing and error handling of the job
|
36
|
-
# Calls the #
|
36
|
+
# Calls the #perform_work method, then sets workflow to 'completed' or 'error' depending on success
|
37
37
|
# rubocop:disable Metrics/AbcSize
|
38
|
-
# rubocop:disable Metrics/
|
39
|
-
|
40
|
-
|
41
|
-
Honeybadger.context(druid: druid, process: process, workflow_name: workflow_name)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return if check_queued_status && !item_queued?(druid)
|
38
|
+
# rubocop:disable Metrics/MethodLength
|
39
|
+
def perform(druid)
|
40
|
+
@druid = druid
|
41
|
+
Honeybadger.context(druid: druid, process: process, workflow_name: workflow_name)
|
42
|
+
|
43
|
+
logger.info "#{druid} processing #{process} (#{workflow_name})"
|
44
|
+
return unless check_item_queued?
|
46
45
|
|
47
46
|
# this is the default note to pass back to workflow service,
|
48
|
-
# but it can be overriden by a robot that uses the
|
47
|
+
# but it can be overriden by a robot that uses the Robots::ReturnState
|
49
48
|
# object to return a status
|
50
49
|
note = Socket.gethostname
|
51
50
|
|
52
51
|
# update the workflow status to indicate that started
|
53
|
-
workflow.start(note)
|
52
|
+
workflow.start!(note)
|
54
53
|
|
55
54
|
result = nil
|
56
55
|
elapsed = Benchmark.realtime do
|
57
|
-
result =
|
58
|
-
perform druid # implemented in the mixed-in robot class
|
59
|
-
else
|
60
|
-
perform druid, context
|
61
|
-
end
|
56
|
+
result = perform_work
|
62
57
|
end
|
63
58
|
|
64
59
|
# the final workflow state is determined by the return value of the perform step, if it is a ReturnState object,
|
65
60
|
# we will use the defined status, otherwise default to completed
|
66
61
|
# if a note is passed back, we will also use that instead of the default
|
67
|
-
if result.
|
62
|
+
if result.instance_of?(ReturnState)
|
68
63
|
workflow_state = result.status
|
69
64
|
note = result.note unless result.note.blank?
|
70
65
|
else
|
71
66
|
workflow_state = 'completed'
|
72
67
|
end
|
73
|
-
# update the workflow status from its current state to the state returned by perform
|
68
|
+
# update the workflow status from its current state to the state returned by perform
|
69
|
+
# (or 'completed' as the default)
|
74
70
|
# noop allows a robot to not set a workflow as complete, e.g., if that is delegated to another service.
|
75
|
-
workflow.complete(workflow_state, elapsed, note) unless workflow_state == 'noop'
|
71
|
+
workflow.complete!(workflow_state, elapsed, note) unless workflow_state == 'noop'
|
76
72
|
|
77
|
-
|
73
|
+
logger.info "Finished #{druid} in #{format('%0.4f', elapsed)}s"
|
78
74
|
rescue StandardError => e
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
75
|
+
handle_error(e)
|
76
|
+
end
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
78
|
+
# rubocop:enable Metrics/MethodLength
|
79
|
+
|
80
|
+
# Work performed by the robot.
|
81
|
+
# This method is to be implemented by robot subclasses.
|
82
|
+
def perform_work
|
83
|
+
raise NotImplementedError
|
84
|
+
end
|
85
|
+
|
86
|
+
def bare_druid
|
87
|
+
@bare_druid = druid.delete_prefix('druid:')
|
87
88
|
end
|
88
|
-
# rubocop:enable Metrics/AbcSize
|
89
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
90
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
91
89
|
|
92
|
-
|
90
|
+
private
|
91
|
+
|
92
|
+
# rubocop:disable Metrics/AbcSize
|
93
|
+
def handle_error(error)
|
94
|
+
Honeybadger.notify(error)
|
95
|
+
logger.error "#{error.message}\n#{error.backtrace.join("\n")}"
|
96
|
+
workflow.error!(error.message, Socket.gethostname)
|
97
|
+
rescue StandardError => e
|
98
|
+
logger.error "Cannot set #{druid} to status='error'\n#{e.message}\n#{e.backtrace.join("\n")}"
|
99
|
+
raise e # send exception to Sidekiq failed queue
|
100
|
+
end
|
101
|
+
# rubocop:enable Metrics/AbcSize
|
93
102
|
|
94
|
-
def workflow
|
95
|
-
Workflow.new(workflow_service: workflow_service,
|
96
|
-
|
97
|
-
|
98
|
-
|
103
|
+
def workflow
|
104
|
+
@workflow ||= Workflow.new(workflow_service: workflow_service,
|
105
|
+
druid: druid,
|
106
|
+
workflow_name: workflow_name,
|
107
|
+
process: process)
|
99
108
|
end
|
100
109
|
|
101
|
-
def
|
102
|
-
|
103
|
-
workflow: workflow_name,
|
104
|
-
process: process)
|
105
|
-
return true if status =~ /queued/i
|
110
|
+
def check_item_queued?
|
111
|
+
return true if /queued/i.match?(workflow.status)
|
106
112
|
|
107
|
-
msg = "Item #{druid} is not queued for #{process} (#{workflow_name}),
|
108
|
-
|
109
|
-
|
113
|
+
msg = "Item #{druid} is not queued for #{process} (#{workflow_name}), " \
|
114
|
+
"but has status of '#{workflow.status}'. Will skip processing"
|
115
|
+
Honeybadger.notify(msg)
|
116
|
+
logger.warn(msg)
|
110
117
|
false
|
111
118
|
end
|
112
119
|
end
|
data/lib/lyber_core/workflow.rb
CHANGED
@@ -10,7 +10,7 @@ module LyberCore
|
|
10
10
|
@process = process
|
11
11
|
end
|
12
12
|
|
13
|
-
def start(note)
|
13
|
+
def start!(note)
|
14
14
|
workflow_service.update_status(druid: druid,
|
15
15
|
workflow: workflow_name,
|
16
16
|
process: process,
|
@@ -19,7 +19,7 @@ module LyberCore
|
|
19
19
|
note: note)
|
20
20
|
end
|
21
21
|
|
22
|
-
def complete(status, elapsed, note)
|
22
|
+
def complete!(status, elapsed, note)
|
23
23
|
workflow_service.update_status(druid: druid,
|
24
24
|
workflow: workflow_name,
|
25
25
|
process: process,
|
@@ -28,7 +28,7 @@ module LyberCore
|
|
28
28
|
note: note)
|
29
29
|
end
|
30
30
|
|
31
|
-
def error(error_msg, error_text)
|
31
|
+
def error!(error_msg, error_text)
|
32
32
|
workflow_service.update_error_status(druid: druid,
|
33
33
|
workflow: workflow_name,
|
34
34
|
process: process,
|
@@ -36,7 +36,17 @@ module LyberCore
|
|
36
36
|
error_text: error_text)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
def status
|
40
|
+
@status ||= workflow_service.workflow_status(druid: druid,
|
41
|
+
workflow: workflow_name,
|
42
|
+
process: process)
|
43
|
+
end
|
44
|
+
|
45
|
+
def lane_id
|
46
|
+
@lane_id ||= workflow_service.process(pid: druid, workflow_name: workflow_name, process: process).lane_id
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
40
50
|
|
41
51
|
attr_reader :workflow_service, :druid, :workflow_name, :process
|
42
52
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LyberCore
|
4
|
+
# Factory for creating a workflow client
|
5
|
+
class WorkflowClientFactory
|
6
|
+
def self.build(logger:)
|
7
|
+
Dor::Workflow::Client.new(url: Settings.workflow.url, logger: logger, timeout: Settings.workflow.timeout)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/lyber_core.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
3
|
+
require 'benchmark'
|
4
|
+
require 'socket'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext/object/blank' # String#blank?
|
7
|
+
require 'active_support/core_ext/module/delegation'
|
8
|
+
require 'sidekiq'
|
9
|
+
require 'honeybadger'
|
10
|
+
require 'dor/workflow/client'
|
11
|
+
require 'dor/services/client'
|
12
|
+
require 'druid-tools'
|
13
|
+
require 'zeitwerk'
|
14
|
+
|
15
|
+
loader = Zeitwerk::Loader.for_gem
|
16
|
+
loader.ignore("#{__dir__}/lyber-core.rb")
|
17
|
+
loader.setup
|
18
|
+
|
19
|
+
# Elon Musk: "Robots will be able to do everything better than us"
|
20
|
+
module LyberCore
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lyber-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 7.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alpana Pande
|
@@ -13,19 +13,19 @@ authors:
|
|
13
13
|
- Michael Klein
|
14
14
|
- Darren Weber
|
15
15
|
- Peter Mangiafico
|
16
|
-
autorequire:
|
16
|
+
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date:
|
19
|
+
date: 2023-02-21 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: activesupport
|
23
23
|
requirement: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
|
-
type: :
|
28
|
+
type: :runtime
|
29
29
|
prerelease: false
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
@@ -33,27 +33,55 @@ dependencies:
|
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
36
|
+
name: config
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0
|
42
|
-
type: :
|
41
|
+
version: '0'
|
42
|
+
type: :runtime
|
43
43
|
prerelease: false
|
44
44
|
version_requirements: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 0
|
48
|
+
version: '0'
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
50
|
+
name: dor-services-client
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '12.10'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '12.10'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: dor-workflow-client
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '5.0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '5.0'
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: druid-tools
|
51
79
|
requirement: !ruby/object:Gem::Requirement
|
52
80
|
requirements:
|
53
81
|
- - ">="
|
54
82
|
- !ruby/object:Gem::Version
|
55
83
|
version: '0'
|
56
|
-
type: :
|
84
|
+
type: :runtime
|
57
85
|
prerelease: false
|
58
86
|
version_requirements: !ruby/object:Gem::Requirement
|
59
87
|
requirements:
|
@@ -61,27 +89,41 @@ dependencies:
|
|
61
89
|
- !ruby/object:Gem::Version
|
62
90
|
version: '0'
|
63
91
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
92
|
+
name: honeybadger
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
type: :runtime
|
99
|
+
prerelease: false
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: sidekiq
|
65
107
|
requirement: !ruby/object:Gem::Requirement
|
66
108
|
requirements:
|
67
109
|
- - "~>"
|
68
110
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
70
|
-
type: :
|
111
|
+
version: '6.2'
|
112
|
+
type: :runtime
|
71
113
|
prerelease: false
|
72
114
|
version_requirements: !ruby/object:Gem::Requirement
|
73
115
|
requirements:
|
74
116
|
- - "~>"
|
75
117
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
118
|
+
version: '6.2'
|
77
119
|
- !ruby/object:Gem::Dependency
|
78
|
-
name:
|
120
|
+
name: zeitwerk
|
79
121
|
requirement: !ruby/object:Gem::Requirement
|
80
122
|
requirements:
|
81
123
|
- - ">="
|
82
124
|
- !ruby/object:Gem::Version
|
83
125
|
version: '0'
|
84
|
-
type: :
|
126
|
+
type: :runtime
|
85
127
|
prerelease: false
|
86
128
|
version_requirements: !ruby/object:Gem::Requirement
|
87
129
|
requirements:
|
@@ -89,7 +131,35 @@ dependencies:
|
|
89
131
|
- !ruby/object:Gem::Version
|
90
132
|
version: '0'
|
91
133
|
- !ruby/object:Gem::Dependency
|
92
|
-
name:
|
134
|
+
name: rake
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 0.8.7
|
140
|
+
type: :development
|
141
|
+
prerelease: false
|
142
|
+
version_requirements: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 0.8.7
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: rspec
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '3.0'
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '3.0'
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: rubocop
|
93
163
|
requirement: !ruby/object:Gem::Requirement
|
94
164
|
requirements:
|
95
165
|
- - "~>"
|
@@ -103,7 +173,21 @@ dependencies:
|
|
103
173
|
- !ruby/object:Gem::Version
|
104
174
|
version: '1.24'
|
105
175
|
- !ruby/object:Gem::Dependency
|
106
|
-
name:
|
176
|
+
name: rubocop-rspec
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
- !ruby/object:Gem::Dependency
|
190
|
+
name: simplecov
|
107
191
|
requirement: !ruby/object:Gem::Requirement
|
108
192
|
requirements:
|
109
193
|
- - ">="
|
@@ -129,16 +213,18 @@ files:
|
|
129
213
|
- README.md
|
130
214
|
- lib/lyber-core.rb
|
131
215
|
- lib/lyber_core.rb
|
132
|
-
- lib/lyber_core/
|
216
|
+
- lib/lyber_core/boot.rb
|
133
217
|
- lib/lyber_core/return_state.rb
|
134
218
|
- lib/lyber_core/robot.rb
|
219
|
+
- lib/lyber_core/rspec.rb
|
220
|
+
- lib/lyber_core/version.rb
|
135
221
|
- lib/lyber_core/workflow.rb
|
136
|
-
- lib/
|
222
|
+
- lib/lyber_core/workflow_client_factory.rb
|
137
223
|
homepage: http://github.com/sul-dlss/lyber-core
|
138
224
|
licenses:
|
139
225
|
- Apache-2.0
|
140
226
|
metadata: {}
|
141
|
-
post_install_message:
|
227
|
+
post_install_message:
|
142
228
|
rdoc_options: []
|
143
229
|
require_paths:
|
144
230
|
- lib
|
@@ -146,15 +232,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
232
|
requirements:
|
147
233
|
- - ">="
|
148
234
|
- !ruby/object:Gem::Version
|
149
|
-
version: '0'
|
235
|
+
version: '3.0'
|
150
236
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
237
|
requirements:
|
152
238
|
- - ">="
|
153
239
|
- !ruby/object:Gem::Version
|
154
240
|
version: 1.3.6
|
155
241
|
requirements: []
|
156
|
-
rubygems_version: 3.
|
157
|
-
signing_key:
|
242
|
+
rubygems_version: 3.3.7
|
243
|
+
signing_key:
|
158
244
|
specification_version: 4
|
159
245
|
summary: Core services used by the SUL Digital Library
|
160
246
|
test_files: []
|
data/lib/lyber_core/log.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module LyberCore
|
4
|
-
class LyberCore::Log
|
5
|
-
require 'logger'
|
6
|
-
|
7
|
-
# Default values
|
8
|
-
DEFAULT_LOGFILE = '/tmp/lybercore_log.log' # TODO: change to STDOUT?
|
9
|
-
DEFAULT_LOG_LEVEL = Logger::INFO
|
10
|
-
DEFAULT_FORMATTER = proc do |s, t, p, m|
|
11
|
-
"%5s [%s] (%s) %s :: %s\n" % [s, t.strftime('%Y-%m-%d %H:%M:%S'), $$, p, m]
|
12
|
-
end
|
13
|
-
|
14
|
-
# Initial state
|
15
|
-
@@logfile = DEFAULT_LOGFILE
|
16
|
-
@@log ||= Logger.new(@@logfile)
|
17
|
-
# $stdout.reopen(@@logfile)
|
18
|
-
# $stderr.reopen(@@logfile)
|
19
|
-
@@log.level = DEFAULT_LOG_LEVEL
|
20
|
-
@@log.formatter = DEFAULT_FORMATTER
|
21
|
-
|
22
|
-
# Restore LyberCore::Log to its default state
|
23
|
-
def Log.restore_defaults
|
24
|
-
@@log.level = DEFAULT_LOG_LEVEL
|
25
|
-
Log.set_logfile(DEFAULT_LOGFILE)
|
26
|
-
@@log.formatter = DEFAULT_FORMATTER
|
27
|
-
end
|
28
|
-
|
29
|
-
# The current location of the logfile
|
30
|
-
def Log.logfile
|
31
|
-
@@logfile
|
32
|
-
end
|
33
|
-
|
34
|
-
# Accepts a filename as an argument, and checks to see whether that file can be
|
35
|
-
# opened for writing. If it can be opened, it closes the existing Logger object
|
36
|
-
# and re-opens it with the new logfile location. It raises an exception if it
|
37
|
-
# cannot write to the specified logfile.
|
38
|
-
def Log.set_logfile(new_logfile)
|
39
|
-
current_log_level = @@log.level
|
40
|
-
current_formatter = @@log.formatter
|
41
|
-
@@log = Logger.new(new_logfile)
|
42
|
-
@@logfile = new_logfile
|
43
|
-
@@log.level = current_log_level
|
44
|
-
@@log.formatter = current_formatter
|
45
|
-
rescue Exception => e
|
46
|
-
raise e, "Couldn't initialize logfile #{new_logfile} because\n#{e.message}: #{e.backtrace.join(%(\n))}}"
|
47
|
-
end
|
48
|
-
|
49
|
-
# Set the log level.
|
50
|
-
# See http://ruby-doc.org/core/classes/Logger.html for more info.
|
51
|
-
# Possible values are:
|
52
|
-
# Logger::FATAL (4): an unhandleable error that results in a program crash
|
53
|
-
# Logger::ERROR (3): a handleable error condition
|
54
|
-
# Logger::WARN (2): a warning
|
55
|
-
# Logger::INFO (1): generic (useful) information about system operation
|
56
|
-
# Logger::DEBUG (0): low-level information for developers
|
57
|
-
def Log.set_level(loglevel)
|
58
|
-
if [0, 1, 2, 3, 4].include? loglevel
|
59
|
-
@@log.level = loglevel
|
60
|
-
@@log.debug "Setting LyberCore::Log.level to #{loglevel}"
|
61
|
-
else
|
62
|
-
@@log.warn "I received an invalid option for log level. I expected a number between 0 and 4 but I got #{loglevel}"
|
63
|
-
@@log.warn "I'm setting the loglevel to 0 (debug) because you seem to be having trouble."
|
64
|
-
@@log.level = 0
|
65
|
-
end
|
66
|
-
rescue Exception => e
|
67
|
-
raise e, "Couldn't set log level because\n#{e.message}: #{e.backtrace.join(%(\n))}"
|
68
|
-
end
|
69
|
-
|
70
|
-
# Return the current log level
|
71
|
-
def Log.level
|
72
|
-
@@log.level
|
73
|
-
end
|
74
|
-
|
75
|
-
def Log.fatal(msg)
|
76
|
-
@@log.add(Logger::FATAL) { msg }
|
77
|
-
end
|
78
|
-
|
79
|
-
def Log.error(msg)
|
80
|
-
@@log.add(Logger::ERROR) { msg }
|
81
|
-
end
|
82
|
-
|
83
|
-
def Log.warn(msg)
|
84
|
-
@@log.add(Logger::WARN) { msg }
|
85
|
-
end
|
86
|
-
|
87
|
-
def Log.info(msg)
|
88
|
-
@@log.add(Logger::INFO) { msg }
|
89
|
-
end
|
90
|
-
|
91
|
-
def Log.debug(msg)
|
92
|
-
@@log.add(Logger::DEBUG) { msg }
|
93
|
-
end
|
94
|
-
|
95
|
-
def Log.exception(exc)
|
96
|
-
msg = Log.exception_message(exc)
|
97
|
-
Log.error(msg)
|
98
|
-
end
|
99
|
-
|
100
|
-
def Log.exception_message(exc)
|
101
|
-
msg = exc.inspect.split($/).join('; ') + "\n"
|
102
|
-
msg << exc.backtrace.join("\n") if exc.backtrace
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
data/lib/tasks/rdoc.rake
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
desc 'Generate RDoc'
|
4
|
-
task doc: ['doc:generate']
|
5
|
-
|
6
|
-
namespace :doc do
|
7
|
-
project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
8
|
-
doc_destination = File.join(project_root, 'rdoc')
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'yard'
|
12
|
-
require 'yard/rake/yardoc_task'
|
13
|
-
|
14
|
-
YARD::Rake::YardocTask.new(:generate) do |yt|
|
15
|
-
yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
|
16
|
-
Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
|
17
|
-
[File.join(project_root, 'README.rdoc')] +
|
18
|
-
[File.join(project_root, 'LICENSE')]
|
19
|
-
|
20
|
-
yt.options = ['--output-dir', doc_destination, '--readme', 'README.rdoc']
|
21
|
-
end
|
22
|
-
rescue LoadError
|
23
|
-
desc 'Generate YARD Documentation'
|
24
|
-
task :generate do
|
25
|
-
abort 'Please install the YARD gem to generate rdoc.'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
desc 'Remove generated documenation'
|
30
|
-
task :clean do
|
31
|
-
rm_r doc_destination if File.exist?(doc_destination)
|
32
|
-
end
|
33
|
-
end
|