eco-helpers 3.0.20 → 3.0.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96eaee3dd7897d77b22857cf8f812ce6d0639af324565c54f649c1e8068b7fb4
4
- data.tar.gz: c9af686fe8f01d45eb3ea6a0dc89de276b789dfd6e3f64b515e17107b233b2d3
3
+ metadata.gz: a7764e6e3e78228f59b9a5f5baf2aa8602c627882905a23270007b4fe1a09c9f
4
+ data.tar.gz: aca94b571b1c70c000e0d88f09182f2339a306187c5f9651968e9692981d79d9
5
5
  SHA512:
6
- metadata.gz: 66bdc8b7c98b2aa0e60e205ac64b47a302e2cd8dbe1efd1720ad36c04a4f4c1a70b2cbb4d4978c67a17bd0f86893d34b47ff809f95a3e06952c002b872872553
7
- data.tar.gz: f205d190dc159c0218bc1cafa52f139a6faaa133a01190ae1b189d2b8b6ef2470f49b634169effcf2021023803ec58f1793b8ce4c019db9d1dd025df7bbf5493
6
+ metadata.gz: bcef313643bc67ba9d90755e3ce8a3a3a39c1973404b2dcd35292b76c67d158ad3e9c666414e2f6254776eeb800f4d07fc2ab10953a15e9e2b293d2b8f15303e
7
+ data.tar.gz: 3d12155562df35e9ecadea021a758f922f35ab68d689592e4a319e41232b4865a87e22c0e333b1083e42340418f57388f24139748246d08652142ef52f1a041d
data/CHANGELOG.md CHANGED
@@ -2,7 +2,27 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [3.0.20] - 2024-12-xx
5
+ ## [3.0.21] - 2024-12-16
6
+
7
+ ### Added
8
+
9
+ - `Eco::API::Common::Session::Logger`
10
+ - Implement **channels** logging.
11
+
12
+ ### Changed
13
+
14
+ - Moved `input` and `people` **cli_default configurations** to a class definition
15
+ - `Eco::Language::AuxiliarLogger#log`
16
+ - Allow for multiple levels
17
+ - Return `NilClass`
18
+
19
+ ### Fixed
20
+
21
+ - `Eco::API::Session::Batch::Job#summary`
22
+ - Ensure a summary of pending jobs can be handled, even if `#launch` was NOT explicitly called.
23
+ - As we don't consolidate, it may give more actual updates than pending, yet this is better than providing the `count` of entries in the job's queue.
24
+
25
+ ## [3.0.20] - 2024-12-07
6
26
 
7
27
  ### Added
8
28
 
@@ -16,8 +36,6 @@ All notable changes to this project will be documented in this file.
16
36
 
17
37
  - On failure, `Eco::API::Session::Job#summary` to give precise estimates on what is pending to be run.
18
38
 
19
- ### Fixed
20
-
21
39
  ## [3.0.19] - 2024-11-21
22
40
 
23
41
  ### Added
@@ -0,0 +1,9 @@
1
+ class Eco::API::Common::Loaders::CliConfig < Eco::API::Common::Loaders::Config
2
+ class << self
3
+ def config
4
+ ASSETS.cli.config
5
+ end
6
+ end
7
+
8
+ delegate_missing_to :config
9
+ end
@@ -33,5 +33,6 @@ class Eco::API::Common::Loaders::Config
33
33
  delegate_missing_to :config
34
34
  end
35
35
 
36
+ require_relative 'config/cli'
36
37
  require_relative 'config/workflow'
37
38
  require_relative 'config/session'
@@ -27,7 +27,7 @@ class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Lo
27
27
  end
28
28
 
29
29
  def expected_headers
30
- log(:warn) {
30
+ log(:info) {
31
31
  "Headers detection is using your fields_map.json file (native behaviour)"
32
32
  }
33
33
  session.fields_mapper.list(:external).uniq
@@ -4,7 +4,8 @@ module Eco
4
4
  module Session
5
5
  class Logger
6
6
  class Cache
7
- LEVELS = %w[UNKNOWN FATAL ERROR WARN INFO DEBUG].freeze
7
+ LEVELS = %w[UNKNOWN FATAL ERROR WARN INFO DEBUG].freeze
8
+ CHANNELS = Logger::CHANNELS.map(&:to_s).map(&:upcase).freeze
8
9
 
9
10
  def initialize
10
11
  reset
@@ -56,7 +57,8 @@ module Eco
56
57
  end
57
58
 
58
59
  def to_datetime(value)
59
- return nil unless value
60
+ return unless value
61
+
60
62
  Time.parse(value)
61
63
  end
62
64
 
@@ -64,7 +66,7 @@ module Eco
64
66
  levels = [value].flatten.map {|v| to_level(v)}.compact
65
67
  return levels unless levels.empty?
66
68
 
67
- LEVELS
69
+ valid_levels
68
70
  end
69
71
 
70
72
  def to_level(value)
@@ -75,7 +77,7 @@ module Eco
75
77
 
76
78
  def valid_level!(str)
77
79
  return true unless str
78
- return true if LEVELS.any? {|lev| str == lev}
80
+ return true if valid_levels.any? {|lev| str == lev}
79
81
 
80
82
  msg = "Unknown level #{str}. Should be one of #{LEVELS}"
81
83
  raise ArgumentError, msg
@@ -87,6 +89,10 @@ module Eco
87
89
 
88
90
  value
89
91
  end
92
+
93
+ def valid_levels
94
+ @valid_levels ||= self.class::LEVELS | self.class::CHANNELS
95
+ end
90
96
  end
91
97
  end
92
98
  end
@@ -0,0 +1,41 @@
1
+ module Eco
2
+ module API
3
+ module Common
4
+ module Session
5
+ class Logger
6
+ module Channels
7
+ CHANNELS = %i[general].freeze
8
+
9
+ class << self
10
+ def included(base)
11
+ super
12
+ base.extend ClassMethods
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def channels!(&def_block)
18
+ str = "Block with channel implementation expected. None given."
19
+ raise ArgumentError, str unless block_given?
20
+
21
+ channels.each do |channel|
22
+ meth = channel.to_s.downcase.to_sym
23
+
24
+ define_method(meth) do |msg = nil, &block|
25
+ def_block.call(meth, msg, &block)
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def channels
33
+ self::CHANNELS
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -5,6 +5,15 @@ module Eco
5
5
  class Logger < Eco::Language::BasicLogger
6
6
  TIMESTAMP_PATTERN = '%Y-%m-%dT%H:%M:%S'.freeze
7
7
 
8
+ require_relative 'logger/channels'
9
+ include Channels
10
+
11
+ channels! do |channel, message = nil, &block|
12
+ format_proc(console: true) do |severity, datetime, msg, formatted_msg|
13
+ cache.add(severity, datetime, msg, formatted_msg)
14
+ end.call(channel, Time.now, 'prog_name', message || block.call)
15
+ end
16
+
8
17
  attr_reader :cache
9
18
 
10
19
  def initialize(file_level: ::Logger::DEBUG, log_file: nil, enviro: nil, **kargs)
@@ -146,6 +146,16 @@ module Eco
146
146
  @pending
147
147
  end
148
148
 
149
+ # @note some times we need a summary of what actually
150
+ # is going to be run without invoking `launch`
151
+ # (i.e. when there's a uncompliance with the batch policy)
152
+ def ensure_requests!
153
+ return if instance_variable_defined?(:@requests)
154
+
155
+ pqueue = processed_queue
156
+ @requests = as_update(pqueue)
157
+ end
158
+
149
159
  # @note it requires launch to be firstly invoked
150
160
  # @raise [Exception] if 'launch' has not firstly invoked
151
161
  # @return [Enumbrable<Hash>] the last requests that the queue will generate
@@ -250,6 +260,7 @@ module Eco
250
260
  def summary
251
261
  [].tap do |msg|
252
262
  msg << "PENDING Job -------->\n" if pending?
263
+ ensure_requests!
253
264
  msg << feedback.generate(requests, only_stats: true)
254
265
 
255
266
  if batch_policy && !batch_policy.compliant?(request_stats)
@@ -1,6 +1,5 @@
1
- # rubocop:disable Metrics/BlockLength
2
- ASSETS.cli.config do |cnf|
3
- formats = {
1
+ class Eco::CliDefault::Input < Eco::API::Common::Loaders::CliConfig
2
+ FORMATS = {
4
3
  csv: {
5
4
  option: ["-csv"],
6
5
  extname: [".csv", ".txt"]
@@ -17,51 +16,74 @@ ASSETS.cli.config do |cnf|
17
16
  option: ["-json"],
18
17
  extname: [".json"]
19
18
  }
20
- }
19
+ }.freeze
21
20
 
22
- cnf.input(default_option: "-entries-from") do |session, str_opt, options|
23
- input = []
21
+ class << self
22
+ attr_reader :options, :session
24
23
 
24
+ def encoding
25
+ options.dig(:input, :file, :encoding)
26
+ end
27
+
28
+ def format_by_cli
29
+ FORMATS.reduce(nil) do |matched, (frm, selectors)|
30
+ next matched if matched
31
+
32
+ used = selectors[:option].reduce(false) do |us, option|
33
+ SCR.get_arg(option) || us
34
+ end
35
+
36
+ next frm if used
37
+ end
38
+ end
39
+
40
+ def format_by_ext(ext)
41
+ FORMATS.reduce(nil) do |matched, (frm, selectors)|
42
+ next matched if matched
43
+ next frm if selectors[:extname].any? {|e| ext == e}
44
+ end
45
+ end
46
+ end
47
+
48
+ input(default_option: "-entries-from") do |session, str_opt, options|
49
+ @options = options
50
+ @session = session
51
+ input = []
25
52
  next input unless SCR.get_arg(str_opt)
26
53
 
27
54
  file = SCR.get_file(str_opt, required: true)
28
55
 
29
56
  # Command line check
30
- format = formats.reduce(nil) do |matched, (frm, selectors)|
31
- used = selectors[:option].reduce(false) {|us, option| SCR.get_arg(option) || us}
32
- next matched if matched
33
- next frm if used
34
- end
57
+ format = format_by_cli
35
58
 
36
59
  # File/Folder check
37
60
  file = File.expand_path(file)
61
+
38
62
  if File.directory?(file)
39
63
  folder = file
40
64
  file = Dir.glob("#{file}/*").reject {|f| File.directory?(f)}
41
- ext = (format && formats[format][:extname]) || [File.extname(file.first)]
42
- file = file.select {|f| ext.any? {|e| File.extname(f) == e}}.tap do |files|
43
- if files.empty?
44
- session.log(:error) {
45
- "Could not find any file with extension: #{ext} in folder '#{folder}'"
46
- }
47
- exit(1)
48
- end
65
+ ext = FORMATS.dig(format, :extname)
66
+ ext ||= [File.extname(file.first)]
67
+ file = file.select do |f|
68
+ ext.any? {|e| File.extname(f) == e}
69
+ end.tap do |files|
70
+ next unless files.empty?
71
+
72
+ session.log(:error) {
73
+ "Could not find any file with extension: #{ext} in folder '#{folder}'"
74
+ }
75
+ exit(1)
49
76
  end
50
77
  else
51
- ext = File.extname(file)
78
+ ext = [File.extname(file)]
52
79
  end
53
80
 
54
- format ||= formats.reduce(nil) do |matched, (frm, selectors)|
55
- next matched if matched
56
- next frm if selectors[:extname].any? {|e| ext == e}
57
- end
81
+ format ||= format_by_ext(ext.first)
58
82
  format ||= :csv
59
83
 
60
- options.deep_merge!(input: {file: {name: file}})
84
+ options.deep_merge!(input: {file: {name: file}})
61
85
  options.deep_merge!(input: {file: {format: format}})
62
86
 
63
- encoding = options.dig(:input, :file, :encoding)
64
-
65
87
  case format
66
88
  when :xml
67
89
  [file].flatten.each {|f| session.config.files.validate(:xml, f)}
@@ -83,5 +105,3 @@ ASSETS.cli.config do |cnf|
83
105
  input
84
106
  end
85
107
  end
86
-
87
- # rubocop:enable Metrics/BlockLength
@@ -69,7 +69,10 @@ ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
69
69
  sch_id = session.schemas.to_id(sch_name)
70
70
 
71
71
  unless sch_id
72
- msg = "You need to specify a correct schema id or name. '#{sch_name}' does not exist"
72
+ msg = "You need to specify a correct schema id or name. "
73
+ msg << "'#{sch_name}' does not exist. Correct options are: "
74
+ msg << session.schemas.map(&:name).join(", ")
75
+
73
76
  session.log(:error) { msg }
74
77
  exit(1)
75
78
  end
@@ -1,69 +1,124 @@
1
- MAX_GET_PARTIAL = 12_000
1
+ class Eco::CliDefault::People < Eco::API::Common::Loaders::CliConfig
2
+ MAX_GET_PARTIAL = 12_000
2
3
 
3
- ASSETS.cli.config do |cnf|
4
- cnf.people do |input, session, options|
5
- get = options.dig(:people, :get)
6
- get = {} if get.nil?
4
+ class << self
5
+ attr_reader :options, :session
6
+ attr_writer :get_full, :get_partial
7
7
 
8
- from_remote = get && get[:from] == :remote
9
- from_local = get && get[:from] == :local
8
+ def get_options # rubocop:disable Naming/AccessorMethodName
9
+ get = options.dig(:people, :get)
10
+ get = {} if get.nil?
11
+ get
12
+ end
13
+
14
+ def no_get?
15
+ get_options == false
16
+ end
10
17
 
11
- get_full = from_remote && get[:type] == :full
12
- get_partial = from_remote && get[:type] == :partial
13
- get_by_file = from_local && get[:type] == :file
18
+ def from_remote?
19
+ return false unless get_options
20
+
21
+ get_options[:from] == :remote
22
+ end
23
+
24
+ def from_local?
25
+ return false unless get_options
26
+
27
+ get_options[:from] == :local
28
+ end
29
+
30
+ def get_full?
31
+ return @get_full if instance_variable_defined?(:@get_full)
32
+ return false unless from_remote?
33
+
34
+ get_options[:type] == :full
35
+ end
36
+
37
+ def get_partial?
38
+ return @get_partial if instance_variable_defined?(:@get_partial)
39
+ return false unless from_remote?
40
+
41
+ @get_partial = (get_options[:type] == :partial)
42
+ end
43
+
44
+ def get_by_file?
45
+ return false unless from_local?
46
+
47
+ get_options[:type] == :file
48
+ end
49
+
50
+ def source_file
51
+ return unless get_by_file?
52
+
53
+ get_options[:file]
54
+ end
55
+
56
+ def switch_to_full_remote!
57
+ self.get_full = true
58
+ self.get_partial = false
59
+
60
+ options.deep_merge!(people: {
61
+ get: {
62
+ from: :remote,
63
+ type: :full
64
+ }
65
+ })
66
+ end
67
+
68
+ def switch_to_full_local!
69
+ self.get_full = true
70
+ self.get_partial = false
71
+
72
+ options.deep_merge!(people: {
73
+ get: {
74
+ from: :local,
75
+ type: :full
76
+ }
77
+ })
78
+ end
79
+
80
+ def optimize_get_partial!(input)
81
+ return unless get_partial?
14
82
 
15
- # -get-partial: validate input present and under max
16
- if get_partial
17
83
  msg = "To use -get-partial (partial updates), you need to use -entries-from"
18
84
  raise msg unless input.is_a?(Enumerable)
19
85
 
20
- if input.count > MAX_GET_PARTIAL
21
- get_full = true
22
- get_partial = false
23
-
24
- msg = "(Optimization) "
25
- msg << "Switching from partial to full people download. "
26
- msg << "Input (#{input.count}) surpases MAX_GET_PARTIAL "
27
- msg << "(#{MAX_GET_PARTIAL}) entries."
28
- session.log(:info) { msg }
29
-
30
- options.deep_merge!(people: {
31
- get: {
32
- from: :remote,
33
- type: :full
34
- }
35
- })
36
- end
86
+ return unless input.count > MAX_GET_PARTIAL
87
+
88
+ msg = "(Optimization) "
89
+ msg << "Switching from partial to full people download. "
90
+ msg << "Input (#{input.count}) surpases MAX_GET_PARTIAL "
91
+ msg << "(#{MAX_GET_PARTIAL}) entries."
92
+ session.log(:info) { msg }
93
+
94
+ switch_to_full_remote!
37
95
  end
96
+ end
97
+
98
+ people do |input, session, options|
99
+ @options = options
100
+ @session = session
38
101
 
39
- if get == false
102
+ # -get-partial: validate input present and under max
103
+ optimize_get_partial!(input) if get_partial?
104
+
105
+ if no_get?
40
106
  Eco::API::Organization::People.new([])
41
- elsif get_full
107
+ elsif get_full?
42
108
  # -get-people
43
109
  session.micro.people_cache
44
- elsif get_partial
110
+ elsif get_partial?
45
111
  # -get-partial
46
112
  session.micro.people_search(input, options: options)
47
- elsif get_by_file
113
+ elsif get_by_file?
48
114
  # -people-from-backup
49
- session.micro.people_load(get[:file], modifier: :file)
115
+ session.micro.people_load(source_file, modifier: :file)
50
116
  else
51
- options.deep_merge!(people: {
52
- get: {
53
- from: :local,
54
- type: :full
55
- }
56
- })
57
-
117
+ switch_to_full_local!
58
118
  people = session.micro.people_load(modifier: %i[newest save])
59
119
 
60
120
  if people.empty?
61
- options.deep_merge!(people: {
62
- get: {
63
- from: :remote,
64
- type: :full
65
- }
66
- })
121
+ switch_to_full_remote!
67
122
  people = session.micro.people_cache
68
123
  end
69
124
 
@@ -92,7 +92,10 @@ ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
92
92
  sch_id = session.schemas.to_id(sch_name)
93
93
 
94
94
  unless sch_id
95
- msg = "You need to specify a correct schema id or name. '#{sch_name}' does not exist"
95
+ msg = "You need to specify a correct schema id or name. "
96
+ msg << "'#{sch_name}' does not exist. Correct options are: "
97
+ msg << session.schemas.map(&:name).join(", ")
98
+
96
99
  session.log(:error) { msg }
97
100
  exit(1)
98
101
  end
@@ -21,10 +21,23 @@ module Eco
21
21
  end
22
22
 
23
23
  # Shortcut to logger.
24
- def log(level, &block)
25
- return unless logger.respond_to?(:level)
24
+ # @todo allow for more channels (atm it's just :general )
25
+ # @note when `:general` is included, it ensures at least
26
+ # `:info` level is also logged.
27
+ # @return [NilClass]
28
+ def log(*levels, &block)
29
+ return unless logger
26
30
 
27
- logger&.send(level, &block)
31
+ levels = levels.compact.uniq.map(&:to_sym)
32
+ levels.unshift(:info) if levels.include?(:general) && levels.length == 1
33
+
34
+ levels.each do |level|
35
+ next unless logger.respond_to?(:level)
36
+
37
+ logger.send(level, &block)
38
+ end
39
+
40
+ nil
28
41
  end
29
42
  end
30
43
  end
@@ -67,6 +67,7 @@ module Eco
67
67
  def format_proc(console: true, &block)
68
68
  proc do |severity, datetime, _progname, msg|
69
69
  str_stamp = console ? console_timestamp(datetime) : timestamp(datetime)
70
+
70
71
  "#{severity.to_s[0]}: #{str_stamp}#{msg}\n".tap do |formatted_msg|
71
72
  block&.call(severity, datetime, msg, formatted_msg)
72
73
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '3.0.20'.freeze
2
+ VERSION = '3.0.21'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.20
4
+ version: 3.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-07 00:00:00.000000000 Z
11
+ date: 2024-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -538,6 +538,7 @@ files:
538
538
  - lib/eco/api/common/loaders/base.rb
539
539
  - lib/eco/api/common/loaders/case_base.rb
540
540
  - lib/eco/api/common/loaders/config.rb
541
+ - lib/eco/api/common/loaders/config/cli.rb
541
542
  - lib/eco/api/common/loaders/config/session.rb
542
543
  - lib/eco/api/common/loaders/config/workflow.rb
543
544
  - lib/eco/api/common/loaders/config/workflow/mailer.rb
@@ -580,6 +581,7 @@ files:
580
581
  - lib/eco/api/common/session/helpers/prompt_user.rb
581
582
  - lib/eco/api/common/session/logger.rb
582
583
  - lib/eco/api/common/session/logger/cache.rb
584
+ - lib/eco/api/common/session/logger/channels.rb
583
585
  - lib/eco/api/common/session/logger/log.rb
584
586
  - lib/eco/api/common/session/mailer.rb
585
587
  - lib/eco/api/common/session/mailer/aws_provider.rb