cantemo-portal-agent 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cantemo/portal/agent/cli/commands/watch_folders.rb +14 -9
- data/lib/cantemo/portal/agent/version.rb +1 -1
- data/lib/envoi/mam/agent/cli/commands/cantemo.rb +1 -1
- data/lib/envoi/mam/cantemo/agent.rb +32 -25
- data/lib/envoi/mam/cantemo/agent/watch_folder_manager.rb +35 -17
- data/lib/envoi/watch_folder_utility/watch_folder.rb +55 -7
- data/lib/envoi/watch_folder_utility/watch_folder/handler/listen.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0df20d26170e018fbb101b896771dda9a848a8a
|
4
|
+
data.tar.gz: 977b72cf9a04ce9c70b31dc03436a57c78a5675a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5173fe6dbe088d8ab5195c59c3666887d957cd2876e86c65463dd3da4386594973252ddb93fc714ef6831c0685cda06db0cbd8413424e9e46b8c6646b233938f
|
7
|
+
data.tar.gz: 4ad8f5e06305f2cd174c3bcb6a86c7959414ba257dcd59580cfd32dd9fe7ef072aedef4033f840e732987237738e8a4616f9b0586b57d8266cdaf7c8c4fffd4a
|
@@ -35,19 +35,22 @@ def args; @args end
|
|
35
35
|
op = OptionParser.new
|
36
36
|
op.on('-c', '--config-file-path FILEPATH', 'The path to the configuration file.',
|
37
37
|
"Default Path(s): #{args[:config_file_path]}") { |v| args[:config_file_path] = v }
|
38
|
-
op.on('-b', '--[no-]background', 'Tells the application to run in the background.') { |v| args[:daemonize] = v }
|
39
|
-
op.
|
40
|
-
op.
|
38
|
+
# op.on('-b', '--[no-]background', 'Tells the application to run in the background.') { |v| args[:daemonize] = v }
|
39
|
+
op.on_tail('-t', '--log-to FILEPATH', 'Log file to log to') { |log_to| args[:log_to] = log_to }
|
40
|
+
op.on_tail('-l', '--log-level LEVEL', ['fatal', 'error', 'warn', 'info', 'debug'], 'Select logging level') do |log_level|
|
41
|
+
args[:log_level] = log_level.upcase
|
42
|
+
end
|
43
|
+
op.on_tail('-v', '--version', 'Output the version and exit.') { puts "Version #{Cantemo::Portal::Agent::VERSION}"; exit }
|
44
|
+
op.on_tail('--help', 'Show this message.') { puts op; exit }
|
41
45
|
op.load
|
42
46
|
op.parse!
|
43
47
|
|
44
48
|
config_file_path = args[:config_file_path]
|
45
49
|
args[:config_file_path].map! { |v| File.expand_path(v) } if config_file_path.is_a?(Array)
|
46
50
|
|
47
|
-
command = ARGV.first
|
48
|
-
|
51
|
+
command = ARGV.first
|
49
52
|
daemon_control_command_present = command && begin
|
50
|
-
command.downcase
|
53
|
+
command = command.dup.downcase if command
|
51
54
|
%w(start stop restart run zap killall status).include?(command)
|
52
55
|
end
|
53
56
|
|
@@ -71,9 +74,11 @@ should_daemonize = (daemon_control_command_present && %w(start restart).include?
|
|
71
74
|
#
|
72
75
|
#
|
73
76
|
|
74
|
-
|
75
|
-
|
76
77
|
class Watcher < Envoi::Mam::Cantemo::Agent::WatchFolderManager; end
|
77
78
|
# daemonize ? Watcher.run_as_daemon(args, { force: true }) : Watcher.run(args)
|
78
79
|
# daemon_control_command_present ? Watcher.run_as_daemon(args) : Watcher.run(args)
|
79
|
-
|
80
|
+
begin
|
81
|
+
Watcher.run_with_process_manager(args)
|
82
|
+
rescue => e
|
83
|
+
abort("An error occurred. #{e.message}\n#{e.backtrace}")
|
84
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
if [ 'watchfolder', 'watchfolders'].include?((ARGV.first || '').tr('_-', ''))
|
1
|
+
if [ 'watchfolder', 'watchfolders'].include?((ARGV.first || '').tr('_-', '').downcase)
|
2
2
|
require 'cantemo/portal/agent/cli/commands/watch_folders'
|
3
3
|
else
|
4
4
|
require 'envoi/mam/agent/cli/commands/cantemo-agent'
|
@@ -132,6 +132,15 @@ module Envoi
|
|
132
132
|
logger.warn { "No Supported TransferClient Configuration#{transfer_type && !transfer_type.empty? ? " for transfer type '#{transfer_type}' " : ''}Found in Storage Configuration." }
|
133
133
|
end
|
134
134
|
|
135
|
+
# @param [Hash] args
|
136
|
+
# @option args [String] :file_path
|
137
|
+
# @option args [String] :storage_id
|
138
|
+
# @option args [String] :transfer_type ('')
|
139
|
+
# @option args [Boolean] :import_file (true)
|
140
|
+
# @option args [Boolean] :preserve_path (storage_config['preserve_path'] || default_preserve_path)
|
141
|
+
# @return [Hash]
|
142
|
+
#
|
143
|
+
#
|
135
144
|
def upload(args = {})
|
136
145
|
_response = {}
|
137
146
|
|
@@ -149,17 +158,18 @@ module Envoi
|
|
149
158
|
|
150
159
|
transfer_type = args[:transfer_type] || ''
|
151
160
|
storage_id = args[:storage_id]
|
152
|
-
|
161
|
+
storage_config = agent_config_storages[storage_id]
|
153
162
|
|
154
|
-
unless
|
163
|
+
unless storage_config && !storage_config.empty?
|
155
164
|
raise "No configuration found for storage '#{storage_id}'"
|
156
165
|
end
|
157
166
|
|
158
|
-
should_import_file = args.fetch(:import_file,
|
167
|
+
should_import_file = args.fetch(:import_file, storage_config.fetch('import', true))
|
159
168
|
|
160
|
-
should_preserve_path = args.fetch(:preserve_path,
|
169
|
+
should_preserve_path = args.fetch(:preserve_path,
|
170
|
+
storage_config.fetch('preserve_path', default_preserve_file_path))
|
161
171
|
|
162
|
-
destination_path = args[:destination_path] ||
|
172
|
+
destination_path = args[:destination_path] || storage_config['destination_path'] || '/'
|
163
173
|
relative_path = should_preserve_path ? File.dirname(file_path) : nil
|
164
174
|
relative_path = File.expand_path(relative_path) if relative_path == '.'
|
165
175
|
|
@@ -171,7 +181,7 @@ module Envoi
|
|
171
181
|
|
172
182
|
transfer_response = begin
|
173
183
|
response = nil
|
174
|
-
aspera_config =
|
184
|
+
aspera_config = storage_config['aspera']
|
175
185
|
begin
|
176
186
|
if (transfer_type.empty? || transfer_type == :aspera) && (aspera_config && !aspera_config.empty?)
|
177
187
|
client = Envoi::Mam::Agent::TransferClient::Aspera.new(agent: self)
|
@@ -181,7 +191,7 @@ module Envoi
|
|
181
191
|
logger.error { "Aspera Transfer Failed. '#{e.message}'\n#{e.backtrace.first}" }
|
182
192
|
end
|
183
193
|
|
184
|
-
s3_config =
|
194
|
+
s3_config = storage_config['s3']
|
185
195
|
begin
|
186
196
|
if !response && (transfer_type.empty? || transfer_type == :s3) && (s3_config && !s3_config.empty?)
|
187
197
|
_target_path = target_path
|
@@ -202,7 +212,7 @@ module Envoi
|
|
202
212
|
_response[:transfer_response] = transfer_response
|
203
213
|
|
204
214
|
if transfer_response.nil?
|
205
|
-
logger.warn { "No supported TransferClient configuration#{transfer_type && !transfer_type.empty? ? " for transfer type '#{transfer_type}'
|
215
|
+
logger.warn { "No supported TransferClient configuration#{transfer_type && !transfer_type.empty? ? " for transfer type '#{transfer_type}'" : ''} found in storage configuration." }
|
206
216
|
_response[:success] = false
|
207
217
|
return _response
|
208
218
|
end
|
@@ -240,7 +250,7 @@ module Envoi
|
|
240
250
|
# @option args [Hash] :import_options ({})
|
241
251
|
# @option args [String] :item_id
|
242
252
|
# @option args [Hash] :response_object ({})
|
243
|
-
# @option args [String] :
|
253
|
+
# @option args [String] :shape_tag (@default_vidispine_shape_tag)
|
244
254
|
# @option args [String] :storage_id
|
245
255
|
# @option args [String] :target_path
|
246
256
|
#
|
@@ -256,9 +266,8 @@ module Envoi
|
|
256
266
|
item_id = args[:item_id]
|
257
267
|
shape_tag = args[:shape_tag] || default_vidispine_shape_tag
|
258
268
|
|
259
|
-
|
260
|
-
|
261
|
-
|
269
|
+
item_add_args_in = args[:item_add_args] || { }
|
270
|
+
item_add_options_in = args[:item_add_options] || { }
|
262
271
|
|
263
272
|
# attach file to item as shape
|
264
273
|
path_on_storage = File.join(target_path, File.basename(file_path))
|
@@ -292,28 +301,26 @@ module Envoi
|
|
292
301
|
|
293
302
|
if item_id
|
294
303
|
item_shape_import_response = api_client.item_shape_import(item_id: item_id,
|
295
|
-
tag: shape_tag,
|
304
|
+
tag: shape_tag, file_id: file_id)
|
296
305
|
else
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
306
|
+
item_add_args = {
|
307
|
+
storage_id: storage_id,
|
308
|
+
file_path: path_on_storage,
|
309
|
+
file_id: file_id,
|
310
|
+
storage_path_map: { '/' => storage_id }
|
302
311
|
}
|
303
|
-
|
312
|
+
item_add_args.merge(item_add_args_in) if item_add_args_in.is_a?(Hash)
|
304
313
|
|
305
|
-
|
314
|
+
item_add_options = { }
|
315
|
+
item_add_options.merge!(item_add_options_in) if item_add_options_in.is_a?(Hash)
|
316
|
+
|
317
|
+
item_shape_import_response = api_client.item_add_using_file_path(item_add_args, item_add_options)
|
306
318
|
end
|
307
319
|
_response[:import_response] = item_shape_import_response
|
308
320
|
|
309
321
|
_response
|
310
322
|
end
|
311
323
|
|
312
|
-
def upload_transfer_spec_get(file_paths)
|
313
|
-
|
314
|
-
end
|
315
|
-
|
316
|
-
|
317
324
|
def ingest_file
|
318
325
|
# 1) export ASPERA_SCP_TOKEN="ATB3_AEA9dUI5dd2u1k8XBMVD0qInR-Lyylkz8AylTXLVt5_SMVGR8SO7Sdc0lj6RkoHK_DvAAEWac8bllF_Yan1NbbDTyPj_3BTA"
|
319
326
|
# 2) ascp -i asperaweb_id_dsa.openssh -P 33001 -l 20m /Users/nicholasstokes/Desktop/CantemoAgent.mov xfer@ats-aws-us-west-2.aspera.io:
|
@@ -42,6 +42,8 @@ module Envoi::Mam::Cantemo
|
|
42
42
|
args[:default_preserve_file_path] = args.fetch(:default_preserve_file_path, false)
|
43
43
|
|
44
44
|
@config = Envoi::Mam::Cantemo::Agent.load_config_from_file(args)
|
45
|
+
initialize_logger_from_config
|
46
|
+
|
45
47
|
cantemo_config = config[:cantemo] || config['cantemo']
|
46
48
|
|
47
49
|
@default_agent_class = Envoi::Mam::Cantemo::Agent
|
@@ -63,7 +65,7 @@ module Envoi::Mam::Cantemo
|
|
63
65
|
@ignored_file_paths_by_watch_folder = Hash.new { |h, k| h[k] = [] }
|
64
66
|
@ignored_file_paths_lock = Mutex.new
|
65
67
|
|
66
|
-
@threaded = args.fetch(:threaded, true)
|
68
|
+
@threaded = args.fetch(:threaded, config.fetch(:threaded, config.fetch('threaded', true)))
|
67
69
|
|
68
70
|
@default_maximum_active_processors = DEFAULT_WATCH_FOLDER_PROCESSOR_LIMIT
|
69
71
|
@processors_by_watch_folder = Hash.new { |h, k| h[k] = {} }
|
@@ -73,7 +75,7 @@ module Envoi::Mam::Cantemo
|
|
73
75
|
|
74
76
|
def initialize_logger(args = {})
|
75
77
|
@logger = args[:logger] ||= Logger.new(args[:log_to] || STDOUT)
|
76
|
-
log_level = args[:log_level] = Logger::
|
78
|
+
log_level = args[:log_level] = Logger::INFO
|
77
79
|
if log_level
|
78
80
|
@logger.level = log_level
|
79
81
|
args[:logger] = @logger
|
@@ -81,6 +83,18 @@ module Envoi::Mam::Cantemo
|
|
81
83
|
@logger
|
82
84
|
end
|
83
85
|
|
86
|
+
def initialize_logger_from_config(_config = @config)
|
87
|
+
logger_args = { }
|
88
|
+
log_to = _config['log_to']
|
89
|
+
logger_args[:log_to] = log_to if log_to
|
90
|
+
log_level = _config['log_level']
|
91
|
+
if log_level
|
92
|
+
_log_level = ['fatal', 'error', 'warn', 'info', 'debug'].find(log_level.downcase)
|
93
|
+
logger_args[:log_level] = _log_level.upcase if _log_level
|
94
|
+
end
|
95
|
+
initialize_logger(logger_args) unless logger_args.empty?
|
96
|
+
end
|
97
|
+
|
84
98
|
# @param [Hash] watch_folder_def
|
85
99
|
# @option watch_folder_def [String] path
|
86
100
|
# @option watch_folder_def [String] upload_to_storage_id
|
@@ -140,7 +154,7 @@ module Envoi::Mam::Cantemo
|
|
140
154
|
end
|
141
155
|
|
142
156
|
# @param [Object] file
|
143
|
-
# @return [
|
157
|
+
# @return [Hash]
|
144
158
|
def process_file(file)
|
145
159
|
file.processing = true
|
146
160
|
file_name = file.name || file.path
|
@@ -150,20 +164,26 @@ module Envoi::Mam::Cantemo
|
|
150
164
|
agent ||= default_agent
|
151
165
|
|
152
166
|
storage_id = watch_folder.definition['upload_to_storage_id']
|
153
|
-
quarantine_directory_path = watch_folder.definition['quarantine_directory_path']
|
154
|
-
completed_directory_path = watch_folder.definition['completed_directory_path']
|
155
|
-
import_args = watch_folder.definition['import_args']
|
156
|
-
import_options = watch_folder.definition['import_options']
|
157
167
|
|
158
|
-
# full_file_path = File.join(watch_folder.path, file.path)
|
159
|
-
full_file_path = file.path
|
160
168
|
unless storage_id
|
161
169
|
logger.warn { "Skipping processing of file because of missing storage ID." }
|
162
170
|
return { success: false, message: 'Missing storage ID.' }
|
163
171
|
end
|
164
172
|
|
165
|
-
|
166
|
-
|
173
|
+
quarantine_directory_path = watch_folder.definition['quarantine_directory_path']
|
174
|
+
completed_directory_path = watch_folder.definition['completed_directory_path']
|
175
|
+
watch_folder_upload_args = watch_folder.definition['upload_args']
|
176
|
+
|
177
|
+
# full_file_path = File.join(watch_folder.path, file.path)
|
178
|
+
full_file_path = file.path
|
179
|
+
|
180
|
+
upload_args = {
|
181
|
+
file_path: full_file_path,
|
182
|
+
storage_id: storage_id
|
183
|
+
}
|
184
|
+
upload_args.merge!(watch_folder_upload_args) if watch_folder_upload_args.is_a?(Hash)
|
185
|
+
|
186
|
+
_response = agent.upload(upload_args)
|
167
187
|
_response = { success: _response } if _response == true || _response == false
|
168
188
|
|
169
189
|
if _response[:success]
|
@@ -219,7 +239,6 @@ module Envoi::Mam::Cantemo
|
|
219
239
|
ignored_file_paths = @ignored_file_paths_by_watch_folder[wf]
|
220
240
|
end
|
221
241
|
|
222
|
-
|
223
242
|
stable_files.each do |file|
|
224
243
|
next if file.respond_to?(:ignore?) ? file.ignore? : ignored_file_paths.include?(file.path)
|
225
244
|
next if file.processing || file.processed
|
@@ -240,9 +259,9 @@ module Envoi::Mam::Cantemo
|
|
240
259
|
|
241
260
|
if @threaded
|
242
261
|
active_processors.keep_if { |k, v| k.processing }
|
243
|
-
if active_processors.length
|
262
|
+
if active_processors.length >= maximum_active_processors
|
244
263
|
logger.debug { "Maximum number of active processors reached for watch folder. #{wf.name || wf.paths}" }
|
245
|
-
|
264
|
+
break
|
246
265
|
end
|
247
266
|
t = Thread.new(file) do |file|
|
248
267
|
wf = file.watch_folder
|
@@ -302,7 +321,8 @@ module Envoi::Mam::Cantemo
|
|
302
321
|
end
|
303
322
|
logger.info { 'Exiting...' }
|
304
323
|
rescue => e
|
305
|
-
logger.
|
324
|
+
logger.debug { "EXCEPTION #{e.message} \n#{e.backtrace.join("\n")}\n" }
|
325
|
+
logger.error { "An error occurred. #{e.message}" }
|
306
326
|
raise e
|
307
327
|
ensure
|
308
328
|
watch_folders.each { |wf| wf.stop if wf.respond_to?(:stop) }
|
@@ -331,8 +351,6 @@ module Envoi::Mam::Cantemo
|
|
331
351
|
def self.run(args)
|
332
352
|
w = self.new(args)
|
333
353
|
w.run
|
334
|
-
rescue => e
|
335
|
-
abort("An error occurred. #{e.message}\n#{e.backtrace.join("\n")}")
|
336
354
|
end
|
337
355
|
|
338
356
|
def self.daemons_run_proc_with_cleanup(options, &block)
|
@@ -49,7 +49,7 @@ module Envoi
|
|
49
49
|
|
50
50
|
def initialize_logger(args = {})
|
51
51
|
@logger = args[:logger] ||= Logger.new(args[:log_to] || STDOUT)
|
52
|
-
log_level = args[:log_level] = Logger::
|
52
|
+
log_level = args[:log_level] = Logger::INFO
|
53
53
|
if log_level
|
54
54
|
@logger.level = log_level
|
55
55
|
args[:logger] = @logger
|
@@ -220,13 +220,20 @@ module Envoi
|
|
220
220
|
end
|
221
221
|
logger.debug { "Parameter 'upload to storage id' initialized." }
|
222
222
|
|
223
|
-
logger.debug { "Initializing parameter 'import
|
224
|
-
|
225
|
-
|
223
|
+
logger.debug { "Initializing parameter 'upload/import arguments'." }
|
224
|
+
upload_args = watch_folder_def['upload_args']
|
225
|
+
item_add_args = watch_folder_def['item_add_args']
|
226
|
+
item_add_options = watch_folder_def['item_add_options']
|
227
|
+
import_args = watch_folder_def['import_args'] || { }
|
228
|
+
import_options = watch_folder_def['import_options'] || { }
|
229
|
+
|
226
230
|
import_args = Hash[import_args.map { |k,v| [ k.respond_to?(:to_sym) ? k.to_sym.downcase : k, v ] }]
|
227
231
|
import_options = Hash[import_options.map { |k,v| [ k.respond_to?(:to_sym) ? k.to_sym.downcase : k, v ] }]
|
228
232
|
|
229
|
-
|
233
|
+
# Allow adding to collection to be overridden
|
234
|
+
add_item_to_collection = import_options.fetch(:add_item_to_collection,
|
235
|
+
import_args.fetch(:add_item_to_collection,
|
236
|
+
watch_folder_def['add_item_to_collection']))
|
230
237
|
if add_item_to_collection.nil? || add_item_to_collection
|
231
238
|
_add_item_to_collection = false
|
232
239
|
collection_id = watch_folder_def['collection_id']
|
@@ -256,10 +263,36 @@ module Envoi
|
|
256
263
|
if metadata
|
257
264
|
import_args[:metadata] = metadata
|
258
265
|
watch_folder_def.delete('metadata')
|
259
|
-
|
266
|
+
end
|
267
|
+
|
268
|
+
metadata_map = watch_folder_def['metadata_map']
|
269
|
+
metadata_group = watch_folder_def['metadata_group']
|
270
|
+
if metadata_map || metadata_group
|
271
|
+
((metadata_map ||= { })[:__build_metadata_document_options] ||= {})[:parent_group_name] = metadata_group if metadata_group
|
260
272
|
import_options[:metadata_map] ||= metadata_map if metadata_map
|
261
273
|
end
|
262
|
-
|
274
|
+
|
275
|
+
ingest_group = watch_folder_def['ingest_group']
|
276
|
+
if ingest_group
|
277
|
+
job_metadata = (import_args[:jobmetadata] ||= '')
|
278
|
+
job_metadata += ',' unless job_metadata.empty?
|
279
|
+
job_metadata += "portal_groups:StringArray=#{ingest_group}"
|
280
|
+
import_args[:jobmetadata] = job_metadata
|
281
|
+
end
|
282
|
+
|
283
|
+
item_add_args = symbolize_keys(item_add_args)
|
284
|
+
((item_add_args ||= {})[:import_args] ||= {}).merge! import_args if import_args.is_a?(Hash)
|
285
|
+
((item_add_args ||= {})[:import_options] ||= {}).merge! import_options if import_options.is_a?(Hash)
|
286
|
+
|
287
|
+
upload_args = symbolize_keys(upload_args)
|
288
|
+
((upload_args ||= {})[:item_add_args] ||= {}).merge! item_add_args if item_add_args.is_a?(Hash)
|
289
|
+
((upload_args ||= {})[:item_add_options] ||= {}).merge! symbolize_keys(item_add_options) if item_add_options.is_a?(Hash)
|
290
|
+
|
291
|
+
watch_folder_def.delete('import_args')
|
292
|
+
watch_folder_def.delete('import_options')
|
293
|
+
|
294
|
+
watch_folder_def['upload_args'] = upload_args
|
295
|
+
logger.debug { "Parameter 'upload/import arguments' initialized." }
|
263
296
|
|
264
297
|
|
265
298
|
maximum_active_processors = watch_folder_def['maximum_active_processors']
|
@@ -305,6 +338,21 @@ module Envoi
|
|
305
338
|
handler.stable_files
|
306
339
|
end
|
307
340
|
|
341
|
+
# Converts hash keys to symbols
|
342
|
+
#
|
343
|
+
# @param [Hash] value hash
|
344
|
+
# @param [Boolean] recursive Will recurse into any values that are hashes or arrays
|
345
|
+
def symbolize_keys (value, recursive = true)
|
346
|
+
case value
|
347
|
+
when Hash
|
348
|
+
Hash[value.map { |k,v| [ k.respond_to?(:to_sym) ? k.to_sym : k, recursive ? symbolize_keys(v, true) : v ] }]
|
349
|
+
when Array
|
350
|
+
value.map { |v| symbolize_keys(v, recursive) }
|
351
|
+
else
|
352
|
+
value
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
308
356
|
end
|
309
357
|
|
310
358
|
end
|
@@ -121,7 +121,7 @@ module Envoi
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def process_deleted_path(path)
|
124
|
-
return path.each { |path| process_deleted_path(path
|
124
|
+
return path.each { |path| process_deleted_path(path) } if path.is_a?(Array)
|
125
125
|
logger.debug { "PATH #{:deleted} '#{path}'" }
|
126
126
|
file = known_path_map[path]
|
127
127
|
known_path_map.delete(path)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cantemo-portal-agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Whitson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asperalm
|