command_line 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65b543edab02b25241f4283219efee33d7c5d6308726e494e74af84f16bbbd17
4
- data.tar.gz: 5a4e2cf8d5eb9699163adfdf1c94a525fa75b68901684fe50aa8021dc81fa33f
3
+ metadata.gz: aaa71300b625158d9cf0460e8be73d20fdc1e045ff0f7dcab2e7483019f96408
4
+ data.tar.gz: 6d5eb5b7ff2083b75ae156c14038cc01ecbda66572a1cf8c5b9fa017f35b05f1
5
5
  SHA512:
6
- metadata.gz: 002c295694393a0a0227ff5826d67dc77cc4d1a0ddf9cea8c50e7a5462750ba5d3e9f1c6c5d991d415648b89afc7260acd91769b18416239295f9d2fb9ce572b
7
- data.tar.gz: 49533b8f1e135b0f0b1da7dee0f4b2df83cf8ed86477bfab60f6b7918e4f83b9a94a266c48593f27bddd6a5f9a89d24ffb7db45e3efe98a7fa616dc08d0015e2
6
+ metadata.gz: b4335254d86f1369417000bdecc9fd486040918368d3757976e884da50f4a213dc197b5f20de55ed0176497dcd21b3f6998774443928b9967c356019546db639
7
+ data.tar.gz: 8116f37462c0cda552988f526bbd75f768db92a9520646959a0cb50328930328ec4b4282ae2da44ec45ef22a66436ab6ac412d80a3f9069c45693560af84eb22
@@ -13,5 +13,9 @@ Layout/IndentFirstHashElement:
13
13
  Metrics/BlockLength:
14
14
  Exclude:
15
15
  - spec/**/*
16
+ Metrics/AbcSize:
17
+ Enabled: false
16
18
  Metrics/MethodLength:
17
- Max: 15
19
+ Enabled: false
20
+ Style/RescueModifier:
21
+ Enabled: false
@@ -1,3 +1,11 @@
1
+ # [1.1.0] (TBD)
2
+
3
+ ## Added
4
+
5
+ - CommandLine.command_line!
6
+ - Added a `:timeout` argument for setting a timeout.
7
+ - Allow more than strings as arguments to pass to the command. We'll convert everything with `to_s`.
8
+
1
9
  # [1.0.1] (2019-08-16)
2
10
 
3
11
  ## Fixed
@@ -8,4 +16,5 @@
8
16
 
9
17
  Initial release.
10
18
 
19
+ [1.1.0]: https://github.com/DragonRuby/command_line/compare/v1.0.1...v1.1.0
11
20
  [1.0.1]: https://github.com/DragonRuby/command_line/compare/v1.0.0...v1.0.1
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CommandLine
2
2
 
3
+ [![Version](https://img.shields.io/gem/v/command_line.svg?style=flat-square)](https://rubygems.org/gems/command_line)
4
+ [![Linux and OS X Build](https://img.shields.io/travis/com/DragonRuby/command_line?label=Linux%20and%20OS%20X&style=flat-square)](https://travis-ci.com/DragonRuby/command_line)
5
+ [![Windows Build](https://img.shields.io/appveyor/ci/AaronLasseigne/command-line?label=Windows&style=flat-square)](https://ci.appveyor.com/project/AaronLasseigne/command-line)
6
+
3
7
  CommandLine provides an easier way to run command-line applications.
4
8
  It captures all outputs, can handle applications that require stdin, and can pass environment variables.
5
9
  It's also helpful for testing commmand-line applications.
@@ -13,13 +17,13 @@ This project uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
13
17
  Add this line to your application's Gemfile:
14
18
 
15
19
  ```ruby
16
- gem 'command_line', '~> 1.0'
20
+ gem 'command_line', '~> 1.1'
17
21
  ```
18
22
 
19
23
  If you want `command_line` available globally you can add this line to your application's Gemfile:
20
24
 
21
25
  ```ruby
22
- gem 'command_line', '~> 1.0', require: 'command_line/global'
26
+ gem 'command_line', '~> 1.1', require: 'command_line/global'
23
27
  ```
24
28
 
25
29
  Or manually install it yourself with:
@@ -70,7 +74,23 @@ end
70
74
  Environment variables can be passed after the command and arguments are passed.
71
75
 
72
76
  ```ruby
73
- command_line('some_webserver', { 'PORT' => '80' })
77
+ command_line('some_webserver', env: { 'PORT' => '80' })
78
+ ```
79
+
80
+ If you're concerned about the command running too long you can set a `:timeout`.
81
+ Exceeding the timeout will cause a `CommandLine::TimeoutError` to be raised.
82
+
83
+ ```ruby
84
+ >> command_line('sleep', 5, timeout: 2)
85
+ CommandLine::TimeoutError (execution expired)
86
+ ```
87
+
88
+ You can use `command_line!` if you want to raise an error on an exit failure.
89
+ The contents of `stderr` will be the error message.
90
+
91
+ ```ruby
92
+ >> command_line!('grep')
93
+ CommandLine::ExitFailureError (usage: grep [-abc....
74
94
  ```
75
95
 
76
96
  ### RSpec
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
+ require 'timeout'
4
5
 
5
6
  require 'command_line/result'
6
7
  require 'command_line/version'
@@ -10,15 +11,28 @@ require 'command_line/version'
10
11
  # environment variables. It's also helpful for testing commmand-line
11
12
  # applications.
12
13
  module CommandLine
14
+ # Top-level error class. All other errors subclass this.
15
+ class Error < StandardError; end
16
+
17
+ # Raised if CommandLine#command_line! is called an has an exit failure.
18
+ class ExitFailureError < Error; end
19
+
20
+ # Raised if a timeout is given and exceeded.
21
+ class TimeoutError < Error; end
22
+
13
23
  module_function
14
24
 
15
25
  # Run a command and get back the result.
16
26
  #
17
- # @param command [String] the command to run
18
- # @param args [Array<String>] any arguments passed to the command
27
+ # @param command [String] The command to run.
28
+ # @param args [Array] Any arguments passed to the command. All arguments will
29
+ # be converted to strings using `to_s`.
19
30
  # @param [Hash] env: Pass environment variables to use. The key should
20
31
  # be a String representing the environment variable name. The value
21
32
  # is the value you want that variable to have.
33
+ # @param [Integer, Float, nil] Number of seconds to wait for the block to
34
+ # terminate. Floats can be used to specify fractional seconds. A value of 0
35
+ # or nil will execute the block without any timeout.
22
36
  #
23
37
  # @yield [stdin] Handle any input on stdin that the command needs.
24
38
  # @yieldparam stdin [IO]
@@ -33,24 +47,54 @@ module CommandLine
33
47
  # end
34
48
  #
35
49
  # @example
36
- # command_line('some_webserver', { 'PORT' => '80' })
50
+ # command_line('some_webserver', env: { 'PORT' => '80' })
37
51
  #
38
52
  # @return [Result]
39
- def command_line(command, *args, env: {})
53
+ def command_line(command, *args, env: {}, timeout: nil)
40
54
  stdout = ''
41
55
  stderr = ''
42
56
  status = nil
43
57
 
44
- Open3.popen3(env, command, *args) do |i, o, e, wait_thr|
45
- yield i if block_given?
58
+ Open3.popen3(env, command.to_str, *args.map(&:to_s)) do |i, o, e, wait_thr|
59
+ begin
60
+ threads = []
61
+
62
+ Timeout.timeout(timeout, TimeoutError) do
63
+ yield i if block_given?
46
64
 
47
- [
48
- Thread.new { stdout = o.read },
49
- Thread.new { stderr = e.read }
50
- ].each(&:join)
51
- status = wait_thr.value
65
+ threads << Thread.new { stdout = o.read }
66
+ threads << Thread.new { stderr = e.read }
67
+ threads.each(&:join)
68
+ status = wait_thr.value
69
+ end
70
+ rescue TimeoutError => e
71
+ threads.map(&:kill)
72
+
73
+ raise e
74
+ end
52
75
  end
53
76
 
54
77
  Result.new(stdout, stderr, status)
55
78
  end
79
+
80
+ # Same as CommandLine.command_line except that a failure on exit raises an
81
+ # error.
82
+ #
83
+ # @see CommandLine.command_line
84
+ #
85
+ # @example
86
+ # command_line!('echo', 'hello')
87
+ #
88
+ # @example
89
+ # command_line!('grep')
90
+ # # => CommandLine::ExitFailureError (usage: grep ...
91
+ #
92
+ # @return [Result]
93
+ # @raise [CommandLine::ExitFailureError] If the application exits with an
94
+ # error status. The message will be the contents of Result#stderr.
95
+ def command_line!(*args, &block)
96
+ command_line(*args, &block).tap do |result|
97
+ raise ExitFailureError, result.stderr if result.failure?
98
+ end
99
+ end
56
100
  end
@@ -6,11 +6,15 @@ require 'command_line'
6
6
 
7
7
  # Run a command and get back the result.
8
8
  #
9
- # @param command [String] the command to run
10
- # @param args [Array<String>] any arguments passed to the command
9
+ # @param command [String] The command to run.
10
+ # @param args [Array] Any arguments passed to the command. All arguments will
11
+ # be converted to strings using `to_s`.
11
12
  # @param [Hash] env: Pass environment variables to use. The key should
12
13
  # be a String representing the environment variable name. The value
13
14
  # is the value you want that variable to have.
15
+ # @param [Integer, Float, nil] Number of seconds to wait for the block to
16
+ # terminate. Floats can be used to specify fractional seconds. A value of 0
17
+ # or nil will execute the block without any timeout.
14
18
  #
15
19
  # @yield [stdin] Handle any input on stdin that the command needs.
16
20
  # @yieldparam stdin [IO]
@@ -25,9 +29,28 @@ require 'command_line'
25
29
  # end
26
30
  #
27
31
  # @example
28
- # command_line('some_webserver', { 'PORT' => '80' })
32
+ # command_line('some_webserver', env: { 'PORT' => '80' })
29
33
  #
30
34
  # @return [Result]
31
35
  def command_line(*args, &block)
32
36
  CommandLine.command_line(*args, &block)
33
37
  end
38
+
39
+ # Same as CommandLine.command_line except that a failure on exit raises an
40
+ # error.
41
+ #
42
+ # @see CommandLine.command_line
43
+ #
44
+ # @example
45
+ # command_line!('echo', 'hello')
46
+ #
47
+ # @example
48
+ # command_line!('grep')
49
+ # # => CommandLine::ExitFailureError (usage: grep ...
50
+ #
51
+ # @return [Result]
52
+ # @raise [CommandLine::ExitFailureError] If the application exits with an
53
+ # error status. The message will be the contents of Result#stderr.
54
+ def command_line!(*args, &block)
55
+ CommandLine.command_line!(*args, &block)
56
+ end
@@ -45,7 +45,7 @@ module CommandLine
45
45
  # command_line('grep').exitstatus
46
46
  # # => 2
47
47
  #
48
- # @return [Integer,nil]
48
+ # @return [Integer, nil]
49
49
  def exitstatus
50
50
  @status.exitstatus
51
51
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CommandLine
4
- VERSION = '1.0.1'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_line
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Lasseigne
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-16 00:00:00.000000000 Z
11
+ date: 2019-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler