linecook 1.2.1 → 2.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.
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