linecook 0.6.2 → 1.0.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.
- data/History +139 -0
- data/HowTo/Control Virtual Machines +106 -0
- data/HowTo/Generate Scripts +263 -0
- data/HowTo/Run Scripts +87 -0
- data/HowTo/Setup Virtual Machines +76 -0
- data/License.txt +1 -1
- data/README +78 -59
- data/bin/linecook +12 -5
- data/bin/linecook_run +45 -0
- data/bin/linecook_scp +50 -0
- data/lib/linecook.rb +1 -3
- data/lib/linecook/attributes.rb +49 -12
- data/lib/linecook/commands.rb +9 -4
- data/lib/linecook/commands/build.rb +69 -0
- data/lib/linecook/commands/command.rb +13 -3
- data/lib/linecook/commands/command_error.rb +6 -0
- data/lib/linecook/commands/env.rb +74 -8
- data/lib/linecook/commands/helper.rb +271 -24
- data/lib/linecook/commands/init.rb +10 -6
- data/lib/linecook/commands/package.rb +36 -18
- data/lib/linecook/commands/run.rb +66 -0
- data/lib/linecook/commands/snapshot.rb +114 -0
- data/lib/linecook/commands/ssh.rb +39 -0
- data/lib/linecook/commands/start.rb +34 -0
- data/lib/linecook/commands/state.rb +32 -0
- data/lib/linecook/commands/stop.rb +22 -0
- data/lib/linecook/commands/vbox_command.rb +130 -0
- data/lib/linecook/cookbook.rb +112 -55
- data/lib/linecook/package.rb +293 -109
- data/lib/linecook/proxy.rb +19 -0
- data/lib/linecook/recipe.rb +321 -62
- data/lib/linecook/template.rb +7 -101
- data/lib/linecook/test.rb +196 -141
- data/lib/linecook/test/command_parser.rb +75 -0
- data/lib/linecook/test/file_test.rb +153 -35
- data/lib/linecook/test/shell_test.rb +176 -0
- data/lib/linecook/utils.rb +25 -7
- data/lib/linecook/version.rb +4 -4
- data/templates/Rakefile +44 -47
- data/templates/_gitignore +1 -1
- data/templates/attributes/project_name.rb +4 -4
- data/templates/config/ssh +15 -0
- data/templates/files/help.txt +1 -0
- data/templates/helpers/project_name/assert_content_equal.erb +15 -0
- data/templates/helpers/project_name/create_dir.erb +9 -0
- data/templates/helpers/project_name/create_file.erb +8 -0
- data/templates/helpers/project_name/install_file.erb +8 -0
- data/templates/packages/abox.yml +4 -0
- data/templates/recipes/abox.rb +22 -0
- data/templates/recipes/abox_test.rb +14 -0
- data/templates/templates/todo.txt.erb +3 -0
- data/templates/test/project_name_test.rb +19 -0
- data/templates/test/test_helper.rb +14 -0
- metadata +43 -41
- data/cookbook +0 -0
- data/lib/linecook/commands/helpers.rb +0 -28
- data/lib/linecook/commands/vbox.rb +0 -85
- data/lib/linecook/helper.rb +0 -117
- data/lib/linecook/shell.rb +0 -11
- data/lib/linecook/shell/posix.rb +0 -145
- data/lib/linecook/shell/test.rb +0 -254
- data/lib/linecook/shell/unix.rb +0 -117
- data/lib/linecook/shell/utils.rb +0 -138
- data/templates/README +0 -90
- data/templates/files/file.txt +0 -1
- data/templates/helpers/project_name/echo.erb +0 -5
- data/templates/recipes/project_name.rb +0 -20
- data/templates/scripts/project_name.yml +0 -7
- data/templates/templates/template.txt.erb +0 -3
- data/templates/vbox/setup/virtual_box +0 -86
- data/templates/vbox/ssh/id_rsa +0 -27
- data/templates/vbox/ssh/id_rsa.pub +0 -1
data/lib/linecook/test.rb
CHANGED
@@ -1,172 +1,227 @@
|
|
1
|
-
require 'linecook/
|
2
|
-
require 'linecook/recipe'
|
1
|
+
require 'linecook/package'
|
3
2
|
require 'linecook/test/file_test'
|
4
|
-
require 'linecook/test/
|
5
|
-
require 'linecook/utils'
|
3
|
+
require 'linecook/test/shell_test'
|
6
4
|
|
7
5
|
module Linecook
|
8
6
|
module Test
|
7
|
+
module ClassMethods
|
8
|
+
def host
|
9
|
+
@host ||= ENV['LINECOOK_TEST_HOST'] || name
|
10
|
+
end
|
11
|
+
|
12
|
+
def use_host(host)
|
13
|
+
@host = host
|
14
|
+
end
|
15
|
+
|
16
|
+
def only_hosts(*patterns)
|
17
|
+
patterns.collect! do |pattern|
|
18
|
+
pattern.kind_of?(Regexp) ? pattern : /\A#{pattern}\z/
|
19
|
+
end
|
20
|
+
|
21
|
+
@skip_test_suite = false
|
22
|
+
unless patterns.any? {|pattern| host =~ pattern }
|
23
|
+
skip_test "not for host (#{host})"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Causes a test suite to be skipped. If a message is given, it will
|
28
|
+
# print and notify the user the test suite has been skipped.
|
29
|
+
def skip_test(msg=nil)
|
30
|
+
@skip_test_suite = true
|
31
|
+
skip_messages << msg
|
32
|
+
end
|
33
|
+
|
34
|
+
# Modifies the default suite method to skip the suit unless
|
35
|
+
# run_test_suite is true. If the test is skipped, the skip_messages
|
36
|
+
# will be printed along with the default 'Skipping <Test>' message.
|
37
|
+
def suite # :nodoc:
|
38
|
+
if (@skip_test_suite ||= false)
|
39
|
+
skip_message = skip_messages.compact.join(', ')
|
40
|
+
puts "Skipping #{name}#{skip_message.empty? ? '' : ': ' + skip_message}"
|
41
|
+
|
42
|
+
# return an empty test suite of the appropriate name
|
43
|
+
::Test::Unit::TestSuite.new(name)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def skip_messages # :nodoc:
|
52
|
+
@skip_messages ||= []
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module ModuleMethods
|
57
|
+
module_function
|
58
|
+
|
59
|
+
def included(base)
|
60
|
+
base.extend ClassMethods
|
61
|
+
base.extend ModuleMethods unless base.kind_of?(Class)
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
extend ModuleMethods
|
67
|
+
|
9
68
|
include FileTest
|
69
|
+
include ShellTest
|
10
70
|
|
11
|
-
|
12
|
-
|
13
|
-
|
71
|
+
LINECOOK_DIR = File.expand_path('../../..', __FILE__)
|
72
|
+
LINECOOK = File.join(LINECOOK_DIR, 'bin/linecook')
|
73
|
+
|
74
|
+
def method_dir
|
75
|
+
@host_method_dir ||= begin
|
76
|
+
if test_host = ENV['LINECOOK_TEST_HOST']
|
77
|
+
File.join(super, test_host)
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def remote_dir
|
85
|
+
method_dir[(user_dir.length + 1)..-1]
|
86
|
+
end
|
87
|
+
|
88
|
+
def ssh_config_file
|
89
|
+
method_ssh_config_file = path('config/ssh')
|
90
|
+
File.file?(method_ssh_config_file) ? method_ssh_config_file : 'config/ssh'
|
91
|
+
end
|
92
|
+
|
93
|
+
def setup_cookbook(configs=nil, project_dir=method_dir)
|
94
|
+
configs ||= Cookbook.config_file(project_dir)
|
95
|
+
@cookbook = Cookbook.setup(configs, project_dir)
|
96
|
+
end
|
14
97
|
|
15
98
|
def cookbook
|
16
|
-
@cookbook ||=
|
99
|
+
@cookbook ||= setup_cookbook
|
17
100
|
end
|
18
101
|
|
19
|
-
def
|
20
|
-
cookbook
|
102
|
+
def setup_package(env={})
|
103
|
+
@package = Package.setup(env, cookbook)
|
21
104
|
end
|
22
105
|
|
23
|
-
def
|
24
|
-
|
106
|
+
def package
|
107
|
+
@package ||= setup_package
|
25
108
|
end
|
26
109
|
|
27
|
-
def
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
def build(env={})
|
32
|
-
env = Utils.deep_merge(default_env, env)
|
33
|
-
Recipe.build(env).export File.join(method_dir, 'scripts')
|
34
|
-
end
|
35
|
-
|
36
|
-
# Asserts whether or not the a and b strings are equal, with a more
|
37
|
-
# readable output than assert_equal for large strings (especially large
|
38
|
-
# strings with significant whitespace).
|
39
|
-
#
|
40
|
-
# One gotcha is that assert_output_equal lstrips indentation off of 'a',
|
41
|
-
# so that these all pass:
|
42
|
-
#
|
43
|
-
# assert_output_equal %q{
|
44
|
-
# line one
|
45
|
-
# line two
|
46
|
-
# }, "line one\nline two\n"
|
47
|
-
#
|
48
|
-
# assert_output_equal %q{
|
49
|
-
# line one
|
50
|
-
# line two
|
51
|
-
# }, "line one\nline two\n
|
52
|
-
#
|
53
|
-
# assert_output_equal %q{
|
54
|
-
# line one
|
55
|
-
# line two
|
56
|
-
# }, "line one\nline two\n"
|
57
|
-
#
|
58
|
-
# Use the assert_output_equal! method to prevent indentation stripping.
|
59
|
-
def assert_output_equal(a, b, msg=nil)
|
60
|
-
a = strip_indent(a)
|
61
|
-
assert_output_equal!(a, b, msg)
|
110
|
+
def use_helpers(*helpers)
|
111
|
+
@helpers = helpers
|
62
112
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if a == b
|
67
|
-
assert true
|
68
|
-
else
|
69
|
-
flunk %Q{
|
70
|
-
#{msg}
|
71
|
-
==================== expected output ====================
|
72
|
-
#{whitespace_escape(a)}
|
73
|
-
======================== but was ========================
|
74
|
-
#{whitespace_escape(b)}
|
75
|
-
=========================================================
|
76
|
-
}
|
77
|
-
end
|
113
|
+
|
114
|
+
def helpers
|
115
|
+
@helpers ||= []
|
78
116
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# with assert_match.
|
83
|
-
#
|
84
|
-
# If a is a string, then indentation is stripped off and it is turned
|
85
|
-
# into a RegexpEscape. Using that syntax, all these pass:
|
86
|
-
#
|
87
|
-
# assert_alike %q{
|
88
|
-
# the time is: :...:
|
89
|
-
# now!
|
90
|
-
# }, "the time is: #{Time.now}\nnow!\n"
|
91
|
-
#
|
92
|
-
# assert_alike %q{
|
93
|
-
# the time is: :...:
|
94
|
-
# now!
|
95
|
-
# }, "the time is: #{Time.now}\nnow!\n"
|
96
|
-
#
|
97
|
-
# assert_alike %q{
|
98
|
-
# the time is: :...:
|
99
|
-
# now!
|
100
|
-
# }, "the time is: #{Time.now}\nnow!\n"
|
101
|
-
#
|
102
|
-
# Use assert_alike! to prevent indentation stripping (conversion to a
|
103
|
-
# RegexpEscape is still in effect).
|
104
|
-
def assert_alike(a, b, msg=nil)
|
105
|
-
a = strip_indent(a) if a.kind_of?(String)
|
106
|
-
assert_alike!(a, b, msg)
|
117
|
+
|
118
|
+
def use_host(host)
|
119
|
+
@host = host
|
107
120
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
a = RegexpEscape.new(a) if a.kind_of?(String)
|
112
|
-
|
113
|
-
if b =~ a
|
114
|
-
assert true
|
115
|
-
else
|
116
|
-
flunk %Q{
|
117
|
-
#{msg}
|
118
|
-
================= expected output like ==================
|
119
|
-
#{whitespace_escape(a)}
|
120
|
-
======================== but was ========================
|
121
|
-
#{whitespace_escape(b)}
|
122
|
-
=========================================================
|
123
|
-
}
|
124
|
-
end
|
121
|
+
|
122
|
+
def host
|
123
|
+
@host ||= self.class.host
|
125
124
|
end
|
126
|
-
|
127
|
-
def
|
128
|
-
|
125
|
+
|
126
|
+
def runlist
|
127
|
+
@runlist ||= []
|
128
|
+
end
|
129
|
+
|
130
|
+
def setup_recipe(target_name=package.next_target_name('recipe'), mode=0700, &block)
|
131
|
+
recipe = package.setup_recipe(target_name, mode)
|
132
|
+
helpers.each {|helper| recipe.extend helper }
|
133
|
+
|
134
|
+
recipe.instance_eval(&block) if block_given?
|
135
|
+
runlist << target_name
|
136
|
+
|
137
|
+
@recipe = recipe
|
138
|
+
end
|
139
|
+
|
140
|
+
def recipe
|
141
|
+
@recipe ||= setup_recipe
|
142
|
+
end
|
143
|
+
|
144
|
+
def assert_recipe(expected, recipe=setup_recipe, &block)
|
145
|
+
recipe.instance_eval(&block) if block_given?
|
146
|
+
recipe.close
|
147
|
+
|
129
148
|
assert_output_equal expected, recipe.result
|
149
|
+
recipe
|
130
150
|
end
|
131
151
|
|
132
|
-
def
|
133
|
-
recipe.instance_eval(&block)
|
152
|
+
def assert_recipe_matches(expected, recipe=setup_recipe, &block)
|
153
|
+
recipe.instance_eval(&block) if block_given?
|
154
|
+
recipe.close
|
155
|
+
|
134
156
|
assert_alike expected, recipe.result
|
157
|
+
recipe
|
135
158
|
end
|
136
|
-
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
159
|
+
|
160
|
+
def build_package(host=self.host)
|
161
|
+
package_dir = path("packages/#{host}")
|
162
|
+
|
163
|
+
package.build
|
164
|
+
package.export package_dir
|
165
|
+
|
166
|
+
package_dir
|
142
167
|
end
|
143
168
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
indent, str = $1, $2, $3
|
150
|
-
|
151
|
-
if indent.length > 0
|
152
|
-
str.gsub!(/^ {0,#{indent.length}}/, '')
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
str
|
169
|
+
def run_package(options={}, host=self.host)
|
170
|
+
options['remote_script'] ||= runlist.join(',')
|
171
|
+
|
172
|
+
build_package host
|
173
|
+
run_project options, host
|
157
174
|
end
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
175
|
+
|
176
|
+
def build_project(options={})
|
177
|
+
options = {
|
178
|
+
'project_dir' => method_dir,
|
179
|
+
'quiet' => true
|
180
|
+
}.merge(options)
|
181
|
+
|
182
|
+
linecook('build', options)
|
183
|
+
end
|
184
|
+
|
185
|
+
# pick up user dir as a gem... bundler!
|
186
|
+
def run_project(options={}, *package_names)
|
187
|
+
options = {
|
188
|
+
'ssh_config_file' => ssh_config_file,
|
189
|
+
'project_dir' => method_dir,
|
190
|
+
'remote_dir' => remote_dir,
|
191
|
+
'quiet' => true,
|
192
|
+
}.merge(options)
|
193
|
+
|
194
|
+
linecook('run', options, *package_names)
|
195
|
+
end
|
196
|
+
|
197
|
+
def linecook(cmd, options={}, *args)
|
198
|
+
stdout = prepare("log/#{cmd}.out")
|
199
|
+
stderr = prepare("log/#{cmd}.err")
|
200
|
+
|
201
|
+
command = "#{linecook_cmd(cmd, options, *args)} 2> '#{stderr}' > '#{stdout}'"
|
202
|
+
system(command)
|
203
|
+
|
204
|
+
[File.read(stdout), "% #{command}\n#{File.read(stderr)}"]
|
205
|
+
end
|
206
|
+
|
207
|
+
def linecook_cmd(cmd, options={}, *args)
|
208
|
+
opts = []
|
209
|
+
options.each_pair do |key, value|
|
210
|
+
key = key.gsub('_', '-')
|
211
|
+
|
212
|
+
case value
|
213
|
+
when true
|
214
|
+
opts << "--#{key}"
|
215
|
+
when nil, false
|
216
|
+
else
|
217
|
+
opts << "--#{key} '#{value}'"
|
168
218
|
end
|
169
219
|
end
|
220
|
+
|
221
|
+
args = args.collect! {|arg| "'#{arg}'" }
|
222
|
+
|
223
|
+
cmd = [LINECOOK, cmd] + opts.sort + args
|
224
|
+
cmd.join(' ')
|
170
225
|
end
|
171
226
|
end
|
172
227
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Linecook
|
2
|
+
module Test
|
3
|
+
class CommandParser
|
4
|
+
attr_reader :ps1
|
5
|
+
attr_reader :ps2
|
6
|
+
attr_reader :prefix
|
7
|
+
attr_reader :suffix
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
options = {
|
11
|
+
:ps1 => '% ',
|
12
|
+
:ps2 => '> ',
|
13
|
+
:prefix => '0<&- 2>&1 ',
|
14
|
+
:suffix => ''
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
@ps1 = options[:ps1]
|
18
|
+
@ps2 = options[:ps2]
|
19
|
+
@prefix = options[:prefix]
|
20
|
+
@suffix = options[:suffix]
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_cmd(cmd)
|
24
|
+
cmd =~ /.*?#\s*(?:\[(\d+)\])?\s*(\.{3})?/
|
25
|
+
exit_status = $1 ? $1.to_i : 0
|
26
|
+
output = $2 ? nil : ""
|
27
|
+
|
28
|
+
[cmd, output, exit_status]
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse(script)
|
32
|
+
commands = []
|
33
|
+
|
34
|
+
command, output, exit_status = nil, "", 0
|
35
|
+
script.each_line do |line|
|
36
|
+
case
|
37
|
+
when line.index(ps1) == 0
|
38
|
+
if command
|
39
|
+
commands << ["#{prefix}#{command}#{suffix}", output, exit_status]
|
40
|
+
end
|
41
|
+
|
42
|
+
command, output, exit_status = parse_cmd lchomp(ps1, line)
|
43
|
+
|
44
|
+
when command.nil?
|
45
|
+
unless line.strip.empty?
|
46
|
+
command, output, exit_status = parse_cmd(line)
|
47
|
+
end
|
48
|
+
|
49
|
+
when line.index(ps2) == 0
|
50
|
+
command << lchomp(ps2, line)
|
51
|
+
|
52
|
+
when output.nil?
|
53
|
+
output = line
|
54
|
+
|
55
|
+
else
|
56
|
+
output << line
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if command
|
61
|
+
commands << ["#{prefix}#{command}#{suffix}", output, exit_status]
|
62
|
+
end
|
63
|
+
|
64
|
+
commands
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def lchomp(prefix, line) # :nodoc:
|
70
|
+
length = prefix.length
|
71
|
+
line[length, line.length - length]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -4,11 +4,101 @@ module Linecook
|
|
4
4
|
module ClassMethods
|
5
5
|
attr_accessor :class_dir
|
6
6
|
|
7
|
-
|
7
|
+
attr_reader :cleanup_method_registry
|
8
|
+
|
9
|
+
def cleanup_methods
|
10
|
+
@cleanup_methods ||= begin
|
11
|
+
cleanup_methods = {}
|
12
|
+
|
13
|
+
ancestors.reverse.each do |ancestor|
|
14
|
+
next unless ancestor.kind_of?(ClassMethods)
|
15
|
+
ancestor.cleanup_method_registry.each_pair do |key, value|
|
16
|
+
if value.nil?
|
17
|
+
cleanup_methods.delete(key)
|
18
|
+
else
|
19
|
+
cleanup_methods[key] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
cleanup_methods
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_cleanup_methods
|
29
|
+
@cleanup_methods = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def self.initialize(base)
|
8
35
|
# Infers the test directory from the calling file.
|
9
36
|
# 'some_class_test.rb' => 'some_class_test'
|
10
|
-
calling_file = caller[
|
37
|
+
calling_file = caller[1].gsub(/:\d+(:in .*)?$/, "")
|
11
38
|
base.class_dir = calling_file.chomp(File.extname(calling_file))
|
39
|
+
|
40
|
+
base.reset_cleanup_methods
|
41
|
+
unless base.instance_variable_defined?(:@cleanup_method_registry)
|
42
|
+
base.instance_variable_set(:@cleanup_method_registry, {})
|
43
|
+
end
|
44
|
+
|
45
|
+
unless base.instance_variable_defined?(:@cleanup_paths)
|
46
|
+
base.instance_variable_set(:@cleanup_paths, ['.'])
|
47
|
+
end
|
48
|
+
|
49
|
+
unless base.instance_variable_defined?(:@cleanup)
|
50
|
+
base.instance_variable_set(:@cleanup, true)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inherited(base) # :nodoc:
|
55
|
+
ClassMethods.initialize(base)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_method_cleanup(method_name, dirs)
|
60
|
+
reset_cleanup_methods
|
61
|
+
cleanup_method_registry[method_name.to_sym] = dirs
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_method_cleanup(method_name)
|
65
|
+
reset_cleanup_methods
|
66
|
+
cleanup_method_registry.delete(method_name.to_sym)
|
67
|
+
end
|
68
|
+
|
69
|
+
def undef_method_cleanup(method_name)
|
70
|
+
reset_cleanup_methods
|
71
|
+
cleanup_method_registry[method_name.to_sym] = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def cleanup_paths(*dirs)
|
75
|
+
@cleanup_paths = dirs
|
76
|
+
end
|
77
|
+
|
78
|
+
def cleanup(*method_names)
|
79
|
+
if method_names.empty?
|
80
|
+
@cleanup = true
|
81
|
+
else
|
82
|
+
method_names.each do |method_name|
|
83
|
+
define_method_cleanup method_name, @cleanup_paths
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def no_cleanup(*method_names)
|
89
|
+
if method_names.empty?
|
90
|
+
@cleanup = false
|
91
|
+
else
|
92
|
+
method_names.each do |method_name|
|
93
|
+
undef_method_cleanup method_name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def method_added(sym)
|
99
|
+
if @cleanup && !cleanup_method_registry.has_key?(sym.to_sym) && sym.to_s[0, 5] == "test_"
|
100
|
+
cleanup sym
|
101
|
+
end
|
12
102
|
end
|
13
103
|
end
|
14
104
|
|
@@ -16,61 +106,89 @@ module Linecook
|
|
16
106
|
module_function
|
17
107
|
|
18
108
|
def included(base)
|
19
|
-
base.extend
|
109
|
+
base.extend ClassMethods
|
110
|
+
base.extend ModuleMethods unless base.kind_of?(Class)
|
111
|
+
|
112
|
+
ClassMethods.initialize(base)
|
20
113
|
super
|
21
114
|
end
|
22
115
|
end
|
23
|
-
|
116
|
+
|
24
117
|
extend ModuleMethods
|
25
|
-
|
26
|
-
attr_reader :user_dir
|
27
|
-
attr_reader :method_dir
|
28
|
-
|
118
|
+
|
29
119
|
def setup
|
30
120
|
super
|
31
|
-
|
32
|
-
@method_dir = File.expand_path(method_name, self.class.class_dir)
|
33
|
-
|
34
|
-
cleanup method_dir
|
35
|
-
FileUtils.mkdir_p method_dir
|
36
|
-
Dir.chdir method_dir
|
121
|
+
cleanup
|
37
122
|
end
|
38
|
-
|
39
|
-
def teardown
|
40
|
-
Dir.chdir user_dir
|
41
123
|
|
124
|
+
def teardown
|
125
|
+
Dir.chdir(user_dir)
|
126
|
+
|
42
127
|
unless ENV["KEEP_OUTPUTS"] == "true"
|
43
|
-
cleanup
|
128
|
+
cleanup
|
129
|
+
|
130
|
+
dir = method_dir
|
131
|
+
while dir != class_dir
|
132
|
+
dir = File.dirname(dir)
|
133
|
+
Dir.rmdir(dir)
|
134
|
+
end rescue(SystemCallError)
|
44
135
|
end
|
45
|
-
|
136
|
+
|
46
137
|
super
|
47
138
|
end
|
48
|
-
|
49
|
-
def
|
50
|
-
|
139
|
+
|
140
|
+
def user_dir
|
141
|
+
@user_dir ||= File.expand_path('.')
|
51
142
|
end
|
52
|
-
|
143
|
+
|
144
|
+
def class_dir
|
145
|
+
@class_dir ||= File.expand_path(self.class.class_dir, user_dir)
|
146
|
+
end
|
147
|
+
|
148
|
+
def method_dir
|
149
|
+
@method_dir ||= File.expand_path(method_name.to_s, class_dir)
|
150
|
+
end
|
151
|
+
|
152
|
+
def cleanup_methods
|
153
|
+
self.class.cleanup_methods
|
154
|
+
end
|
155
|
+
|
156
|
+
def cleanup
|
157
|
+
if cleanup_paths = cleanup_methods[method_name.to_sym]
|
158
|
+
cleanup_paths.each {|relative_path| remove(relative_path) }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
53
162
|
def path(relative_path)
|
54
|
-
File.expand_path(relative_path, method_dir)
|
163
|
+
path = File.expand_path(relative_path, method_dir)
|
164
|
+
|
165
|
+
unless path.index(method_dir) == 0
|
166
|
+
raise "does not make a path relative to method_dir: #{relative_path.inspect}"
|
167
|
+
end
|
168
|
+
|
169
|
+
path
|
55
170
|
end
|
56
171
|
|
57
|
-
def prepare(relative_path)
|
172
|
+
def prepare(relative_path, content=nil, &block)
|
58
173
|
target = path(relative_path)
|
59
174
|
|
60
|
-
|
61
|
-
|
175
|
+
if File.exists?(target)
|
176
|
+
FileUtils.rm(target)
|
177
|
+
else
|
178
|
+
target_dir = File.dirname(target)
|
179
|
+
FileUtils.mkdir_p(target_dir) unless File.exists?(target_dir)
|
180
|
+
end
|
181
|
+
|
182
|
+
FileUtils.touch(target)
|
183
|
+
File.open(target, 'w') {|io| io << content } if content
|
184
|
+
File.open(target, 'a', &block) if block
|
62
185
|
|
63
186
|
target
|
64
187
|
end
|
65
188
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
target
|
70
|
-
end
|
71
|
-
|
72
|
-
def class_dir
|
73
|
-
self.class.class_dir
|
189
|
+
def remove(relative_path)
|
190
|
+
full_path = path(relative_path)
|
191
|
+
FileUtils.rm_r(full_path) if File.exists?(full_path)
|
74
192
|
end
|
75
193
|
end
|
76
194
|
end
|