methadone-rehab 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
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