qbash 0.0.4 → 0.0.6

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: 513c4fae2df78a6b4ae254b80dcd5e306c34a68cb8c1e869c3073ee612504d41
4
- data.tar.gz: 424695c22db403cfa8ad40def087742cb804a08e4d5c858f378c02ebd3a12303
3
+ metadata.gz: ddc357961a48953ee7c479583b6d648d9ad34873510e7ef6d8096a7bd8e596b5
4
+ data.tar.gz: 16dfe814c412365131380e239a93e90532419ece6e66fb3ce0c74bf6566cae5b
5
5
  SHA512:
6
- metadata.gz: 9fd4f01dd7ba2cbc6da044367d45d14a07e699c632e9ce421674b151095972465e7e3cd86e13bc3efcc80b29a33c9d62cf976c94b56db82578026a0734ba64e3
7
- data.tar.gz: e71a4444310641326ce9eb07d312eeaa5157f1c78faf8dcc0c1effc068df8ce50a3bcc3b184849ade9079bfb936a076bf774834ba1590191fe81ea62c835f8b9
6
+ metadata.gz: 15ae921b000efb256d6907b1b69cda9e60a63612d25eccab76b09f0c765d6aa9d1337ed43580b3bf18cfd84a73e69b4f16aaad62065c8df9644a87779c0d8485
7
+ data.tar.gz: 6de449a43159e54803266ca16cb960bd09772abbb9a33ad3b5fa77fa25be63cef6e38fa0edb003c342e2c495bfd37b98035365aa76a9a2b9271d99385498ac96
data/Gemfile CHANGED
@@ -32,9 +32,9 @@ gem 'random-port', '~>0.0', require: false
32
32
  gem 'rspec-rails', '7.0.1', require: false
33
33
  gem 'rubocop', '1.66.1', require: false
34
34
  gem 'rubocop-performance', '1.22.1', require: false
35
- gem 'rubocop-rspec', '3.0.5', require: false
35
+ gem 'rubocop-rspec', '3.1.0', require: false
36
36
  gem 'simplecov', '0.22.0', require: false
37
37
  gem 'simplecov-cobertura', '2.1.0', require: false
38
38
  gem 'w3c_validators', '1.3.7', require: false
39
- gem 'webmock', '3.23.1', require: false
39
+ gem 'webmock', '3.24.0', require: false
40
40
  gem 'yard', '0.9.37', require: false
data/Gemfile.lock CHANGED
@@ -5,6 +5,7 @@ PATH
5
5
  backtrace (> 0)
6
6
  elapsed (> 0)
7
7
  loog (> 0)
8
+ tago (> 0)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
@@ -94,7 +95,7 @@ GEM
94
95
  i18n (1.14.6)
95
96
  concurrent-ruby (~> 1.0)
96
97
  io-console (0.7.2)
97
- irb (1.14.0)
98
+ irb (1.14.1)
98
99
  rdoc (>= 4.0.0)
99
100
  reline (>= 0.4.2)
100
101
  json (2.7.2)
@@ -166,7 +167,7 @@ GEM
166
167
  regexp_parser (2.9.2)
167
168
  reline (0.5.10)
168
169
  io-console (~> 0.5)
169
- rexml (3.3.7)
170
+ rexml (3.3.8)
170
171
  rspec-core (3.13.1)
171
172
  rspec-support (~> 3.13.0)
172
173
  rspec-expectations (3.13.3)
@@ -199,7 +200,7 @@ GEM
199
200
  rubocop-performance (1.22.1)
200
201
  rubocop (>= 1.48.1, < 2.0)
201
202
  rubocop-ast (>= 1.31.1, < 2.0)
202
- rubocop-rspec (3.0.5)
203
+ rubocop-rspec (3.1.0)
203
204
  rubocop (~> 1.61)
204
205
  ruby-progressbar (1.13.0)
205
206
  securerandom (0.3.1)
@@ -225,11 +226,11 @@ GEM
225
226
  json (>= 1.8)
226
227
  nokogiri (~> 1.6)
227
228
  rexml (~> 3.2)
228
- webmock (3.23.1)
229
+ webmock (3.24.0)
229
230
  addressable (>= 2.8.0)
230
231
  crack (>= 0.3.2)
231
232
  hashdiff (>= 0.4.0, < 2.0.0)
232
- webrick (1.8.1)
233
+ webrick (1.8.2)
233
234
  yard (0.9.37)
234
235
  zeitwerk (2.6.18)
235
236
 
@@ -253,11 +254,11 @@ DEPENDENCIES
253
254
  rspec-rails (= 7.0.1)
254
255
  rubocop (= 1.66.1)
255
256
  rubocop-performance (= 1.22.1)
256
- rubocop-rspec (= 3.0.5)
257
+ rubocop-rspec (= 3.1.0)
257
258
  simplecov (= 0.22.0)
258
259
  simplecov-cobertura (= 2.1.0)
259
260
  w3c_validators (= 1.3.7)
260
- webmock (= 3.23.1)
261
+ webmock (= 3.24.0)
261
262
  yard (= 0.9.37)
262
263
 
263
264
  BUNDLED WITH
data/README.md CHANGED
@@ -32,6 +32,9 @@ stdout = qbash('echo "Hello, world!"', log: $stdout)
32
32
 
33
33
  If the command fails, an exception will be raised.
34
34
 
35
+ The function automatically merges `stderr` with `stdout`
36
+ (you can't change this).
37
+
35
38
  It's possible to provide the standard input and environment variables:
36
39
 
37
40
  ```ruby
@@ -82,6 +85,14 @@ qbash("cat #{Shellwords.escape(file)}")
82
85
  Without such an escaping, in this example, a space inside the `file`
83
86
  will lead to an unpredicatable result of the execution.
84
87
 
88
+ You can also set the maximum time for the command:
89
+
90
+ ```ruby
91
+ qbash("sleep 100", timeout: 4)
92
+ ```
93
+
94
+ This command will raise exception after four seconds.
95
+
85
96
  ## How to contribute
86
97
 
87
98
  Read
data/lib/qbash.rb CHANGED
@@ -24,6 +24,7 @@ require 'backtrace'
24
24
  require 'loog'
25
25
  require 'open3'
26
26
  require 'shellwords'
27
+ require 'tago'
27
28
 
28
29
  # Execute one bash command.
29
30
  #
@@ -33,18 +34,27 @@ require 'shellwords'
33
34
  module Kernel
34
35
  # Execute a single bash command.
35
36
  #
37
+ # For example:
38
+ #
39
+ # year = qbash('date +%Y')
40
+ #
36
41
  # If exit code is not zero, an exception will be raised.
37
42
  #
38
43
  # To escape arguments, use +Shellwords.escape()+ method.
39
44
  #
45
+ # Stderr automatically merges with stdout.
46
+ #
47
+ # Read this <a href="https://github.com/yegor256/qbash">README</a> file for more details.
48
+ #
40
49
  # @param [String] cmd The command to run, for example +echo "Hello, world!"+
41
50
  # @param [String] stdin The +stdin+ to provide to the command
42
51
  # @param [Hash] env Hash of environment variables
43
52
  # @param [Loog|IO] log Logging facility with +.debug()+ method (or +$stdout+)
44
- # @param [Array] accept List of accepted exit codes (accepts all if the list is empty)
53
+ # @param [Array] accept List of accepted exit codes (accepts all if the list is +nil+)
45
54
  # @param [Boolean] both If set to TRUE, the function returns an array +(stdout, code)+
55
+ # @param [Integer] timeout If it's set to non-NIL, the execution will fail after this number of seconds
46
56
  # @return [String] Everything that was printed to the +stdout+ by the command
47
- def qbash(cmd, stdin: '', env: {}, log: Loog::NULL, accept: [0], both: false)
57
+ def qbash(cmd, stdin: '', env: {}, log: Loog::NULL, accept: [0], both: false, timeout: nil)
48
58
  cmd = cmd.join(' ') if cmd.is_a?(Array)
49
59
  if log.respond_to?(:debug)
50
60
  log.debug("+ #{cmd}")
@@ -53,25 +63,32 @@ module Kernel
53
63
  end
54
64
  buf = ''
55
65
  e = 1
56
- Open3.popen2e(env, "/bin/bash -c #{Shellwords.escape(cmd)}") do |sin, sout, thr|
57
- sin.write(stdin)
58
- sin.close
59
- until sout.eof?
60
- begin
61
- ln = sout.gets
62
- rescue IOError => e
63
- ln = Backtrace.new(e).to_s
64
- end
65
- if log.respond_to?(:debug)
66
- log.debug(ln)
67
- else
68
- log.print("#{ln}\n")
66
+ start = Time.now
67
+ thread =
68
+ Thread.new do
69
+ Open3.popen2e(env, "/bin/bash -c #{Shellwords.escape(cmd)}") do |sin, sout, thr|
70
+ sin.write(stdin)
71
+ sin.close
72
+ until sout.eof?
73
+ begin
74
+ ln = sout.gets
75
+ rescue IOError => e
76
+ ln = Backtrace.new(e).to_s
77
+ end
78
+ if log.respond_to?(:debug)
79
+ log.debug(ln)
80
+ else
81
+ log.print("#{ln}\n")
82
+ end
83
+ buf += ln
84
+ end
85
+ e = thr.value.to_i
86
+ if !accept.nil? && !accept.include?(e)
87
+ raise "The command '#{cmd}' failed with exit code ##{e} in #{start.ago}\n#{buf}"
88
+ end
69
89
  end
70
- buf += ln
71
90
  end
72
- e = thr.value.to_i
73
- raise "The command '#{cmd}' failed with exit code ##{e}\n#{buf}" if !accept.empty? && !accept.include?(e)
74
- end
91
+ raise "Execution of #{cmd} timed out in #{start.ago}" if thread.join(timeout).nil?
75
92
  return [buf, e] if both
76
93
  buf
77
94
  end
data/qbash.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 = 'qbash'
29
- s.version = '0.0.4'
29
+ s.version = '0.0.6'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Quick Executor of a BASH Command'
32
32
  s.description =
@@ -42,5 +42,6 @@ Gem::Specification.new do |s|
42
42
  s.add_dependency 'backtrace', '>0'
43
43
  s.add_dependency 'elapsed', '>0'
44
44
  s.add_dependency 'loog', '>0'
45
+ s.add_dependency 'tago', '>0'
45
46
  s.metadata['rubygems_mfa_required'] = 'true'
46
47
  end
data/test/test_qbash.rb CHANGED
@@ -57,6 +57,12 @@ class TestQbash < Minitest::Test
57
57
  end
58
58
  end
59
59
 
60
+ def test_with_timeout
61
+ assert_raises do
62
+ qbash('sleep 100', timeout: 0.1)
63
+ end
64
+ end
65
+
60
66
  def test_with_special_symbols
61
67
  assert_equal("'hi'\n", qbash("echo \"'hi'\""))
62
68
  end
@@ -69,13 +75,13 @@ class TestQbash < Minitest::Test
69
75
 
70
76
  def test_ignore_errors
71
77
  Dir.mktmpdir do |home|
72
- qbash("cat #{Shellwords.escape(File.join(home, 'b.txt'))}", accept: [])
78
+ qbash("cat #{Shellwords.escape(File.join(home, 'b.txt'))}", accept: nil)
73
79
  end
74
80
  end
75
81
 
76
82
  def test_with_both
77
83
  Dir.mktmpdir do |home|
78
- stdout, code = qbash("cat #{Shellwords.escape(File.join(home, 'foo.txt'))}", accept: [], both: true)
84
+ stdout, code = qbash("cat #{Shellwords.escape(File.join(home, 'foo.txt'))}", accept: nil, both: true)
79
85
  assert(code.positive?)
80
86
  assert(!stdout.empty?)
81
87
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qbash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
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-09-25 00:00:00.000000000 Z
11
+ date: 2024-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: tago
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: With the help of Open3 executes bash command and conveniently returns
56
70
  its output and exit code
57
71
  email: yegor256@gmail.com