judges 0.21.0 → 0.22.1

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: f826572e575f1c40c556cb5c0de0a2ca5aaf39554ef9d4219e517c6d8492236b
4
- data.tar.gz: 7f16f70af23a1fb4903934939133015289f06d4a276c32a567356dd60e3fa75f
3
+ metadata.gz: cbef0d45d39354c46895af943ef6180bed47a28b4738bcca9755f9b66a282756
4
+ data.tar.gz: 8dec5ca451e4499509f7158f9c1b115f301713d3e065becd53be78fc82e75c87
5
5
  SHA512:
6
- metadata.gz: f3b4e89fcd538caddf490ca8769c2142e6c06bec83eb99582bf426f48ce35617ce169d08d604a9d4ee2780d88f0cc877651fabd863efffc5cb2d1ee96cf6a6ec
7
- data.tar.gz: 4dd669683164fcd9402f9f4043b5fab0faa086cc68de9f0a6dc1f6e78f9959f5a8a2f18eb3c8fed23986d735010e71c964313090acba222966803b02bd8ba9e3
6
+ metadata.gz: 074313a259b93c9979a941231251335481cca8212ecea88df3a25d8c70eefed71b55064e11f48e9f63b2c3d8f15982d9647193515a4ec57a1b6120afdf302485
7
+ data.tar.gz: 3b5628e0ae419cb8197ab4845165ddcde7de4e02bd6174ca6057dd76b3982475bc036d74a778dbca7f6c0b97f605a836e824d1fd1377d0e92a47212cde879db0
data/.rubocop.yml CHANGED
@@ -58,3 +58,7 @@ Naming/MethodParameterName:
58
58
  MinNameLength: 2
59
59
  Layout/EndOfLine:
60
60
  EnforcedStyle: lf
61
+ Layout/MultilineAssignmentLayout:
62
+ Enabled: true
63
+ Layout/FirstHashElementIndentation:
64
+ EnforcedStyle: consistent
data/Gemfile CHANGED
@@ -30,7 +30,7 @@ gem 'net-ping', '2.0.8', require: false
30
30
  gem 'rake', '13.2.1', require: false
31
31
  gem 'random-port', '~>0.0', require: false
32
32
  gem 'rspec-rails', '6.1.3', require: false
33
- gem 'rubocop', '1.65.0', require: false
33
+ gem 'rubocop', '1.65.1', require: false
34
34
  gem 'rubocop-performance', '1.21.1', require: false
35
35
  gem 'rubocop-rspec', '3.0.3', require: false
36
36
  gem 'simplecov', '0.22.0', require: false
data/Gemfile.lock CHANGED
@@ -71,7 +71,7 @@ GEM
71
71
  multi_test (~> 1.1)
72
72
  sys-uname (~> 1.2)
73
73
  cucumber-ci-environment (10.0.1)
74
- cucumber-core (13.0.2)
74
+ cucumber-core (13.0.3)
75
75
  cucumber-gherkin (>= 27, < 28)
76
76
  cucumber-messages (>= 20, < 23)
77
77
  cucumber-tag-expressions (> 5, < 7)
@@ -79,18 +79,18 @@ GEM
79
79
  bigdecimal
80
80
  cucumber-gherkin (27.0.0)
81
81
  cucumber-messages (>= 19.1.4, < 23)
82
- cucumber-html-formatter (21.4.1)
82
+ cucumber-html-formatter (21.5.0)
83
83
  cucumber-messages (> 19, < 25)
84
84
  cucumber-messages (22.0.0)
85
85
  cucumber-tag-expressions (6.1.0)
86
86
  decoor (0.0.1)
87
87
  diff-lcs (1.5.1)
88
- docile (1.4.0)
88
+ docile (1.4.1)
89
89
  drb (2.2.1)
90
90
  erubi (1.13.0)
91
91
  ethon (0.16.0)
92
92
  ffi (>= 1.15.0)
93
- factbase (0.2.0)
93
+ factbase (0.2.1)
94
94
  backtrace (> 0)
95
95
  decoor (> 0)
96
96
  json (~> 2.7)
@@ -107,7 +107,7 @@ GEM
107
107
  ffi (1.17.0-x86_64-darwin)
108
108
  ffi (1.17.0-x86_64-linux-gnu)
109
109
  gli (2.21.5)
110
- hashdiff (1.1.0)
110
+ hashdiff (1.1.1)
111
111
  i18n (1.14.5)
112
112
  concurrent-ruby (~> 1.0)
113
113
  io-console (0.7.2)
@@ -120,7 +120,7 @@ GEM
120
120
  loofah (2.22.0)
121
121
  crass (~> 1.0.2)
122
122
  nokogiri (>= 1.12.0)
123
- loog (0.5.2)
123
+ loog (0.6.0)
124
124
  mini_mime (1.1.5)
125
125
  minitest (5.24.1)
126
126
  minitest-reporters (1.7.1)
@@ -132,19 +132,19 @@ GEM
132
132
  multi_test (1.1.0)
133
133
  mutex_m (0.2.0)
134
134
  net-ping (2.0.8)
135
- nokogiri (1.16.6-aarch64-linux)
135
+ nokogiri (1.16.7-aarch64-linux)
136
136
  racc (~> 1.4)
137
- nokogiri (1.16.6-arm-linux)
137
+ nokogiri (1.16.7-arm-linux)
138
138
  racc (~> 1.4)
139
- nokogiri (1.16.6-arm64-darwin)
139
+ nokogiri (1.16.7-arm64-darwin)
140
140
  racc (~> 1.4)
141
- nokogiri (1.16.6-x64-mingw-ucrt)
141
+ nokogiri (1.16.7-x64-mingw-ucrt)
142
142
  racc (~> 1.4)
143
- nokogiri (1.16.6-x86-linux)
143
+ nokogiri (1.16.7-x86-linux)
144
144
  racc (~> 1.4)
145
- nokogiri (1.16.6-x86_64-darwin)
145
+ nokogiri (1.16.7-x86_64-darwin)
146
146
  racc (~> 1.4)
147
- nokogiri (1.16.6-x86_64-linux)
147
+ nokogiri (1.16.7-x86_64-linux)
148
148
  racc (~> 1.4)
149
149
  others (0.0.3)
150
150
  parallel (1.25.1)
@@ -153,8 +153,8 @@ GEM
153
153
  racc
154
154
  psych (5.1.2)
155
155
  stringio
156
- public_suffix (6.0.0)
157
- racc (1.8.0)
156
+ public_suffix (6.0.1)
157
+ racc (1.8.1)
158
158
  rack (3.1.7)
159
159
  rack-session (2.0.0)
160
160
  rack (>= 3.0.0)
@@ -187,7 +187,7 @@ GEM
187
187
  reline (0.5.9)
188
188
  io-console (~> 0.5)
189
189
  retries (0.0.5)
190
- rexml (3.3.2)
190
+ rexml (3.3.4)
191
191
  strscan
192
192
  rspec-core (3.13.0)
193
193
  rspec-support (~> 3.13.0)
@@ -206,7 +206,7 @@ GEM
206
206
  rspec-mocks (~> 3.13)
207
207
  rspec-support (~> 3.13)
208
208
  rspec-support (3.13.1)
209
- rubocop (1.65.0)
209
+ rubocop (1.65.1)
210
210
  json (~> 2.3)
211
211
  language_server-protocol (>= 3.17.0)
212
212
  parallel (~> 1.10)
@@ -252,7 +252,7 @@ GEM
252
252
  webrick (1.8.1)
253
253
  yaml (0.3.0)
254
254
  yard (0.9.36)
255
- zeitwerk (2.6.16)
255
+ zeitwerk (2.6.17)
256
256
 
257
257
  PLATFORMS
258
258
  aarch64-linux
@@ -272,7 +272,7 @@ DEPENDENCIES
272
272
  rake (= 13.2.1)
273
273
  random-port (~> 0.0)
274
274
  rspec-rails (= 6.1.3)
275
- rubocop (= 1.65.0)
275
+ rubocop (= 1.65.1)
276
276
  rubocop-performance (= 1.21.1)
277
277
  rubocop-rspec (= 3.0.3)
278
278
  simplecov (= 0.22.0)
@@ -281,4 +281,4 @@ DEPENDENCIES
281
281
  yard (= 0.9.36)
282
282
 
283
283
  BUNDLED WITH
284
- 2.5.6
284
+ 2.5.16
data/assets/index.xsl CHANGED
@@ -66,6 +66,12 @@ SOFTWARE.
66
66
  article { border: none; }
67
67
  header img { width: 3em; height: 3em; }
68
68
  .sorter { cursor: pointer; }
69
+ .S { color: #196F3D; }
70
+ .T { color: #2471A3; }
71
+ .I { color: #212F3C; }
72
+ .F { color: #E74C3C; }
73
+ .BR { color: gray; }
74
+ .hidden { color: gray; }
69
75
  </style>
70
76
  <script type="text/javascript">
71
77
  $(function() {
@@ -97,6 +103,12 @@ SOFTWARE.
97
103
  <xsl:value-of select="$date"/>
98
104
  <xsl:text>.</xsl:text>
99
105
  <br/>
106
+ <xsl:text>Properties with columns: </xsl:text>
107
+ <xsl:value-of select="$columns"/>
108
+ <br/>
109
+ <xsl:text>Hidden properties: </xsl:text>
110
+ <xsl:value-of select="$hidden"/>
111
+ <br/>
100
112
  <a href="https://github.com/yegor256/factbase">
101
113
  <xsl:text>Factbase</xsl:text>
102
114
  </a>
@@ -177,14 +189,14 @@ SOFTWARE.
177
189
  <td>
178
190
  <xsl:for-each select="$f/*">
179
191
  <xsl:text> </xsl:text>
180
- <xsl:variable name="visible" select="string-length(substring-before(concat(',', $hidden, ','), concat(',', name(), ','))) = 0"/>
192
+ <xsl:variable name="visible" select="string-length(substring-before(concat(' ,', $hidden, ','), concat(',', name(), ','))) = 0"/>
181
193
  <xsl:if test="string-length(substring-before(concat(',', $columns, ','), concat(',', name(), ','))) = 0">
182
194
  <xsl:choose>
183
195
  <xsl:when test="$visible">
184
196
  <xsl:value-of select="name()"/>
185
197
  </xsl:when>
186
198
  <xsl:otherwise>
187
- <span style="color:gray;">
199
+ <span class="hidden" title="{.}">
188
200
  <xsl:value-of select="name()"/>
189
201
  </span>
190
202
  </xsl:otherwise>
@@ -218,25 +230,30 @@ SOFTWARE.
218
230
  </xsl:when>
219
231
  <xsl:otherwise>
220
232
  <span>
221
- <xsl:attribute name="style">
222
- <xsl:text>color:</xsl:text>
223
- <xsl:choose>
224
- <xsl:when test="$v/@t = 'S'">
225
- <xsl:text>#196F3D</xsl:text>
226
- </xsl:when>
227
- <xsl:when test="$v/@t = 'T'">
228
- <xsl:text>#2471A3</xsl:text>
229
- </xsl:when>
230
- <xsl:when test="$v/@t = 'I'">
231
- <xsl:text>#212F3C</xsl:text>
232
- </xsl:when>
233
- <xsl:when test="$v/@t = 'F'">
234
- <xsl:text>#E74C3C</xsl:text>
235
- </xsl:when>
236
- </xsl:choose>
233
+ <xsl:attribute name="class">
234
+ <xsl:value-of select="$v/@t"/>
237
235
  </xsl:attribute>
238
- <xsl:value-of select="$v"/>
236
+ <xsl:call-template name="just-value">
237
+ <xsl:with-param name="v" select="$v"/>
238
+ </xsl:call-template>
239
+ </span>
240
+ </xsl:otherwise>
241
+ </xsl:choose>
242
+ </xsl:template>
243
+ <xsl:template name="just-value">
244
+ <xsl:param name="v"/>
245
+ <xsl:choose>
246
+ <xsl:when test="string-length($v) &gt; 64">
247
+ <xsl:value-of select="substring($v, 0, 64)"/>
248
+ <span class="BR">
249
+ <xsl:text>-</xsl:text>
239
250
  </span>
251
+ <xsl:call-template name="just-value">
252
+ <xsl:with-param name="v" select="substring($v, 64)"/>
253
+ </xsl:call-template>
254
+ </xsl:when>
255
+ <xsl:otherwise>
256
+ <xsl:value-of select="$v"/>
240
257
  </xsl:otherwise>
241
258
  </xsl:choose>
242
259
  </xsl:template>
data/bin/judges CHANGED
@@ -32,7 +32,15 @@ Encoding.default_internal = Encoding::UTF_8
32
32
 
33
33
  class JudgesGLI extend GLI::App
34
34
 
35
- loog = Loog::REGULAR
35
+ def self.run_it(cmd, ruby)
36
+ cmd.action do |global, options, args|
37
+ require_relative "../lib/judges/commands/#{ruby}"
38
+ @@loog.debug("Running '#{ruby}' command...")
39
+ Object.const_get("Judges::#{ruby.capitalize}").new(@@loog).run(options, args)
40
+ end
41
+ end
42
+
43
+ @@loog = Loog::REGULAR
36
44
 
37
45
  program_desc('Automated executor of judges for a factbase')
38
46
 
@@ -48,13 +56,13 @@ class JudgesGLI extend GLI::App
48
56
 
49
57
  pre do |global, command, options, args|
50
58
  if global[:verbose]
51
- loog = Loog::VERBOSE
59
+ @@loog = Loog::VERBOSE
52
60
  end
53
- loog.debug("Judges #{Judges::VERSION}")
54
- loog.debug("Factbase #{Factbase::VERSION}")
55
- loog.debug("Ruby: #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}")
56
- loog.debug("Current directory: #{Dir.getwd}")
57
- loog.debug("Time: #{Time.now.utc.iso8601}")
61
+ @@loog.debug("Judges #{Judges::VERSION}")
62
+ @@loog.debug("Factbase #{Factbase::VERSION}")
63
+ @@loog.debug("Ruby: #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}")
64
+ @@loog.debug("Current directory: #{Dir.getwd}")
65
+ @@loog.debug("Time: #{Time.now.utc.iso8601}")
58
66
  true
59
67
  end
60
68
 
@@ -72,44 +80,29 @@ class JudgesGLI extend GLI::App
72
80
  c.switch([:summary], default_value: false)
73
81
  c.desc 'Use default logging facility'
74
82
  c.switch([:log], default_value: true)
75
- c.action do |global, options, args|
76
- require_relative '../lib/judges/commands/update'
77
- Judges::Update.new(loog).run(options, args)
78
- end
83
+ run_it(c, 'update')
79
84
  end
80
85
 
81
86
  desc 'Evaluate a single Ruby expression on the factbase'
82
87
  command :eval do |c|
83
- c.action do |global, options, args|
84
- require_relative '../lib/judges/commands/eval'
85
- Judges::Eval.new(loog).run(options, args)
86
- end
88
+ run_it(c, 'eval')
87
89
  end
88
90
 
89
91
  desc 'Join two factbases'
90
92
  command :join do |c|
91
- c.action do |global, options, args|
92
- require_relative '../lib/judges/commands/join'
93
- Judges::Join.new(loog).run(options, args)
94
- end
93
+ run_it(c, 'join')
95
94
  end
96
95
 
97
96
  desc 'Import YAML into a factbase'
98
97
  command :import do |c|
99
- c.action do |global, options, args|
100
- require_relative '../lib/judges/commands/import'
101
- Judges::Import.new(loog).run(options, args)
102
- end
98
+ run_it(c, 'import')
103
99
  end
104
100
 
105
101
  desc 'Remove the facts that are too old'
106
102
  command :trim do |c|
107
103
  c.desc 'Only the facts that match the expression are deleted'
108
104
  c.flag([:query], default_value: '(never)')
109
- c.action do |global, options, args|
110
- require_relative '../lib/judges/commands/trim'
111
- Judges::Trim.new(loog).run(options, args)
112
- end
105
+ run_it(c, 'trim')
113
106
  end
114
107
 
115
108
  desc 'Print the factbase into a human-readable format (YAML, JSON, etc.)'
@@ -128,18 +121,12 @@ class JudgesGLI extend GLI::App
128
121
  c.flag([:hidden], default_value: '_id,_time,_version')
129
122
  c.desc 'Print even if target file already exists and is older than the factbase'
130
123
  c.switch([:force], default_value: false)
131
- c.action do |global, options, args|
132
- require_relative '../lib/judges/commands/print'
133
- Judges::Print.new(loog).run(options, args)
134
- end
124
+ run_it(c, 'print')
135
125
  end
136
126
 
137
127
  desc 'Inspect the factbase and print all its possible meta-data'
138
128
  command :inspect do |c|
139
- c.action do |global, options, args|
140
- require_relative '../lib/judges/commands/inspect'
141
- Judges::Inspect.new(loog).run(options, args)
142
- end
129
+ run_it(c, 'inspect')
143
130
  end
144
131
 
145
132
  desc 'Run automated tests for all judges'
@@ -160,10 +147,7 @@ class JudgesGLI extend GLI::App
160
147
  c.switch([:quiet], default_value: false)
161
148
  c.desc 'Use default logging facility'
162
149
  c.switch([:log], default_value: true)
163
- c.action do |global, options, args|
164
- require_relative '../lib/judges/commands/test'
165
- Judges::Test.new(loog).run(options, args)
166
- end
150
+ run_it(c, 'test')
167
151
  end
168
152
 
169
153
  desc 'Push the factbase to the server'
@@ -184,10 +168,9 @@ class JudgesGLI extend GLI::App
184
168
  c.flag([:meta], type: String, multiple: true)
185
169
  c.desc 'How many times to retry'
186
170
  c.flag([:retries], type: Integer, default_value: 3)
187
- c.action do |global, options, args|
188
- require_relative '../lib/judges/commands/push'
189
- Judges::Push.new(loog).run(options, args)
190
- end
171
+ c.desc 'Turn on the package compression'
172
+ c.switch([:zip], default_value: true)
173
+ run_it(c, 'push')
191
174
  end
192
175
 
193
176
  desc 'Pull the factbase from the server'
@@ -208,10 +191,7 @@ class JudgesGLI extend GLI::App
208
191
  c.flag([:owner], default_value: 'default', type: String)
209
192
  c.desc 'How many times to retry'
210
193
  c.flag([:retries], type: Integer, default_value: 3)
211
- c.action do |global, options, args|
212
- require_relative '../lib/judges/commands/pull'
213
- Judges::Pull.new(loog).run(options, args)
214
- end
194
+ run_it(c, 'pull')
215
195
  end
216
196
  end
217
197
 
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.21.0'
29
+ s.version = '0.22.1'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Command-Line Tool for a Factbase'
32
32
  s.description =
data/lib/judges/baza.rb CHANGED
@@ -38,7 +38,7 @@ require_relative '../judges/elapsed'
38
38
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
39
39
  # License:: MIT
40
40
  class Judges::Baza
41
- def initialize(host, port, token, ssl: true, timeout: 30, retries: 3, loog: Loog::NULL)
41
+ def initialize(host, port, token, ssl: true, timeout: 30, retries: 3, loog: Loog::NULL, compression: true)
42
42
  @host = host
43
43
  @port = port
44
44
  @ssl = ssl
@@ -46,6 +46,7 @@ class Judges::Baza
46
46
  @timeout = timeout
47
47
  @loog = loog
48
48
  @retries = retries
49
+ @compression = compression
49
50
  end
50
51
 
51
52
  # Push factbase to the server.
@@ -62,18 +63,22 @@ class Judges::Baza
62
63
  unless meta.empty?
63
64
  hdrs = hdrs.merge('X-Zerocracy-Meta' => meta.map { |v| Base64.encode64(v).gsub("\n", '') }.join(' '))
64
65
  end
66
+ params = {
67
+ connecttimeout: @timeout,
68
+ timeout: @timeout,
69
+ body: data,
70
+ headers: hdrs
71
+ }
65
72
  elapsed(@loog) do
66
- ret = with_retries(max_tries: @retries) do
67
- checked(
68
- Typhoeus::Request.put(
69
- home.append('push').append(name).to_s,
70
- body: data,
71
- headers: hdrs,
72
- connecttimeout: @timeout,
73
- timeout: @timeout
73
+ ret =
74
+ with_retries(max_tries: @retries) do
75
+ checked(
76
+ Typhoeus::Request.put(
77
+ home.append('push').append(name).to_s,
78
+ @compression ? zipped(params) : params
79
+ )
74
80
  )
75
- )
76
- end
81
+ end
77
82
  id = ret.body.to_i
78
83
  throw :"Pushed #{data.size} bytes to #{@host}, job ID is ##{id}"
79
84
  end
@@ -117,20 +122,63 @@ class Judges::Baza
117
122
  def finished?(id)
118
123
  finished = false
119
124
  elapsed(@loog) do
120
- ret = with_retries(max_tries: @retries) do
121
- checked(
122
- Typhoeus::Request.get(
123
- home.append('finished').append(id).to_s,
124
- headers:
125
+ ret =
126
+ with_retries(max_tries: @retries) do
127
+ checked(
128
+ Typhoeus::Request.get(
129
+ home.append('finished').append(id).to_s,
130
+ headers:
131
+ )
125
132
  )
126
- )
127
- end
133
+ end
128
134
  finished = ret.body == 'yes'
129
135
  throw :"The job ##{id} is #{finished ? '' : 'not yet '}finished at #{@host}"
130
136
  end
131
137
  finished
132
138
  end
133
139
 
140
+ # Read and return the stdout of the job.
141
+ # @param [Integer] id The ID of the job on the server
142
+ # @return [String] The stdout, as a text
143
+ def stdout(id)
144
+ stdout = ''
145
+ elapsed(@loog) do
146
+ ret =
147
+ with_retries(max_tries: @retries) do
148
+ checked(
149
+ Typhoeus::Request.get(
150
+ home.append('stdout').append("#{id}.txt").to_s,
151
+ headers:
152
+ )
153
+ )
154
+ end
155
+ stdout = ret.body
156
+ throw :"The stdout of the job ##{id} has #{stdout.split("\n")} lines"
157
+ end
158
+ stdout
159
+ end
160
+
161
+ # Read and return the exit code of the job.
162
+ # @param [Integer] id The ID of the job on the server
163
+ # @return [Integer] The exit code
164
+ def exit_code(id)
165
+ code = 0
166
+ elapsed(@loog) do
167
+ ret =
168
+ with_retries(max_tries: @retries) do
169
+ checked(
170
+ Typhoeus::Request.get(
171
+ home.append('exit').append("#{id}.txt").to_s,
172
+ headers:
173
+ )
174
+ )
175
+ end
176
+ code = ret.body.to_i
177
+ throw :"The exit code of the job ##{id} is #{code}"
178
+ end
179
+ code
180
+ end
181
+
134
182
  # Lock the name.
135
183
  # @param [String] name The name of the job on the server
136
184
  # @param [String] owner The owner of the lock (any string)
@@ -171,14 +219,15 @@ class Judges::Baza
171
219
  def recent(name)
172
220
  job = 0
173
221
  elapsed(@loog) do
174
- ret = with_retries(max_tries: @retries) do
175
- checked(
176
- Typhoeus::Request.get(
177
- home.append('recent').append("#{name}.txt").to_s,
178
- headers:
222
+ ret =
223
+ with_retries(max_tries: @retries) do
224
+ checked(
225
+ Typhoeus::Request.get(
226
+ home.append('recent').append("#{name}.txt").to_s,
227
+ headers:
228
+ )
179
229
  )
180
- )
181
- end
230
+ end
182
231
  job = ret.body.to_i
183
232
  throw :"The recent \"#{name}\" job's ID is ##{job} at #{@host}"
184
233
  end
@@ -191,14 +240,15 @@ class Judges::Baza
191
240
  def name_exists?(name)
192
241
  exists = 0
193
242
  elapsed(@loog) do
194
- ret = with_retries(max_tries: @retries) do
195
- checked(
196
- Typhoeus::Request.get(
197
- home.append('exists').append(name).to_s,
198
- headers:
243
+ ret =
244
+ with_retries(max_tries: @retries) do
245
+ checked(
246
+ Typhoeus::Request.get(
247
+ home.append('exists').append(name).to_s,
248
+ headers:
249
+ )
199
250
  )
200
- )
201
- end
251
+ end
202
252
  exists = ret.body == 'yes'
203
253
  throw :"The name \"#{name}\" #{exists ? 'exists' : "doesn't exist"} at #{@host}"
204
254
  end
@@ -215,6 +265,27 @@ class Judges::Baza
215
265
  }
216
266
  end
217
267
 
268
+ def zipped(params)
269
+ body = gzip(params.fetch(:body))
270
+ headers = params
271
+ .fetch(:headers)
272
+ .merge({
273
+ 'Content-Type' => 'application/zip',
274
+ 'Content-Encoding' => 'gzip',
275
+ 'Content-Length' => body.size
276
+ })
277
+ params.merge(body:, headers:)
278
+ end
279
+
280
+ def gzip(data)
281
+ ''.dup.tap do |result|
282
+ io = StringIO.new(result)
283
+ gz = Zlib::GzipWriter.new(io)
284
+ gz.write(data)
285
+ gz.close
286
+ end
287
+ end
288
+
218
289
  def home
219
290
  Iri.new('')
220
291
  .host(@host)
@@ -51,9 +51,14 @@ class Judges::Pull
51
51
  )
52
52
  name = args[0]
53
53
  elapsed(@loog) do
54
+ baza.lock(name, opts['owner'])
54
55
  if baza.name_exists?(name)
55
- baza.lock(name, opts['owner'])
56
- fb.import(baza.pull(wait(name, baza, baza.recent(name), opts['wait'])))
56
+ jid = baza.recent(name)
57
+ unless baza.exit_code(jid).zero?
58
+ @loog.warn("STDOUT of the job ##{jid} (from the server):\n#{baza.stdout(jid)}")
59
+ raise "The job ##{jid} ('#{name}') is broken, maybe you should expire it"
60
+ end
61
+ fb.import(baza.pull(wait(name, baza, jid, opts['wait'])))
57
62
  Judges::Impex.new(@loog, args[1]).export(fb)
58
63
  throw :"Pulled #{fb.size} facts by the name '#{name}'"
59
64
  else
@@ -48,7 +48,8 @@ class Judges::Push
48
48
  ssl: opts['ssl'],
49
49
  timeout: (opts['timeout'] || 30).to_i,
50
50
  loog: @loog,
51
- retries: (opts['retries'] || 3).to_i
51
+ retries: (opts['retries'] || 3).to_i,
52
+ compression: opts.fetch('zip', true)
52
53
  )
53
54
  elapsed(@loog) do
54
55
  baza.lock(name, opts['owner'])
@@ -64,7 +64,7 @@ class Judges::Update
64
64
  loop do
65
65
  c += 1
66
66
  if c > 1
67
- @loog.info("\n\nStarting cycle ##{c}#{opts['max-cycles'] ? " (out of #{opts['max-cycles']})" : ''}...")
67
+ @loog.info("\nStarting cycle ##{c}#{opts['max-cycles'] ? " (out of #{opts['max-cycles']})" : ''}...")
68
68
  end
69
69
  delta = cycle(opts, judges, fb, options)
70
70
  churn += delta
@@ -103,17 +103,18 @@ class Judges::Update
103
103
  churn = Judges::Churn.new(0, 0)
104
104
  global = {}
105
105
  elapsed(@loog) do
106
- done = judges.each_with_index do |p, i|
107
- @loog.info("\n👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
108
- elapsed(@loog) do
109
- c = one_judge(fb, p, global, options)
110
- churn += c
111
- throw :"👍 The judge #{p.name} modified #{c} facts out of #{fb.size}"
106
+ done =
107
+ judges.each_with_index do |p, i|
108
+ @loog.info("\n👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
109
+ elapsed(@loog) do
110
+ c = one_judge(fb, p, global, options)
111
+ churn += c
112
+ throw :"👍 The judge #{p.name} modified #{c} facts out of #{fb.size}"
113
+ end
114
+ rescue StandardError, SyntaxError => e
115
+ @loog.warn(Backtrace.new(e))
116
+ churn << e.message
112
117
  end
113
- rescue StandardError, SyntaxError => e
114
- @loog.warn(Backtrace.new(e))
115
- churn << e.message
116
- end
117
118
  throw :"👍 #{done} judge(s) processed" if churn.errors.empty?
118
119
  throw :"❌ #{done} judge(s) processed with #{churn.errors.size} errors"
119
120
  end
@@ -52,32 +52,33 @@ class Judges::Options
52
52
  v = v.to_s
53
53
  v = "#{v[0..3]}#{'*' * (v.length - 8)}#{v[-4..]}" if v.length > 8
54
54
  "#{k} → \"#{v}\""
55
- end.join("\n")
55
+ end.sort.join("\n")
56
56
  end
57
57
 
58
58
  def to_h
59
- @to_h ||= begin
60
- pp = @pairs || []
61
- pp = pp.split(',') if pp.is_a?(String)
62
- if pp.is_a?(Array)
63
- pp = pp
64
- .compact
65
- .map(&:strip)
66
- .reject(&:empty?)
67
- .map { |s| s.split('=', 2) }
68
- .map { |a| a.size == 1 ? [a[0], nil] : a }
69
- .reject { |a| a[0].empty? }
59
+ @to_h ||=
60
+ begin
61
+ pp = @pairs || []
62
+ pp = pp.split(',') if pp.is_a?(String)
63
+ if pp.is_a?(Array)
64
+ pp = pp
65
+ .compact
66
+ .map(&:strip)
67
+ .reject(&:empty?)
68
+ .map { |s| s.split('=', 2) }
69
+ .map { |a| a.size == 1 ? [a[0], nil] : a }
70
+ .reject { |a| a[0].empty? }
71
+ .to_h
72
+ end
73
+ pp
74
+ .reject { |k, _| k.nil? }
75
+ .reject { |k, _| k.is_a?(String) && k.empty? }
70
76
  .to_h
77
+ .transform_values { |v| v.nil? ? 'true' : v }
78
+ .transform_values { |v| v.is_a?(String) ? v.strip : v }
79
+ .transform_values { |v| v.is_a?(String) && v.match?(/^[0-9]+$/) ? v.to_i : v }
80
+ .transform_keys { |k| k.to_s.strip.upcase.to_sym }
71
81
  end
72
- pp
73
- .reject { |k, _| k.nil? }
74
- .reject { |k, _| k.is_a?(String) && k.empty? }
75
- .to_h
76
- .transform_values { |v| v.nil? ? 'true' : v }
77
- .transform_values { |v| v.is_a?(String) ? v.strip : v }
78
- .transform_values { |v| v.is_a?(String) && v.match?(/^[0-9]+$/) ? v.to_i : v }
79
- .transform_keys { |k| k.to_s.strip.upcase.to_sym }
80
- end
81
82
  end
82
83
 
83
84
  # Get option by name.
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.21.0'
28
+ VERSION = '0.22.1'
29
29
  end
@@ -50,11 +50,13 @@ class TestPrint < Minitest::Test
50
50
  fb = Factbase.new
51
51
  10.times do
52
52
  f = fb.insert
53
+ f._id = 44
53
54
  f.what = SecureRandom.hex(10)
54
55
  f.when = Time.now
55
56
  f.details = 'hey, друг'
56
57
  f.ticket = 42
57
58
  f.ticket = 55
59
+ f.long_property = 'test_' * 100
58
60
  end
59
61
  Dir.mktmpdir do |d|
60
62
  f = File.join(d, 'base.fb')
@@ -38,6 +38,7 @@ class TestPull < Minitest::Test
38
38
  stub_request(:get, 'http://example.org/exists/foo').to_return(body: 'yes')
39
39
  stub_request(:get, 'http://example.org/recent/foo.txt').to_return(body: '42')
40
40
  stub_request(:get, 'http://example.org/finished/42').to_return(body: 'yes')
41
+ stub_request(:get, 'http://example.org/exit/42.txt').to_return(body: '0')
41
42
  fb = Factbase.new
42
43
  fb.insert.foo = 42
43
44
  stub_request(:get, 'http://example.org/pull/42.fb').to_return(body: fb.export)
@@ -58,4 +59,32 @@ class TestPull < Minitest::Test
58
59
  fb.import(File.binread(file))
59
60
  end
60
61
  end
62
+
63
+ def test_fail_pull_when_job_is_broken
64
+ WebMock.disable_net_connect!
65
+ stub_request(:get, 'http://example.org/lock/foo?owner=none').to_return(status: 302)
66
+ stub_request(:get, 'http://example.org/exists/foo').to_return(body: 'yes')
67
+ stub_request(:get, 'http://example.org/recent/foo.txt').to_return(body: '42')
68
+ stub_request(:get, 'http://example.org/finished/42').to_return(body: 'yes')
69
+ stub_request(:get, 'http://example.org/exit/42.txt').to_return(body: '1')
70
+ stub_request(:get, 'http://example.org/stdout/42.txt').to_return(body: 'oops, some trouble here')
71
+ Dir.mktmpdir do |d|
72
+ file = File.join(d, 'base.fb')
73
+ e =
74
+ assert_raises do
75
+ Judges::Pull.new(Loog::NULL).run(
76
+ {
77
+ 'token' => '000',
78
+ 'host' => 'example.org',
79
+ 'port' => 80,
80
+ 'ssl' => false,
81
+ 'wait' => 10,
82
+ 'owner' => 'none'
83
+ },
84
+ ['foo', file]
85
+ )
86
+ end
87
+ assert(e.message.include?('expire it'), e)
88
+ end
89
+ end
61
90
  end
data/test/test_baza.rb CHANGED
@@ -22,8 +22,10 @@
22
22
 
23
23
  require 'minitest/autorun'
24
24
  require 'webmock/minitest'
25
+ require 'webrick'
25
26
  require 'loog'
26
27
  require 'socket'
28
+ require 'stringio'
27
29
  require 'random-port'
28
30
  require_relative '../lib/judges'
29
31
  require_relative '../lib/judges/baza'
@@ -65,6 +67,26 @@ class TestBaza < Minitest::Test
65
67
  )
66
68
  end
67
69
 
70
+ def test_exit_code_check
71
+ WebMock.disable_net_connect!
72
+ stub_request(:get, 'https://example.org/exit/42.txt').to_return(
73
+ status: 200, body: '0'
74
+ )
75
+ assert(
76
+ Judges::Baza.new('example.org', 443, '000').exit_code(42).zero?
77
+ )
78
+ end
79
+
80
+ def test_stdout_read
81
+ WebMock.disable_net_connect!
82
+ stub_request(:get, 'https://example.org/stdout/42.txt').to_return(
83
+ status: 200, body: 'hello!'
84
+ )
85
+ assert(
86
+ !Judges::Baza.new('example.org', 443, '000').stdout(42).empty?
87
+ )
88
+ end
89
+
68
90
  def test_simple_pull
69
91
  WebMock.disable_net_connect!
70
92
  stub_request(:get, 'https://example.org/pull/333.fb').to_return(
@@ -76,53 +98,76 @@ class TestBaza < Minitest::Test
76
98
  end
77
99
 
78
100
  def test_real_http
79
- req = with_http_server(200, 'yes') do |baza|
80
- baza.name_exists?('simple')
81
- end
82
- assert(req.include?("User-Agent: judges #{Judges::VERSION}\r\n"))
101
+ req =
102
+ with_http_server(200, 'yes') do |baza|
103
+ baza.name_exists?('simple')
104
+ end
105
+ assert_equal("judges #{Judges::VERSION}", req['user-agent'])
83
106
  end
84
107
 
85
108
  def test_push_with_meta
86
- req = with_http_server(200, 'yes') do |baza|
87
- baza.push('simple', 'hello, world!', ['boom!', 'хей!'])
88
- end
89
- assert(req.include?("X-Zerocracy-Meta: Ym9vbSE= 0YXQtdC5IQ==\r\n"))
109
+ req =
110
+ with_http_server(200, 'yes') do |baza|
111
+ baza.push('simple', 'hello, world!', ['boom!', 'хей!'])
112
+ end
113
+ assert_equal('Ym9vbSE= 0YXQtdC5IQ==', req['x-zerocracy-meta'])
90
114
  end
91
115
 
92
116
  def test_push_with_big_meta
93
- req = with_http_server(200, 'yes') do |baza|
94
- baza.push(
95
- 'simple',
96
- 'hello, world!',
97
- [
98
- 'pages_url:https://zerocracy.github.io/zerocracy.html',
99
- 'others:https://zerocracy.github.io/zerocracy.html',
100
- 'duration:59595'
101
- ]
102
- )
103
- end
104
- assert(req.join.include?('X-Zerocracy-Meta: '))
117
+ req =
118
+ with_http_server(200, 'yes') do |baza|
119
+ baza.push(
120
+ 'simple',
121
+ 'hello, world!',
122
+ [
123
+ 'pages_url:https://zerocracy.github.io/zerocracy.html',
124
+ 'others:https://zerocracy.github.io/zerocracy.html',
125
+ 'duration:59595'
126
+ ]
127
+ )
128
+ end
129
+ assert(req['x-zerocracy-meta'])
130
+ end
131
+
132
+ def test_push_compressed_content
133
+ skip # this test is not stable, see https://github.com/yegor256/judges/issues/105
134
+ req =
135
+ with_http_server(200, 'yes') do |baza|
136
+ baza.push('simple', 'hello, world!', %w[meta1 meta2 meta3])
137
+ end
138
+ assert_equal('application/zip', req.content_type)
139
+ assert_equal('gzip', req['content-encoding'])
140
+ body = Zlib::GzipReader.zcat(StringIO.new(req.body))
141
+ assert_equal('hello, world!', body)
142
+ end
143
+
144
+ def test_push_compression_disabled
145
+ req =
146
+ with_http_server(200, 'yes', compression: false) do |baza|
147
+ baza.push('simple', 'hello, world!', %w[meta1 meta2 meta3])
148
+ end
149
+ assert_equal('application/octet-stream', req.content_type)
150
+ assert_equal('hello, world!', req.body)
105
151
  end
106
152
 
107
153
  private
108
154
 
109
- def with_http_server(code, response)
155
+ def with_http_server(code, response, opts = {})
156
+ opts = { ssl: false, timeout: 1 }.merge(opts)
110
157
  WebMock.enable_net_connect!
111
- req = []
158
+ req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
112
159
  host = '127.0.0.1'
113
160
  RandomPort::Pool::SINGLETON.acquire do |port|
114
161
  server = TCPServer.new(host, port)
115
- t = Thread.new do
116
- socket = server.accept
117
- loop do
118
- line = socket.gets
119
- break if line == "\r\n"
120
- req << line
162
+ t =
163
+ Thread.new do
164
+ socket = server.accept
165
+ req.parse(socket)
166
+ req.body
167
+ socket.puts "HTTP/1.1 #{code} OK\r\nContent-Length: #{response.length}\r\n\r\n#{response}"
168
+ socket.close
121
169
  end
122
- socket.puts "HTTP/1.1 #{code} OK\r\nContent-Length: #{response.length}\r\n\r\n#{response}"
123
- socket.close
124
- end
125
- yield Judges::Baza.new(host, port, '0000', ssl: false, timeout: 1)
170
+ yield Judges::Baza.new(host, port, '0000', **opts)
126
171
  t.join
127
172
  end
128
173
  req
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.21.0
4
+ version: 0.22.1
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-07-29 00:00:00.000000000 Z
11
+ date: 2024-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace