lyber-core 6.1.1 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: 9fee6187de84b39ea2e21ffb214d2e8d9dcb6be544df35a26366652aabf98d52
|
4
|
+
data.tar.gz: d2e57ab17e7f966491248ca077c17064430d9945585b027b46865d3053a5bac5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de1f7e5c8bfd12d1d72ad712b409fdcedce82202f34679648bb448d800de7f40f84a6c55e187635cb21f5759af464e44ccebc7baec062789f3719e170f586e65
|
7
|
+
data.tar.gz: d02c0221f2cd4eb19e41d84e59104cc5926b2c53c0d7616cf964b64e99e2893a6e864fad487004096bee515eebaaae7f884bcc26e6ad2c5c1705a3c1f02e6dd1
|
data/README.md
CHANGED
@@ -1,31 +1,30 @@
|
|
1
|
-
[![
|
2
|
-
[![Coverage
|
1
|
+
[![CircleCI](https://circleci.com/gh/sul-dlss/lyber-core/tree/main.svg?style=svg)](https://circleci.com/gh/sul-dlss/lyber-core/tree/main)
|
2
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/472f67659e513e3d8ffa/test_coverage)](https://codeclimate.com/github/sul-dlss/lyber-core/test_coverage)
|
3
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/472f67659e513e3d8ffa/maintainability)](https://codeclimate.com/github/sul-dlss/lyber-core/maintainability)
|
3
4
|
[![Gem Version](https://badge.fury.io/rb/lyber-core.svg)](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.1.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-03-27 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: '7.0'
|
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: '7.0'
|
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
|