judges 0.3.0 ā†’ 0.5.0

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: be8151f228edd7b8c45f0fcf1f566e8585fae93ce87bcb7f56ca6f452a1b67ca
4
- data.tar.gz: 99e20604a1f8a78a0c5dbf4080522aab725a7e82df5cb87d3b456962636aad10
3
+ metadata.gz: 8eed10a2293bdfe6ddfc33e7623d7eb8f905428f60fd002c55e7eb75afdcd96f
4
+ data.tar.gz: df6b6941021d0c4fbcdb22d4608d41365ca7e537104eda09909f56cb4dd8dd3d
5
5
  SHA512:
6
- metadata.gz: 2df81af8fd18810e54c05fc3631a2e38037d45e49a7f87cd4e9e8592155b155b81671ad5641e3923886e86752fa3be8c5f7926f2ce539d48ccfac714269f44d4
7
- data.tar.gz: 6fd2568f060510bc0b0600cc9d186d622025a7f886085bf5993bc3388f246c283c2c08c785199d609fd7a4729eb949a27a829d199785d43334addbdcd7f51248
6
+ metadata.gz: 07a943829af24cf0388303f9804f8b476449e3feea10ec3fa3703278ffb96e3b8c7a342d06e611e99168a8711397c380fdb70e8504fecaa22be48a6db0627550
7
+ data.tar.gz: 605f4d9c1598a4950098837ae6d8a8a432b882d1d4da75f93df78e530a584101642fbed0eb76d3df728f7dae4adbe30fb86c517ded6c16ff13f907b89ee4f797
data/Gemfile.lock CHANGED
@@ -9,14 +9,15 @@ PATH
9
9
  iri (~> 0.8)
10
10
  loog (~> 0.2)
11
11
  nokogiri (~> 1.10)
12
+ retries (~> 0.0)
12
13
  typhoeus (~> 1.3)
13
14
 
14
15
  GEM
15
16
  remote: https://rubygems.org/
16
17
  specs:
17
- actionpack (7.1.3.3)
18
- actionview (= 7.1.3.3)
19
- activesupport (= 7.1.3.3)
18
+ actionpack (7.1.3.4)
19
+ actionview (= 7.1.3.4)
20
+ activesupport (= 7.1.3.4)
20
21
  nokogiri (>= 1.8.5)
21
22
  racc
22
23
  rack (>= 2.2.4)
@@ -24,13 +25,13 @@ GEM
24
25
  rack-test (>= 0.6.3)
25
26
  rails-dom-testing (~> 2.2)
26
27
  rails-html-sanitizer (~> 1.6)
27
- actionview (7.1.3.3)
28
- activesupport (= 7.1.3.3)
28
+ actionview (7.1.3.4)
29
+ activesupport (= 7.1.3.4)
29
30
  builder (~> 3.1)
30
31
  erubi (~> 1.11)
31
32
  rails-dom-testing (~> 2.2)
32
33
  rails-html-sanitizer (~> 1.6)
33
- activesupport (7.1.3.3)
34
+ activesupport (7.1.3.4)
34
35
  base64
35
36
  bigdecimal
36
37
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -84,7 +85,7 @@ GEM
84
85
  erubi (1.12.0)
85
86
  ethon (0.16.0)
86
87
  ffi (>= 1.15.0)
87
- factbase (0.0.41)
88
+ factbase (0.0.42)
88
89
  json (~> 2.7)
89
90
  loog (~> 0.2)
90
91
  nokogiri (~> 1.10)
@@ -153,9 +154,9 @@ GEM
153
154
  rails-html-sanitizer (1.6.0)
154
155
  loofah (~> 2.21)
155
156
  nokogiri (~> 1.14)
156
- railties (7.1.3.3)
157
- actionpack (= 7.1.3.3)
158
- activesupport (= 7.1.3.3)
157
+ railties (7.1.3.4)
158
+ actionpack (= 7.1.3.4)
159
+ activesupport (= 7.1.3.4)
159
160
  irb
160
161
  rackup (>= 1.0.0)
161
162
  rake (>= 12.2)
@@ -168,6 +169,7 @@ GEM
168
169
  regexp_parser (2.9.2)
169
170
  reline (0.5.8)
170
171
  io-console (~> 0.5)
172
+ retries (0.0.5)
171
173
  rexml (3.2.8)
172
174
  strscan (>= 3.0.9)
173
175
  rspec-core (3.13.0)
data/bin/judges CHANGED
@@ -155,9 +155,9 @@ class App
155
155
  c.desc 'The IP/hostname of the server'
156
156
  c.flag([:host], default_value: 'www.zerocracy.com')
157
157
  c.desc 'The TCP port number of the server'
158
- c.flag([:port], default_value: 443)
158
+ c.flag([:port], default_value: 443, type: Integer)
159
159
  c.desc 'Connection and read time in seconds'
160
- c.flag([:timeout], default_value: 30)
160
+ c.flag([:timeout], default_value: 30, type: Integer)
161
161
  c.desc 'Shall SSL be used?'
162
162
  c.switch([:ssl], default_value: true)
163
163
  c.action do |global, options, args|
@@ -170,12 +170,14 @@ class App
170
170
  command :pull do |c|
171
171
  c.desc 'Authentication token'
172
172
  c.flag([:token])
173
+ c.desc 'How many seconds to wait'
174
+ c.flag([:wait], default_value: 10 * 60, arg_name: '<seconds>', type: Integer)
173
175
  c.desc 'The IP/hostname of the server'
174
176
  c.flag([:host], default_value: 'www.zerocracy.com')
175
177
  c.desc 'The TCP port number of the server'
176
- c.flag([:port], default_value: 443)
178
+ c.flag([:port], default_value: 443, type: Integer)
177
179
  c.desc 'Connection and read time in seconds'
178
- c.flag([:timeout], default_value: 30)
180
+ c.flag([:timeout], default_value: 30, type: Integer)
179
181
  c.desc 'Shall SSL be used?'
180
182
  c.switch([:ssl], default_value: true)
181
183
  c.action do |global, options, args|
@@ -4,7 +4,7 @@ Feature: Pull
4
4
  Scenario: Pull a small factbase
5
5
  Given We are online
6
6
  Given I make a temp directory
7
- Then I run bin/judges with "--verbose pull --token 00000000-0000-0000-0000-000000000000 simple simple.fb"
7
+ Then I run bin/judges with "--verbose pull --token 00000000-0000-0000-0000-000000000000 --wait=15 simple simple.fb"
8
8
  Then Stdout contains "Pulled"
9
9
  And Exit code is zero
10
10
  Then I run bin/judges with "inspect simple.fb"
data/judges.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=3.2'
28
28
  s.name = 'judges'
29
- s.version = '0.3.0'
29
+ s.version = '0.5.0'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Command-Line Tool for a Factbase'
32
32
  s.description =
@@ -42,13 +42,14 @@ Gem::Specification.new do |s|
42
42
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
43
43
  s.rdoc_options = ['--charset=UTF-8']
44
44
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
45
- s.add_runtime_dependency 'backtrace', '~> 0.3'
45
+ s.add_runtime_dependency 'backtrace', '~>0.3'
46
46
  s.add_runtime_dependency 'concurrent-ruby', '1.2.3'
47
47
  s.add_runtime_dependency 'factbase', '~>0.0'
48
48
  s.add_runtime_dependency 'gli', '~>2.21'
49
49
  s.add_runtime_dependency 'iri', '~>0.8'
50
50
  s.add_runtime_dependency 'loog', '~>0.2'
51
- s.add_runtime_dependency 'nokogiri', '~> 1.10'
51
+ s.add_runtime_dependency 'nokogiri', '~>1.10'
52
+ s.add_runtime_dependency 'retries', '~>0.0'
52
53
  s.add_runtime_dependency 'typhoeus', '~>1.3'
53
54
  s.metadata['rubygems_mfa_required'] = 'true'
54
55
  end
data/lib/judges/baza.rb CHANGED
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'typhoeus'
24
+ require 'retries'
24
25
  require 'iri'
25
26
  require 'loog'
26
27
  require_relative '../judges'
@@ -45,17 +46,20 @@ class Judges::Baza
45
46
  def push(name, data)
46
47
  id = 0
47
48
  elapsed(@loog) do
48
- ret = Typhoeus::Request.put(
49
- home.append('push').append(name).to_s,
50
- body: data,
51
- headers: headers.merge(
52
- 'Content-Type' => 'application/octet-stream',
53
- 'Content-Length' => data.size
54
- ),
55
- connecttimeout: @timeout,
56
- timeout: @timeout
57
- )
58
- check_code(ret)
49
+ ret = with_retries do
50
+ checked(
51
+ Typhoeus::Request.put(
52
+ home.append('push').append(name).to_s,
53
+ body: data,
54
+ headers: headers.merge(
55
+ 'Content-Type' => 'application/octet-stream',
56
+ 'Content-Length' => data.size
57
+ ),
58
+ connecttimeout: @timeout,
59
+ timeout: @timeout
60
+ )
61
+ )
62
+ end
59
63
  id = ret.body.to_i
60
64
  throw :"Pushed #{data.size} bytes to #{@host}, job ID is ##{id}"
61
65
  end
@@ -79,7 +83,7 @@ class Judges::Baza
79
83
  f.write(chunk)
80
84
  end
81
85
  request.run
82
- check_code(request.response)
86
+ checked(request.response)
83
87
  end
84
88
  data = File.binread(file)
85
89
  throw :"Pulled #{data.size} bytes of job ##{id} factbase at #{@host}"
@@ -92,11 +96,14 @@ class Judges::Baza
92
96
  def finished?(id)
93
97
  finished = false
94
98
  elapsed(@loog) do
95
- ret = Typhoeus::Request.get(
96
- home.append('finished').append(id).to_s,
97
- headers:
98
- )
99
- check_code(ret)
99
+ ret = with_retries do
100
+ checked(
101
+ Typhoeus::Request.get(
102
+ home.append('finished').append(id).to_s,
103
+ headers:
104
+ )
105
+ )
106
+ end
100
107
  finished = ret.body == 'yes'
101
108
  throw :"The job ##{id} is #{finished ? '' : 'not yet '}finished at #{@host}"
102
109
  end
@@ -106,11 +113,14 @@ class Judges::Baza
106
113
  def recent(name)
107
114
  job = 0
108
115
  elapsed(@loog) do
109
- ret = Typhoeus::Request.get(
110
- home.append('recent').append("#{name}.txt").to_s,
111
- headers:
112
- )
113
- check_code(ret)
116
+ ret = with_retries do
117
+ checked(
118
+ Typhoeus::Request.get(
119
+ home.append('recent').append("#{name}.txt").to_s,
120
+ headers:
121
+ )
122
+ )
123
+ end
114
124
  job = ret.body.to_i
115
125
  throw :"The recent \"#{name}\" job's ID is ##{job} at #{@host}"
116
126
  end
@@ -120,11 +130,12 @@ class Judges::Baza
120
130
  def name_exists?(name)
121
131
  exists = 0
122
132
  elapsed(@loog) do
123
- ret = Typhoeus::Request.get(
124
- home.append('exists').append(name).to_s,
125
- headers:
133
+ ret = checked(
134
+ Typhoeus::Request.get(
135
+ home.append('exists').append(name).to_s,
136
+ headers:
137
+ )
126
138
  )
127
- check_code(ret)
128
139
  exists = ret.body == 'yes'
129
140
  throw :"The name \"#{name}\" #{exists ? 'exists' : "doesn't exist"} at #{@host}"
130
141
  end
@@ -148,14 +159,14 @@ class Judges::Baza
148
159
  .scheme(@ssl ? 'https' : 'http')
149
160
  end
150
161
 
151
- def check_code(ret, allowed = [200])
162
+ def checked(ret, allowed = [200])
152
163
  allowed = [allowed] unless allowed.is_a?(Array)
153
164
  mtd = (ret.request.original_options[:method] || '???').upcase
154
165
  url = ret.effective_url
155
166
  log = "#{mtd} #{url} -> #{ret.code}"
156
167
  if allowed.include?(ret.code)
157
168
  @loog.debug(log)
158
- return
169
+ return ret
159
170
  end
160
171
  @loog.debug("#{log}\n #{(ret.headers || {}).map { |k, v| "#{k}: #{v}" }.join("\n ")}")
161
172
  msg =
@@ -47,7 +47,7 @@ class Judges::Pull
47
47
  name = args[0]
48
48
  elapsed(@loog) do
49
49
  if baza.name_exists?(name)
50
- fb.import(baza.pull(wait(baza, baza.recent(name))))
50
+ fb.import(baza.pull(wait(baza, baza.recent(name), opts['wait'])))
51
51
  Judges::Impex.new(@loog, args[1]).export(fb)
52
52
  throw :"Pulled #{fb.size} facts by the name '#{name}'"
53
53
  else
@@ -58,12 +58,14 @@ class Judges::Pull
58
58
 
59
59
  private
60
60
 
61
- def wait(baza, id)
61
+ def wait(baza, id, limit)
62
+ raise 'Waiting time is nil' if limit.nil?
62
63
  start = Time.now
63
64
  loop do
64
65
  break if baza.finished?(id)
65
66
  sleep 1
66
- raise 'Time is over, the job is still not finished' if Time.now - start > 10 * 60
67
+ raise 'Time is over, the job is still not finished' if Time.now - start > limit
68
+ @loog.debug("Still waiting for the job ##{id} to finish... (#{format('%.2f', Time.now - start)}s already)")
67
69
  end
68
70
  id
69
71
  end
@@ -69,7 +69,7 @@ class Judges::Test
69
69
  end
70
70
  @loog.info("šŸ› ļø Testing #{f.to_rel}:")
71
71
  begin
72
- test_one(opts, p, yaml)
72
+ test_one(opts, p, tname, yaml)
73
73
  tests += 1
74
74
  rescue StandardError => e
75
75
  @loog.warn(Backtrace.new(e))
@@ -106,7 +106,7 @@ class Judges::Test
106
106
  judges.any? { |n| n.match?(%r{^#{name}(/#{tre})?$}) }
107
107
  end
108
108
 
109
- def test_one(opts, judge, yaml)
109
+ def test_one(opts, judge, tname, yaml)
110
110
  fb = Factbase.new
111
111
  inputs = yaml['input']
112
112
  inputs&.each do |i|
@@ -127,7 +127,7 @@ class Judges::Test
127
127
  return if xpaths.nil?
128
128
  xml = Nokogiri::XML.parse(Factbase::ToXML.new(fb).xml)
129
129
  xpaths.each do |xp|
130
- raise "#{judge.script} doesn't match '#{xp}':\n#{xml}" if xml.xpath(xp).empty?
130
+ raise "#{judge.name}/#{tname} doesn't match '#{xp}':\n#{xml}" if xml.xpath(xp).empty?
131
131
  end
132
132
  end
133
133
  end
@@ -56,9 +56,9 @@ class Judges::Update
56
56
  if c > 1
57
57
  @loog.info("\n\nStarting cycle ##{c}#{opts['max-cycles'] ? " (out of #{opts['max-cycles']})" : ''}...")
58
58
  end
59
- diff = cycle(opts, judges, fb, options)
59
+ churn = cycle(opts, judges, fb, options)
60
60
  impex.export(fb)
61
- if diff.zero?
61
+ if churn.zero?
62
62
  @loog.info("The update cycle ##{c} has made no changes to the factbase, let's stop")
63
63
  break
64
64
  end
@@ -66,36 +66,52 @@ class Judges::Update
66
66
  @loog.info("Too many cycles already, as set by --max-cycles=#{opts['max-cycles']}, breaking")
67
67
  break
68
68
  end
69
- @loog.info(
70
- "By #{diff.abs} fact(s) the factbase " \
71
- "#{diff.positive? ? 'increased' : 'decreased'} " \
72
- "its size at the cycle ##{c}"
73
- )
69
+ @loog.info("At the cycle #{c}, the factbase was modified by #{churn} fact(s)")
74
70
  end
75
71
  throw :"Update finished in #{c} cycle(s), #{format('+%d', fb.size - before)} fact(s)"
76
72
  end
77
73
  end
78
74
 
75
+ # How many facts were modified.
76
+ class Churn
77
+ attr_reader :added, :removed
78
+
79
+ def initialize(added, removed)
80
+ @added = added
81
+ @removed = removed
82
+ end
83
+
84
+ def to_s
85
+ "#{@added}/-#{@removed}"
86
+ end
87
+
88
+ def zero?
89
+ @added.zero? && @removed.zero?
90
+ end
91
+
92
+ def +(other)
93
+ Churn.new(@added + other.added, @removed + other.removed)
94
+ end
95
+ end
96
+
79
97
  private
80
98
 
99
+ # Run all judges in a full cycle, one by one.
100
+ # @return [Churn] How many modifications have been made
81
101
  def cycle(opts, judges, fb, options)
82
102
  errors = []
83
- diff = 0
103
+ churn = Churn.new(0, 0)
84
104
  global = {}
85
105
  elapsed(@loog) do
86
106
  done = judges.each_with_index do |p, i|
87
- local = {}
88
107
  @loog.info("\nšŸ‘‰ Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
89
- before = fb.size
90
- begin
91
- p.run(fb, global, local, options)
92
- rescue StandardError, SyntaxError => e
93
- @loog.warn(Backtrace.new(e))
94
- errors << p.script
108
+ elapsed(@loog) do
109
+ churn += one_judge(fb, p, global, options)
110
+ throw :"šŸ‘ The judge #{p.name} modified #{churn} facts\n"
95
111
  end
96
- after = fb.size
97
- @loog.info("šŸ‘ The judge #{p.dir.to_rel} added #{after - before} facts") if after > before
98
- diff += after - before
112
+ rescue StandardError, SyntaxError => e
113
+ @loog.warn(Backtrace.new(e))
114
+ errors << p.script
99
115
  end
100
116
  throw :"šŸ‘ #{done} judge(s) processed" if errors.empty?
101
117
  throw :"āŒ #{done} judge(s) processed with #{errors.size} errors"
@@ -104,6 +120,21 @@ class Judges::Update
104
120
  raise "Failed to update correctly (#{errors.size} errors)" unless opts['quiet']
105
121
  @loog.info('Not failing because of the --quiet flag provided')
106
122
  end
107
- diff
123
+ churn
124
+ end
125
+
126
+ # Run a single judge.
127
+ # @return [Churn] How many modifications have been made
128
+ def one_judge(fb, judge, global, options)
129
+ local = {}
130
+ before = fb.size
131
+ judge.run(fb, global, local, options)
132
+ after = fb.size
133
+ diff = after - before
134
+ if diff.positive?
135
+ Churn.new(diff, 0)
136
+ else
137
+ Churn.new(0, -diff)
138
+ end
108
139
  end
109
140
  end
data/lib/judges.rb CHANGED
@@ -25,5 +25,5 @@
25
25
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Judges
28
- VERSION = '0.3.0'
28
+ VERSION = '0.5.0'
29
29
  end
@@ -47,7 +47,8 @@ class TestPull < Minitest::Test
47
47
  'token' => '000',
48
48
  'host' => 'example.org',
49
49
  'port' => 80,
50
- 'ssl' => false
50
+ 'ssl' => false,
51
+ 'wait' => 10
51
52
  },
52
53
  ['foo', file]
53
54
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-04 00:00:00.000000000 Z
11
+ date: 2024-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: retries
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: typhoeus
113
127
  requirement: !ruby/object:Gem::Requirement