methadone-rehab 1.9.2

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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +11 -0
  6. data/CHANGES.md +66 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE.txt +201 -0
  9. data/README.rdoc +179 -0
  10. data/Rakefile +98 -0
  11. data/TODO.md +3 -0
  12. data/bin/methadone +157 -0
  13. data/features/bootstrap.feature +169 -0
  14. data/features/license.feature +43 -0
  15. data/features/multilevel_commands.feature +125 -0
  16. data/features/readme.feature +26 -0
  17. data/features/rspec_support.feature +27 -0
  18. data/features/step_definitions/bootstrap_steps.rb +47 -0
  19. data/features/step_definitions/license_steps.rb +30 -0
  20. data/features/step_definitions/readme_steps.rb +26 -0
  21. data/features/step_definitions/version_steps.rb +4 -0
  22. data/features/support/env.rb +26 -0
  23. data/features/version.feature +17 -0
  24. data/lib/methadone.rb +15 -0
  25. data/lib/methadone/argv_parser.rb +50 -0
  26. data/lib/methadone/cli.rb +124 -0
  27. data/lib/methadone/cli_logger.rb +133 -0
  28. data/lib/methadone/cli_logging.rb +138 -0
  29. data/lib/methadone/cucumber.rb +174 -0
  30. data/lib/methadone/error.rb +32 -0
  31. data/lib/methadone/execution_strategy/base.rb +34 -0
  32. data/lib/methadone/execution_strategy/jvm.rb +37 -0
  33. data/lib/methadone/execution_strategy/mri.rb +16 -0
  34. data/lib/methadone/execution_strategy/open_3.rb +16 -0
  35. data/lib/methadone/execution_strategy/open_4.rb +22 -0
  36. data/lib/methadone/execution_strategy/rbx_open_4.rb +12 -0
  37. data/lib/methadone/exit_now.rb +40 -0
  38. data/lib/methadone/main.rb +1039 -0
  39. data/lib/methadone/process_status.rb +45 -0
  40. data/lib/methadone/sh.rb +223 -0
  41. data/lib/methadone/version.rb +3 -0
  42. data/methadone-rehab.gemspec +32 -0
  43. data/templates/full/.gitignore.erb +4 -0
  44. data/templates/full/README.rdoc.erb +25 -0
  45. data/templates/full/Rakefile.erb +74 -0
  46. data/templates/full/_license_head.txt.erb +2 -0
  47. data/templates/full/apache_LICENSE.txt.erb +203 -0
  48. data/templates/full/bin/executable.erb +47 -0
  49. data/templates/full/custom_LICENSE.txt.erb +0 -0
  50. data/templates/full/features/executable.feature.erb +13 -0
  51. data/templates/full/features/step_definitions/executable_steps.rb.erb +1 -0
  52. data/templates/full/features/support/env.rb.erb +16 -0
  53. data/templates/full/gplv2_LICENSE.txt.erb +14 -0
  54. data/templates/full/gplv3_LICENSE.txt.erb +15 -0
  55. data/templates/full/mit_LICENSE.txt.erb +7 -0
  56. data/templates/multicommand/bin/executable.erb +52 -0
  57. data/templates/multicommand/lib/command.rb.erb +40 -0
  58. data/templates/multicommand/lib/commands.rb.erb +7 -0
  59. data/templates/rspec/spec/something_spec.rb.erb +5 -0
  60. data/templates/test_unit/test/tc_something.rb.erb +7 -0
  61. data/test/base_test.rb +20 -0
  62. data/test/command_for_tests.sh +7 -0
  63. data/test/execution_strategy/test_base.rb +24 -0
  64. data/test/execution_strategy/test_jvm.rb +77 -0
  65. data/test/execution_strategy/test_mri.rb +32 -0
  66. data/test/execution_strategy/test_open_3.rb +70 -0
  67. data/test/execution_strategy/test_open_4.rb +86 -0
  68. data/test/execution_strategy/test_rbx_open_4.rb +25 -0
  69. data/test/test_cli_logger.rb +219 -0
  70. data/test/test_cli_logging.rb +243 -0
  71. data/test/test_exit_now.rb +37 -0
  72. data/test/test_main.rb +1213 -0
  73. data/test/test_multi.rb +405 -0
  74. data/test/test_sh.rb +404 -0
  75. metadata +321 -0
@@ -0,0 +1,86 @@
1
+ require 'base_test'
2
+ require 'mocha/setup'
3
+
4
+ # Define this symbol without requiring the library;
5
+ # all we're goingn to do is mock calls to it
6
+ module Open4
7
+ end
8
+
9
+ module ExecutionStrategy
10
+ class TestOpen_4 < BaseTest
11
+ include Methadone::ExecutionStrategy
12
+
13
+ test_that "run_command proxies to Open4.capture4" do
14
+ Given {
15
+ @command = any_string
16
+ @stdin_io = mock("IO")
17
+ @stdout = any_string
18
+ @stdout_io = StringIO.new(@stdout)
19
+ @stderr = any_string
20
+ @stderr_io = StringIO.new(@stderr)
21
+ @pid = any_int :min => 2, :max => 65536
22
+ @status = stub('Process::Status')
23
+ }
24
+ When the_test_runs
25
+ Then {
26
+ Open4.expects(:popen4).with(@command).returns([@pid,@stdin_io,@stdout_io,@stderr_io])
27
+ @stdin_io.expects(:close)
28
+ Process.expects(:waitpid2).with(@pid).returns([any_string,@status])
29
+ }
30
+
31
+ Given new_open_4_strategy
32
+ When {
33
+ @results = @strategy.run_command(@command)
34
+ }
35
+ Then {
36
+ @results[0].should == @stdout
37
+ @results[1].should == @stderr
38
+ @results[2].should be @status
39
+ }
40
+ end
41
+
42
+ test_that "run_command handles array arguments properly" do
43
+ Given {
44
+ @command = [any_string, any_string, any_string]
45
+ @stdin_io = mock("IO")
46
+ @stdout = any_string
47
+ @stdout_io = StringIO.new(@stdout)
48
+ @stderr = any_string
49
+ @stderr_io = StringIO.new(@stderr)
50
+ @pid = any_int :min => 2, :max => 65536
51
+ @status = stub('Process::Status')
52
+ }
53
+ When the_test_runs
54
+ Then {
55
+ Open4.expects(:popen4).with(*@command).returns([@pid,@stdin_io,@stdout_io,@stderr_io])
56
+ @stdin_io.expects(:close)
57
+ Process.expects(:waitpid2).with(@pid).returns([any_string,@status])
58
+ }
59
+
60
+ Given new_open_4_strategy
61
+ When {
62
+ @results = @strategy.run_command(@command)
63
+ }
64
+ Then {
65
+ @results[0].should == @stdout
66
+ @results[1].should == @stderr
67
+ @results[2].should be @status
68
+ }
69
+ end
70
+
71
+ test_that "exception_meaning_command_not_found returns Errno::ENOENT" do
72
+ Given new_open_4_strategy
73
+ When {
74
+ @klass = @strategy.exception_meaning_command_not_found
75
+ }
76
+ Then {
77
+ @klass.should == Errno::ENOENT
78
+ }
79
+ end
80
+
81
+ private
82
+ def new_open_4_strategy
83
+ lambda { @strategy = Open_4.new }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,25 @@
1
+ require 'base_test'
2
+ require 'mocha/setup'
3
+
4
+ # Define this symbol without requiring the library;
5
+ # all we're going to do is mock calls to it
6
+ module Open4
7
+ end
8
+
9
+ module ExecutionStrategy
10
+ class TestRBXOpen_4 < BaseTest
11
+ include Methadone::ExecutionStrategy
12
+
13
+ test_that "exception_meaning_command_not_found returns Errno::EINVAL" do
14
+ Given {
15
+ @strategy = RBXOpen_4.new
16
+ }
17
+ When {
18
+ @klass = @strategy.exception_meaning_command_not_found
19
+ }
20
+ Then {
21
+ @klass.should == [Errno::EINVAL,Errno::ENOENT]
22
+ }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,219 @@
1
+ require 'base_test'
2
+ require 'methadone'
3
+ require 'stringio'
4
+ require 'tempfile'
5
+
6
+ class TestCLILogger < BaseTest
7
+ include Methadone
8
+
9
+ def setup
10
+ @blank_format = proc { |severity,datetime,progname,msg|
11
+ msg + "\n"
12
+ }
13
+ @real_stderr = $stderr
14
+ @real_stdout = $stdout
15
+ $stderr = StringIO.new
16
+ $stdout = StringIO.new
17
+ end
18
+
19
+ def teardown
20
+ $stderr = @real_stderr
21
+ $stdout = @real_stdout
22
+ end
23
+
24
+ test_that "when both stderr and stdin are ttys, split the log messages between them and don't format" do
25
+ Given {
26
+ class << $stderr
27
+ def tty?; true; end
28
+ end
29
+ class << $stdout
30
+ def tty?; true; end
31
+ end
32
+
33
+ @logger = CLILogger.new
34
+ @logger.level = Logger::DEBUG
35
+ }
36
+
37
+ When log_all_levels
38
+
39
+ Then {
40
+ $stdout.string.should == "debug\ninfo\n"
41
+ $stderr.string.should == "warn\nerror\nfatal\n"
42
+ }
43
+ end
44
+
45
+ test_that "when both stderr and stdin are ttys, setting the level higher than WARN should affect the error logger" do
46
+ Given {
47
+ class << $stderr
48
+ def tty?; true; end
49
+ end
50
+ class << $stdout
51
+ def tty?; true; end
52
+ end
53
+
54
+ @logger = CLILogger.new
55
+ @logger.level = Logger::ERROR
56
+ }
57
+
58
+ When log_all_levels
59
+
60
+ Then {
61
+ $stdout.string.should == ""
62
+ $stderr.string.should == "error\nfatal\n"
63
+ }
64
+ end
65
+
66
+ test_that "logger sends debug and info to stdout, and warns, errors, and fatals to stderr" do
67
+ Given a_logger_with_blank_format
68
+ When log_all_levels
69
+
70
+ Then stdout_should_have_everything
71
+ And {
72
+ $stderr.string.should == "warn\nerror\nfatal\n"
73
+ }
74
+ end
75
+
76
+ test_that "we can control what goes to stderr" do
77
+ Given a_logger_with_blank_format :at_error_level => Logger::Severity::FATAL
78
+
79
+ When log_all_levels
80
+
81
+ Then stdout_should_have_everything
82
+ And {
83
+ $stderr.string.should == "fatal\n"
84
+ }
85
+ end
86
+
87
+ test_that "we can log to alternate devices easily" do
88
+ Given {
89
+ @out = StringIO.new
90
+ @err = StringIO.new
91
+
92
+ @logger = CLILogger.new(@out,@err)
93
+ @logger.level = Logger::DEBUG
94
+ @logger.formatter = @blank_format
95
+ }
96
+
97
+ When log_all_levels
98
+
99
+ Then {
100
+ @out.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
101
+ @err.string.should == "warn\nerror\nfatal\n"
102
+ }
103
+ end
104
+
105
+
106
+ test_that "error logger ignores the log level" do
107
+ Given a_logger_with_blank_format :at_level => Logger::Severity::FATAL
108
+ When log_all_levels
109
+
110
+ Then {
111
+ $stdout.string.should == "fatal\n"
112
+ $stderr.string.should == "warn\nerror\nfatal\n"
113
+ }
114
+ end
115
+
116
+ test_that "both loggers use the same date format" do
117
+ Given {
118
+ @logger = CLILogger.new
119
+ @logger.level = Logger::DEBUG
120
+ @logger.datetime_format = "the time"
121
+ }
122
+
123
+ When {
124
+ @logger.debug("debug")
125
+ @logger.error("error")
126
+ }
127
+
128
+ Then {
129
+ $stdout.string.should match /the time.*DEBUG.*debug/
130
+ $stderr.string.should match /the time.*ERROR.*error/
131
+ }
132
+ end
133
+
134
+ test_that "error logger does not get <<" do
135
+ Given a_logger_with_blank_format
136
+ When {
137
+ @logger << "foo"
138
+ }
139
+ Then {
140
+ $stdout.string.should == "foo"
141
+ $stderr.string.should == ""
142
+ }
143
+ end
144
+
145
+ test_that "error logger can have a different format" do
146
+ Given {
147
+ @logger = logger_with_blank_format
148
+ @logger.error_formatter = proc do |severity,datetime,progname,msg|
149
+ "ERROR_LOGGER: #{msg}\n"
150
+ end
151
+ }
152
+ When {
153
+ @logger.debug("debug")
154
+ @logger.error("error")
155
+ }
156
+ Then {
157
+ $stdout.string.should == "debug\nerror\n"
158
+ $stderr.string.should == "ERROR_LOGGER: error\n"
159
+ }
160
+ end
161
+
162
+ test_that "we can use filenames as log devices" do
163
+ Given {
164
+ tempfile = Tempfile.new("stderr_log")
165
+ @stdout_file = tempfile.path
166
+ tempfile.close
167
+
168
+ tempfile = Tempfile.new("stdout_log")
169
+ @stderr_file = tempfile.path
170
+ tempfile.close
171
+ }
172
+ When {
173
+ @logger = CLILogger.new(@stdout_file,@stderr_file)
174
+ @logger.info("some info")
175
+ @logger.error("some error")
176
+ }
177
+ Then {
178
+ File.read(@stdout_file).should =~ /some info/
179
+ File.read(@stderr_file).should =~ /some error/
180
+ }
181
+ end
182
+
183
+ private
184
+
185
+ def log_all_levels
186
+ proc do
187
+ @logger.debug("debug")
188
+ @logger.info("info")
189
+ @logger.warn("warn")
190
+ @logger.error("error")
191
+ @logger.fatal("fatal")
192
+ end
193
+ end
194
+
195
+
196
+ def logger_with_blank_format
197
+ logger = CLILogger.new
198
+ logger.formatter = @blank_format
199
+ logger.level = Logger::Severity::DEBUG
200
+ logger
201
+ end
202
+
203
+ # options - :at_level - level to set the logger
204
+ def a_logger_with_blank_format(options = {})
205
+ proc do
206
+ @logger = logger_with_blank_format
207
+ @logger.level = options[:at_level] if options[:at_level]
208
+ @logger.error_level = options[:at_error_level] if options[:at_error_level]
209
+ end
210
+ end
211
+
212
+ def stdout_should_have_everything
213
+ proc do
214
+ $stdout.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
215
+ end
216
+ end
217
+
218
+
219
+ end
@@ -0,0 +1,243 @@
1
+ require 'base_test'
2
+ require 'methadone'
3
+ require 'stringio'
4
+
5
+ class TestCLILogging < BaseTest
6
+ include Methadone
7
+
8
+ SLEEP_TIME = 0.1
9
+
10
+ def setup
11
+ @blank_format = proc do |severity,datetime,progname,msg|
12
+ msg + "\n"
13
+ end
14
+ @real_stderr = $stderr
15
+ @real_stdout = $stdout
16
+ $stderr = StringIO.new
17
+ $stdout = StringIO.new
18
+ end
19
+
20
+ def teardown
21
+ $stderr = @real_stderr
22
+ $stdout = @real_stdout
23
+ end
24
+
25
+ test_that "a class can include CLILogging and get terser logging" do
26
+ Given {
27
+ @class_with_logger = MyClassThatLogsToStdout.new
28
+ }
29
+
30
+ When {
31
+ @class_with_logger.doit
32
+ }
33
+
34
+ Then {
35
+ $stdout.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
36
+ $stderr.string.should == "warn\nerror\nfatal\n"
37
+ }
38
+ end
39
+
40
+ test_that "another class using CLILogging gets the same logger instance" do
41
+ Given {
42
+ @first = MyClassThatLogsToStdout.new
43
+ @second = MyOtherClassThatLogsToStdout.new
44
+ }
45
+ Then {
46
+ @first.logger_id.should == @second.logger_id
47
+ }
48
+ end
49
+
50
+ test_that "we can change the global logger via self." do
51
+ Given {
52
+ @first = MyClassThatLogsToStdout.new
53
+ @second = MyOtherClassThatLogsToStdout.new
54
+ @logger_id = @second.logger_id
55
+ }
56
+ When {
57
+ @second.instance_eval do
58
+ self.logger=(Methadone::CLILogger.new)
59
+ end
60
+ }
61
+ Then {
62
+ @logger_id.should_not == @second.logger_id
63
+ @first.logger_id.should == @second.logger_id
64
+ }
65
+ end
66
+
67
+ test_that "we can change the global logger change_logger()" do
68
+ Given {
69
+ @first = MyClassThatLogsToStdout.new
70
+ @second = MyOtherClassThatLogsToStdout.new
71
+ @logger_id = @second.logger_id
72
+ }
73
+ When {
74
+ @second.instance_eval do
75
+ change_logger(Logger.new(STDERR))
76
+ end
77
+ }
78
+ Then {
79
+ @logger_id.should_not == @second.logger_id
80
+ @first.logger_id.should == @second.logger_id
81
+ }
82
+ end
83
+
84
+ test_that "we cannot use a nil logger" do
85
+ Given {
86
+ @other_class = MyOtherClassThatLogsToStdout.new
87
+ }
88
+ Then {
89
+ lambda {
90
+ MyOtherClassThatLogsToStdout.new.instance_eval do
91
+ self.logger=(nil)
92
+ end
93
+ }.should raise_error(ArgumentError)
94
+ }
95
+ end
96
+
97
+ test_that "when we call use_log_level_option, it sets up logging level CLI options" do
98
+ Given {
99
+ @app = MyAppThatActsLikeItUsesMain.new
100
+ @app.call_use_log_level_option
101
+ @level = any_int
102
+ }
103
+ When {
104
+ @app.use_option(@level)
105
+ }
106
+ Then {
107
+ @app.logger.level.should == @level
108
+ }
109
+ end
110
+
111
+ test_that "when we call use_log_level_option, then later change the logger, that logger gets the proper level set" do
112
+ Given {
113
+ @app = MyAppThatActsLikeItUsesMain.new
114
+ @app.call_use_log_level_option
115
+ @level = any_int
116
+ }
117
+ When {
118
+ @app.use_option(@level)
119
+ @other_logger = OpenStruct.new
120
+ @app.change_logger(@other_logger)
121
+ }
122
+ Then {
123
+ @other_logger.level.should == @level
124
+ }
125
+ end
126
+
127
+
128
+ test_that "when we enable runtime log level toggling, it toggles the log level on receiving the set signal" do
129
+ Given {
130
+ @app = MyAppThatActsLikeItUsesMain.new
131
+ @app.call_use_log_level_option( :toggle_debug_on_signal => 'USR2' )
132
+ @level = Logger::INFO
133
+ @app.use_option(@level)
134
+ }
135
+ When {
136
+ send_signal_and_wait_a_moment('USR2')
137
+ }
138
+ Then {
139
+ @app.logger.level.should == Logger::DEBUG
140
+ }
141
+ end
142
+
143
+ test_that "when we toggle the log level and change the logger, the new logger has also it's log level increased" do
144
+ Given {
145
+ @app = MyAppThatActsLikeItUsesMain.new
146
+ @app.call_use_log_level_option( :toggle_debug_on_signal => 'USR2' )
147
+ @level = Logger::INFO
148
+ @app.use_option(@level)
149
+ }
150
+ When {
151
+ send_signal_and_wait_a_moment('USR2')
152
+ @other_logger = OpenStruct.new
153
+ @app.change_logger(@other_logger)
154
+ }
155
+ Then {
156
+ @other_logger.level.should == Logger::DEBUG
157
+ }
158
+ end
159
+
160
+ test_that "when we enable runtime log level toggling and send the signal twice, the original log level is restored" do
161
+ Given {
162
+ @app = MyAppThatActsLikeItUsesMain.new
163
+ @app.call_use_log_level_option( :toggle_debug_on_signal => 'USR2' )
164
+ @level = Logger::INFO
165
+ @app.use_option(@level)
166
+ }
167
+ When {
168
+ send_signal_and_wait_a_moment('USR2')
169
+ send_signal_and_wait_a_moment('USR2')
170
+ }
171
+ Then {
172
+ @app.logger.level.should == Logger::INFO
173
+ }
174
+ end
175
+
176
+
177
+ class MyAppThatActsLikeItUsesMain
178
+ include Methadone::CLILogging
179
+
180
+ def call_use_log_level_option(args = {})
181
+ use_log_level_option(args)
182
+ end
183
+
184
+ def use_option(level)
185
+ @block.call(level)
186
+ end
187
+
188
+ def on(*args,&block)
189
+ @block = block
190
+ end
191
+
192
+ def logger
193
+ @logger ||= OpenStruct.new
194
+ end
195
+ end
196
+
197
+ class MyClassThatLogsToStdout
198
+ include Methadone::CLILogging
199
+
200
+ def initialize
201
+ logger.formatter = proc do |severity,datetime,progname,msg|
202
+ msg + "\n"
203
+ end
204
+ logger.level = Logger::DEBUG
205
+ end
206
+
207
+ def doit
208
+ debug("debug")
209
+ info("info")
210
+ warn("warn")
211
+ error("error")
212
+ fatal("fatal")
213
+ end
214
+
215
+ def logger_id; logger.object_id; end
216
+ end
217
+
218
+
219
+ class MyOtherClassThatLogsToStdout
220
+ include Methadone::CLILogging
221
+
222
+ def initialize
223
+ logger.formatter = proc do |severity,datetime,progname,msg|
224
+ msg + "\n"
225
+ end
226
+ end
227
+
228
+ def doit
229
+ debug("debug")
230
+ info("info")
231
+ warn("warn")
232
+ error("error")
233
+ fatal("fatal")
234
+ end
235
+
236
+ def logger_id; logger.object_id; end
237
+ end
238
+
239
+ def send_signal_and_wait_a_moment(signal)
240
+ Process.kill(signal, $$)
241
+ sleep(SLEEP_TIME) # call sleep to give the trap handler a chance to kick in
242
+ end
243
+ end