linecook 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/{History → History.rdoc} +3 -2
  2. data/README.rdoc +93 -0
  3. data/bin/linecook +32 -56
  4. data/bin/linecook_run +19 -6
  5. data/bin/linecook_scp +12 -4
  6. data/doc/vm_setup.rdoc +75 -0
  7. data/lib/linecook.rb +3 -2
  8. data/lib/linecook/attributes.rb +33 -8
  9. data/lib/linecook/command.rb +61 -0
  10. data/lib/linecook/command_set.rb +85 -0
  11. data/lib/linecook/command_utils.rb +20 -0
  12. data/lib/linecook/commands/build.rb +108 -57
  13. data/lib/linecook/commands/compile.rb +181 -0
  14. data/lib/linecook/commands/{helper.rb → compile_helper.rb} +123 -94
  15. data/lib/linecook/commands/run.rb +43 -39
  16. data/lib/linecook/commands/snapshot.rb +24 -24
  17. data/lib/linecook/commands/ssh.rb +7 -7
  18. data/lib/linecook/commands/start.rb +10 -10
  19. data/lib/linecook/commands/state.rb +7 -7
  20. data/lib/linecook/commands/stop.rb +3 -3
  21. data/lib/linecook/commands/{vbox_command.rb → virtual_box_command.rb} +31 -29
  22. data/lib/linecook/cookbook.rb +149 -131
  23. data/lib/linecook/executable.rb +28 -0
  24. data/lib/linecook/package.rb +177 -361
  25. data/lib/linecook/proxy.rb +4 -10
  26. data/lib/linecook/recipe.rb +289 -369
  27. data/lib/linecook/test.rb +114 -98
  28. data/lib/linecook/utils.rb +31 -41
  29. data/lib/linecook/version.rb +2 -6
  30. metadata +120 -68
  31. data/HowTo/Control Virtual Machines +0 -106
  32. data/HowTo/Generate Scripts +0 -268
  33. data/HowTo/Run Scripts +0 -87
  34. data/HowTo/Setup Virtual Machines +0 -76
  35. data/README +0 -117
  36. data/lib/linecook/commands.rb +0 -11
  37. data/lib/linecook/commands/command.rb +0 -58
  38. data/lib/linecook/commands/command_error.rb +0 -12
  39. data/lib/linecook/commands/env.rb +0 -89
  40. data/lib/linecook/commands/init.rb +0 -86
  41. data/lib/linecook/commands/package.rb +0 -57
  42. data/lib/linecook/template.rb +0 -17
  43. data/lib/linecook/test/command_parser.rb +0 -75
  44. data/lib/linecook/test/file_test.rb +0 -197
  45. data/lib/linecook/test/regexp_escape.rb +0 -86
  46. data/lib/linecook/test/shell_test.rb +0 -177
  47. data/lib/linecook/test/shim.rb +0 -71
  48. data/templates/Gemfile +0 -3
  49. data/templates/Rakefile +0 -146
  50. data/templates/_gitignore +0 -4
  51. data/templates/attributes/project_name.rb +0 -3
  52. data/templates/config/ssh +0 -14
  53. data/templates/cookbook +0 -10
  54. data/templates/files/example.txt +0 -1
  55. data/templates/helpers/project_name/echo.erb +0 -4
  56. data/templates/packages/abox.yml +0 -2
  57. data/templates/project_name.gemspec +0 -30
  58. data/templates/recipes/abox.rb +0 -16
  59. data/templates/templates/example.erb +0 -1
  60. data/templates/test/project_name_test.rb +0 -24
  61. data/templates/test/test_helper.rb +0 -14
@@ -1,57 +0,0 @@
1
- require 'linecook/commands/command'
2
- require 'linecook/cookbook'
3
- require 'linecook/package'
4
- require 'fileutils'
5
- require 'yaml'
6
-
7
- module Linecook
8
- module Commands
9
-
10
- # :startdoc::desc generates a package
11
- #
12
- # Generates the package specified at
13
- # 'project_dir/packages/package_name.yml'. The package file should be a
14
- # YAML files that specifies a package env. The full path to package file
15
- # can be given instead of package name using the --file option.
16
- #
17
- # If a cookbook file is present in the project_dir then it will be used to
18
- # resolve resources available to the package. See the env command to
19
- # interrogate a package env.
20
- class Package < Command
21
- config :project_dir, '.', :short => :d # the project directory
22
- config :force, false, :short => :f, &c.flag # force creation
23
- config :quiet, false, &c.flag # silence output
24
-
25
- def process(package_file, package_dir=nil)
26
- package_dir ||= default_package_dir(package_file)
27
- package_dir = File.expand_path(package_dir)
28
- package = Linecook::Package.init(package_file, project_dir)
29
-
30
- dependencies = package_dependencies(package) + [package_file]
31
- if force || !FileUtils.uptodate?(package_dir, dependencies)
32
- package.build
33
- package.export(package_dir)
34
- $stdout.puts package_dir unless quiet
35
- end
36
-
37
- package_dir
38
- end
39
-
40
- def package_dependencies(package)
41
- dependencies = []
42
- package.manifest.values.collect do |resources|
43
- dependencies.concat resources.values
44
- end
45
-
46
- $LOAD_PATH.each do |path|
47
- dependencies.concat Dir.glob("#{path}/**/*.rb")
48
- end
49
- dependencies
50
- end
51
-
52
- def default_package_dir(package_file)
53
- package_file.chomp(File.extname(package_file))
54
- end
55
- end
56
- end
57
- end
@@ -1,17 +0,0 @@
1
- require 'erb'
2
- require 'ostruct'
3
-
4
- module Linecook
5
- class Template
6
- attr_reader :erb
7
-
8
- def initialize(filename)
9
- @erb = ERB.new File.read(filename)
10
- @erb.filename = filename
11
- end
12
-
13
- def build(locals={})
14
- erb.result OpenStruct.new(locals).instance_eval('binding')
15
- end
16
- end
17
- end
@@ -1,75 +0,0 @@
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
@@ -1,197 +0,0 @@
1
- require 'linecook/test/shim'
2
-
3
- module Linecook
4
- module Test
5
- module FileTest
6
- module ClassMethods
7
- attr_accessor :class_dir
8
-
9
- attr_reader :cleanup_method_registry
10
-
11
- def cleanup_methods
12
- @cleanup_methods ||= begin
13
- cleanup_methods = {}
14
-
15
- ancestors.reverse.each do |ancestor|
16
- next unless ancestor.kind_of?(ClassMethods)
17
- ancestor.cleanup_method_registry.each_pair do |key, value|
18
- if value.nil?
19
- cleanup_methods.delete(key)
20
- else
21
- cleanup_methods[key] = value
22
- end
23
- end
24
- end
25
-
26
- cleanup_methods
27
- end
28
- end
29
-
30
- def reset_cleanup_methods
31
- @cleanup_methods = nil
32
- end
33
-
34
- protected
35
-
36
- def self.initialize(base)
37
- # Infers the test directory from the calling file.
38
- # 'some_class_test.rb' => 'some_class_test'
39
- calling_file = caller[1].gsub(/:\d+(:in .*)?$/, "")
40
- base.class_dir = calling_file.chomp(File.extname(calling_file))
41
-
42
- base.reset_cleanup_methods
43
- unless base.instance_variable_defined?(:@cleanup_method_registry)
44
- base.instance_variable_set(:@cleanup_method_registry, {})
45
- end
46
-
47
- unless base.instance_variable_defined?(:@cleanup_paths)
48
- base.instance_variable_set(:@cleanup_paths, ['.'])
49
- end
50
-
51
- unless base.instance_variable_defined?(:@cleanup)
52
- base.instance_variable_set(:@cleanup, true)
53
- end
54
- end
55
-
56
- def inherited(base) # :nodoc:
57
- ClassMethods.initialize(base)
58
- super
59
- end
60
-
61
- def define_method_cleanup(method_name, dirs)
62
- reset_cleanup_methods
63
- cleanup_method_registry[method_name.to_sym] = dirs
64
- end
65
-
66
- def remove_method_cleanup(method_name)
67
- reset_cleanup_methods
68
- cleanup_method_registry.delete(method_name.to_sym)
69
- end
70
-
71
- def undef_method_cleanup(method_name)
72
- reset_cleanup_methods
73
- cleanup_method_registry[method_name.to_sym] = nil
74
- end
75
-
76
- def cleanup_paths(*dirs)
77
- @cleanup_paths = dirs
78
- end
79
-
80
- def cleanup(*method_names)
81
- if method_names.empty?
82
- @cleanup = true
83
- else
84
- method_names.each do |method_name|
85
- define_method_cleanup method_name, @cleanup_paths
86
- end
87
- end
88
- end
89
-
90
- def no_cleanup(*method_names)
91
- if method_names.empty?
92
- @cleanup = false
93
- else
94
- method_names.each do |method_name|
95
- undef_method_cleanup method_name
96
- end
97
- end
98
- end
99
-
100
- def method_added(sym)
101
- if @cleanup && !cleanup_method_registry.has_key?(sym.to_sym) && sym.to_s[0, 5] == "test_"
102
- cleanup sym
103
- end
104
- end
105
- end
106
-
107
- module ModuleMethods
108
- module_function
109
-
110
- def included(base)
111
- base.extend ClassMethods
112
- base.extend ModuleMethods unless base.kind_of?(Class)
113
-
114
- ClassMethods.initialize(base)
115
- super
116
- end
117
- end
118
-
119
- extend ModuleMethods
120
-
121
- def setup
122
- super
123
- cleanup
124
- end
125
-
126
- def teardown
127
- Dir.chdir(user_dir)
128
-
129
- unless ENV["KEEP_OUTPUTS"] == "true"
130
- cleanup
131
-
132
- dir = method_dir
133
- while dir != class_dir
134
- dir = File.dirname(dir)
135
- Dir.rmdir(dir)
136
- end rescue(SystemCallError)
137
- end
138
-
139
- super
140
- end
141
-
142
- def user_dir
143
- @user_dir ||= File.expand_path('.')
144
- end
145
-
146
- def class_dir
147
- @class_dir ||= File.expand_path(self.class.class_dir, user_dir)
148
- end
149
-
150
- def method_dir
151
- @method_dir ||= File.expand_path(method_name.to_s, class_dir)
152
- end
153
-
154
- def cleanup_methods
155
- self.class.cleanup_methods
156
- end
157
-
158
- def cleanup
159
- if cleanup_paths = cleanup_methods[method_name.to_sym]
160
- cleanup_paths.each {|relative_path| remove(relative_path) }
161
- end
162
- end
163
-
164
- def path(relative_path)
165
- path = File.expand_path(relative_path, method_dir)
166
-
167
- unless path.index(method_dir) == 0
168
- raise "does not make a path relative to method_dir: #{relative_path.inspect}"
169
- end
170
-
171
- path
172
- end
173
-
174
- def prepare(relative_path, content=nil, &block)
175
- target = path(relative_path)
176
-
177
- if File.exists?(target)
178
- FileUtils.rm(target)
179
- else
180
- target_dir = File.dirname(target)
181
- FileUtils.mkdir_p(target_dir) unless File.exists?(target_dir)
182
- end
183
-
184
- FileUtils.touch(target)
185
- File.open(target, 'w') {|io| io << content } if content
186
- File.open(target, 'a', &block) if block
187
-
188
- target
189
- end
190
-
191
- def remove(relative_path)
192
- full_path = path(relative_path)
193
- FileUtils.rm_r(full_path) if File.exists?(full_path)
194
- end
195
- end
196
- end
197
- end
@@ -1,86 +0,0 @@
1
- module Linecook
2
- module Test
3
- # RegexpEscape is a subclass of regexp that escapes all but the text in a
4
- # special escape sequence. This allows the creation of complex regexps
5
- # to match, for instance, console output.
6
- #
7
- # The RegexpEscape.escape (or equivalently the quote) method does the
8
- # work; all regexp-active characters are escaped except for characters
9
- # enclosed by ':.' and '.:' delimiters.
10
- #
11
- # RegexpEscape.escape('reg[exp]+ chars. are(quoted)') # => 'reg\[exp\]\+\ chars\.\ are\(quoted\)'
12
- # RegexpEscape.escape('these are not: :.a(b*)c.:') # => 'these\ are\ not:\ a(b*)c'
13
- #
14
- # In addition, all-period regexps are automatically upgraded to '.*?';
15
- # use the '.{n}' notation to specify n arbitrary characters.
16
- #
17
- # RegexpEscape.escape('_:..:_:...:_:....:') # => '_.*?_.*?_.*?'
18
- # RegexpEscape.escape(':..{1}.:') # => '.{1}'
19
- #
20
- # RegexpEscape instances are initialized using the escaped input string
21
- # and return the original string upon to_s.
22
- #
23
- # str = %q{
24
- # a multiline
25
- # :...:
26
- # example}
27
- # r = RegexpEscape.new(str)
28
- #
29
- # r =~ %q{
30
- # a multiline
31
- # matching
32
- # example} # => true
33
- #
34
- # r !~ %q{
35
- # a failing multiline
36
- # example} # => true
37
- #
38
- # r.to_s # => str
39
- #
40
- class RegexpEscape < Regexp
41
-
42
- # matches the escape sequence
43
- ESCAPE_SEQUENCE = /:\..*?\.:/
44
-
45
- class << self
46
-
47
- # Escapes regexp-active characters in str, except for character
48
- # delimited by ':.' and '.:'. See the class description for
49
- # details.
50
- def escape(str)
51
- substituents = []
52
- str.scan(ESCAPE_SEQUENCE) do
53
- regexp_str = $&[2...-2]
54
- regexp_str = ".*?" if regexp_str =~ /^\.*$/
55
- substituents << regexp_str
56
- end
57
- substituents << ""
58
-
59
- splits = str.split(ESCAPE_SEQUENCE).collect do |split|
60
- super(split)
61
- end
62
- splits << "" if splits.empty?
63
-
64
- splits.zip(substituents).to_a.flatten.join
65
- end
66
-
67
- # Same as escape.
68
- def quote(str)
69
- escape(str)
70
- end
71
- end
72
-
73
- # Generates a new RegexpEscape by escaping the str, using the same
74
- # options as Regexp.
75
- def initialize(str, *options)
76
- super(RegexpEscape.escape(str), *options)
77
- @original_str = str
78
- end
79
-
80
- # Returns the original string for self
81
- def to_s
82
- @original_str
83
- end
84
- end
85
- end
86
- end
@@ -1,177 +0,0 @@
1
- require 'linecook/test/regexp_escape'
2
- require 'linecook/test/command_parser'
3
- require 'linecook/test/shim'
4
-
5
- module Linecook
6
- module Test
7
- module ShellTest
8
-
9
- def setup
10
- super
11
- @notify_method_name = true
12
- end
13
-
14
- # Returns true if the ENV variable 'VERBOSE' is true. When verbose,
15
- # ShellTest prints the expanded commands of sh_test to $stdout.
16
- def verbose?
17
- verbose = ENV['VERBOSE']
18
- verbose && verbose =~ /^true$/i ? true : false
19
- end
20
-
21
- # Sets the specified ENV variables and returns the *current* env.
22
- # If replace is true, current ENV variables are replaced; otherwise
23
- # the new env variables are simply added to the existing set.
24
- def set_env(env={}, replace=false)
25
- current_env = {}
26
- ENV.each_pair do |key, value|
27
- current_env[key] = value
28
- end
29
-
30
- ENV.clear if replace
31
-
32
- env.each_pair do |key, value|
33
- if value.nil?
34
- ENV.delete(key)
35
- else
36
- ENV[key] = value
37
- end
38
- end if env
39
-
40
- current_env
41
- end
42
-
43
- # Sets the specified ENV variables for the duration of the block.
44
- # If replace is true, current ENV variables are replaced; otherwise
45
- # the new env variables are simply added to the existing set.
46
- #
47
- # Returns the block return.
48
- def with_env(env={}, replace=false)
49
- current_env = nil
50
- begin
51
- current_env = set_env(env, replace)
52
- yield
53
- ensure
54
- if current_env
55
- set_env(current_env, true)
56
- end
57
- end
58
- end
59
-
60
- def sh(cmd)
61
- if @notify_method_name && verbose?
62
- @notify_method_name = false
63
- puts
64
- puts method_name
65
- end
66
-
67
- start = Time.now
68
- result = `#{cmd}`
69
- finish = Time.now
70
-
71
- if verbose?
72
- elapsed = "%.3f" % [finish-start]
73
- puts " (#{elapsed}s) #{cmd}"
74
- end
75
-
76
- result
77
- end
78
-
79
- def assert_script(script, options={})
80
- _assert_script outdent(script), options
81
- end
82
-
83
- def _assert_script(script, options={})
84
- commands = CommandParser.new(options).parse(script)
85
- commands.each do |cmd, output, status|
86
- result = sh(cmd)
87
-
88
- _assert_output_equal(output, result, cmd) if output
89
- assert_equal(status, $?.exitstatus, cmd) if status
90
- end
91
- end
92
-
93
- def assert_script_match(script, options={})
94
- _assert_script_match outdent(script), options
95
- end
96
-
97
- def _assert_script_match(script, options={})
98
- commands = CommandParser.new(options).parse(script)
99
- commands.each do |cmd, output, status|
100
- result = sh(cmd)
101
-
102
- _assert_alike(output, result, cmd) if output
103
- assert_equal(status, $?.exitstatus, cmd) if status
104
- end
105
- end
106
-
107
- # Asserts whether or not the a and b strings are equal, with a more
108
- # readable output than assert_equal for large strings (especially large
109
- # strings with significant whitespace).
110
- def assert_output_equal(a, b, msg=nil)
111
- _assert_output_equal outdent(a), b, msg
112
- end
113
-
114
- def _assert_output_equal(a, b, msg=nil)
115
- if a == b
116
- assert true
117
- else
118
- flunk %Q{
119
- #{msg}
120
- ==================== expected output ====================
121
- #{whitespace_escape(a)}
122
- ======================== but was ========================
123
- #{whitespace_escape(b)}
124
- =========================================================
125
- }
126
- end
127
- end
128
-
129
- # Asserts whether or not b is like a (which should be a Regexp), and
130
- # provides a more readable output in the case of a failure as compared
131
- # with assert_match.
132
- #
133
- # If a is a string it is turned into a RegexpEscape.
134
- def assert_alike(a, b, msg=nil)
135
- a = outdent(a) if a.kind_of?(String)
136
- _assert_alike a, b, msg
137
- end
138
-
139
- def _assert_alike(a, b, msg=nil)
140
- if a.kind_of?(String)
141
- a = RegexpEscape.new(a)
142
- end
143
-
144
- if b =~ a
145
- assert true
146
- else
147
- flunk %Q{
148
- #{msg}
149
- ================= expected output like ==================
150
- #{whitespace_escape(a)}
151
- ======================== but was ========================
152
- #{whitespace_escape(b)}
153
- =========================================================
154
- }
155
- end
156
- end
157
-
158
- # helper for stripping indentation off a string
159
- def outdent(str)
160
- str =~ /\A(?:\s*?\n)( *)(.*)\z/m ? $2.gsub!(/^ {0,#{$1.length}}/, '') : str
161
- end
162
-
163
- # helper for formatting escaping whitespace into readable text
164
- def whitespace_escape(str)
165
- str.to_s.gsub(/\s/) do |match|
166
- case match
167
- when "\n" then "\\n\n"
168
- when "\t" then "\\t"
169
- when "\r" then "\\r"
170
- when "\f" then "\\f"
171
- else match
172
- end
173
- end
174
- end
175
- end
176
- end
177
- end