linecook 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History +60 -0
- data/License.txt +22 -0
- data/README +98 -0
- data/bin/linecook +58 -0
- data/cookbook +0 -0
- data/lib/linecook/attributes.rb +22 -0
- data/lib/linecook/commands/command.rb +48 -0
- data/lib/linecook/commands/command_error.rb +6 -0
- data/lib/linecook/commands/env.rb +23 -0
- data/lib/linecook/commands/helper.rb +51 -0
- data/lib/linecook/commands/helpers.rb +28 -0
- data/lib/linecook/commands/init.rb +82 -0
- data/lib/linecook/commands/package.rb +39 -0
- data/lib/linecook/commands/vbox.rb +85 -0
- data/lib/linecook/commands.rb +6 -0
- data/lib/linecook/cookbook.rb +104 -0
- data/lib/linecook/helper.rb +117 -0
- data/lib/linecook/package.rb +197 -0
- data/lib/linecook/recipe.rb +103 -0
- data/lib/linecook/shell/posix.rb +145 -0
- data/lib/linecook/shell/test.rb +254 -0
- data/lib/linecook/shell/unix.rb +117 -0
- data/lib/linecook/shell/utils.rb +138 -0
- data/lib/linecook/shell.rb +11 -0
- data/lib/linecook/template.rb +111 -0
- data/lib/linecook/test/file_test.rb +77 -0
- data/lib/linecook/test/regexp_escape.rb +86 -0
- data/lib/linecook/test.rb +172 -0
- data/lib/linecook/utils.rb +53 -0
- data/lib/linecook/version.rb +8 -0
- data/lib/linecook.rb +6 -0
- data/templates/Gemfile +2 -0
- data/templates/README +90 -0
- data/templates/Rakefile +149 -0
- data/templates/_gitignore +5 -0
- data/templates/attributes/project_name.rb +4 -0
- data/templates/cookbook +9 -0
- data/templates/files/file.txt +1 -0
- data/templates/helpers/project_name/echo.erb +5 -0
- data/templates/project_name.gemspec +30 -0
- data/templates/recipes/project_name.rb +20 -0
- data/templates/scripts/project_name.yml +7 -0
- data/templates/templates/template.txt.erb +3 -0
- data/templates/vbox/setup/virtual_box +86 -0
- data/templates/vbox/ssh/id_rsa +27 -0
- data/templates/vbox/ssh/id_rsa.pub +1 -0
- metadata +166 -0
@@ -0,0 +1,86 @@
|
|
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
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'linecook/cookbook'
|
2
|
+
require 'linecook/recipe'
|
3
|
+
require 'linecook/test/file_test'
|
4
|
+
require 'linecook/test/regexp_escape'
|
5
|
+
require 'linecook/utils'
|
6
|
+
|
7
|
+
module Linecook
|
8
|
+
module Test
|
9
|
+
include FileTest
|
10
|
+
|
11
|
+
attr_writer :cookbook
|
12
|
+
attr_writer :script
|
13
|
+
attr_writer :recipe
|
14
|
+
|
15
|
+
def cookbook
|
16
|
+
@cookbook ||= Cookbook.init(user_dir)
|
17
|
+
end
|
18
|
+
|
19
|
+
def manifest
|
20
|
+
cookbook.manifest
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_env
|
24
|
+
{Package::CONFIG_KEY => {Package::MANIFEST_KEY => manifest}}
|
25
|
+
end
|
26
|
+
|
27
|
+
def recipe
|
28
|
+
@recipe ||= Recipe.new('recipe', default_env)
|
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)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Same as assert_output_equal but without indentation stripping.
|
65
|
+
def assert_output_equal!(a, b, msg=nil)
|
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
|
78
|
+
end
|
79
|
+
|
80
|
+
# Asserts whether or not b is like a (which should be a Regexp), and
|
81
|
+
# provides a more readable output in the case of a failure as compared
|
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)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Same as assert_alike but without indentation stripping.
|
110
|
+
def assert_alike!(a, b, msg=nil)
|
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
|
125
|
+
end
|
126
|
+
|
127
|
+
def assert_recipe(expected, &block)
|
128
|
+
recipe.instance_eval(&block)
|
129
|
+
assert_output_equal expected, recipe.result
|
130
|
+
end
|
131
|
+
|
132
|
+
def assert_recipe_match(expected, &block)
|
133
|
+
recipe.instance_eval(&block)
|
134
|
+
assert_alike expected, recipe.result
|
135
|
+
end
|
136
|
+
|
137
|
+
def assert_content(expected, build_path)
|
138
|
+
registry = recipe.close
|
139
|
+
|
140
|
+
assert_equal true, registry.has_key?(build_path), "not in registry: #{build_path}"
|
141
|
+
assert_output_equal expected, File.read(registry[build_path]), build_path
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# helper for stripping indentation off a string
|
147
|
+
def strip_indent(str) # :nodoc:
|
148
|
+
if str =~ /\A\s*?\n( *)(.*)\z/m
|
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
|
157
|
+
end
|
158
|
+
|
159
|
+
# helper for formatting escaping whitespace into readable text
|
160
|
+
def whitespace_escape(str) # :nodoc:
|
161
|
+
str.to_s.gsub(/\s/) do |match|
|
162
|
+
case match
|
163
|
+
when "\n" then "\\n\n"
|
164
|
+
when "\t" then "\\t"
|
165
|
+
when "\r" then "\\r"
|
166
|
+
when "\f" then "\\f"
|
167
|
+
else match
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Linecook
|
2
|
+
module Utils
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def nest_hash
|
6
|
+
Hash.new {|hash, key| hash[key] = nest_hash }
|
7
|
+
end
|
8
|
+
|
9
|
+
def serial_merge(*hashes)
|
10
|
+
attrs = {}
|
11
|
+
while overrides = hashes.shift
|
12
|
+
attrs = deep_merge(attrs, overrides)
|
13
|
+
end
|
14
|
+
attrs
|
15
|
+
end
|
16
|
+
|
17
|
+
def deep_merge(a, b)
|
18
|
+
b.each_pair do |key, current|
|
19
|
+
previous = a[key]
|
20
|
+
a[key] = deep_merge?(previous, current) ? deep_merge(previous, current) : current
|
21
|
+
end
|
22
|
+
|
23
|
+
a
|
24
|
+
end
|
25
|
+
|
26
|
+
def deep_merge?(previous, current)
|
27
|
+
current.kind_of?(Hash) && previous.kind_of?(Hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
def camelize(str)
|
31
|
+
str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
32
|
+
end
|
33
|
+
|
34
|
+
def underscore(str)
|
35
|
+
str.gsub(/::/, '/').
|
36
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
37
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
38
|
+
tr("-", "_").
|
39
|
+
downcase
|
40
|
+
end
|
41
|
+
|
42
|
+
def constantize(const_name)
|
43
|
+
constants = camelize(const_name).split(/::/)
|
44
|
+
|
45
|
+
const = Object
|
46
|
+
while name = constants.shift
|
47
|
+
const = const.const_get(name)
|
48
|
+
end
|
49
|
+
|
50
|
+
const
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/linecook.rb
ADDED
data/templates/Gemfile
ADDED
data/templates/README
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
= README
|
2
|
+
|
3
|
+
Linecook provides support to develop scripts using VirtualBox, an open-source
|
4
|
+
product to setup and manage virtual machines. Nothing says you have to use
|
5
|
+
VirtualBox during development and obviously you can take the shell scripts
|
6
|
+
produced by Linecook and run them wherever.
|
7
|
+
|
8
|
+
These are instructions for setting up a generic Ubuntu VM for development.
|
9
|
+
|
10
|
+
1. Download and Install VirtualBox (http://www.virtualbox.org)
|
11
|
+
2. Download a Ubuntu ISO (http://www.ubuntu.com/server/get-ubuntu/download)
|
12
|
+
3. Build the Box
|
13
|
+
|
14
|
+
Use the VirtualBox wizard to get started.
|
15
|
+
|
16
|
+
- name: vbox
|
17
|
+
- Linux/Ubuntu
|
18
|
+
- 512 MB memory
|
19
|
+
- 8 GB dynamically resizing drive
|
20
|
+
|
21
|
+
Under Settings:
|
22
|
+
|
23
|
+
- add the ubuntu iso to the cd/dvd device (under storage)
|
24
|
+
- disable audio
|
25
|
+
- network set to NAT
|
26
|
+
- disable usb (only the inner box would stay unchecked)
|
27
|
+
- shared folder: map the 'vbox' directory in project root
|
28
|
+
|
29
|
+
Start the server and install (default unless specified):
|
30
|
+
|
31
|
+
- hostname: vbox-ubuntu
|
32
|
+
- user/password: vbox
|
33
|
+
- no packages
|
34
|
+
- power off, remove ubuntu iso from the cd/dvd device
|
35
|
+
|
36
|
+
Setup Permissions (allows vbox to run sudo without password):
|
37
|
+
|
38
|
+
vm: sudo visudo
|
39
|
+
|
40
|
+
# insert line:
|
41
|
+
#
|
42
|
+
# %vbox ALL=NOPASSWD: ALL
|
43
|
+
#
|
44
|
+
# then exit (write out changes as prompted)
|
45
|
+
|
46
|
+
Setup guest additions (note they are in the application package on
|
47
|
+
osx http://forums.virtualbox.org/viewtopic.php?f=8&t=10286) See also:
|
48
|
+
http://forums.virtualbox.org/viewtopic.php?t=15868.
|
49
|
+
|
50
|
+
(cd/dvd device): add the VBoxGuestAdditions.iso
|
51
|
+
vm: sudo apt-get install linux-headers-$(uname -r) build-essential ssh openssh-server
|
52
|
+
vm: sudo mkdir /media/dvd
|
53
|
+
vm: sudo mount /dev/dvd /media/dvd/
|
54
|
+
vm: sudo sh /media/dvd/VBoxLinuxAdditions-x86.run
|
55
|
+
# there may be a warning about 'Window System drivers fail', ignore
|
56
|
+
|
57
|
+
Add an init script to mount the share on boot:
|
58
|
+
|
59
|
+
vm: sudo mkdir /vbox
|
60
|
+
vm: sudo mount -t vboxsf -o uid=1000,gid=100 vbox /vbox
|
61
|
+
vm: sudo cp /vbox/setup/virtual_box /etc/init.d
|
62
|
+
vm: sudo chmod 0755 /etc/init.d/virtual_box
|
63
|
+
vm: sudo update-rc.d virtual_box defaults 80
|
64
|
+
|
65
|
+
Setup SSH:
|
66
|
+
|
67
|
+
vm: mkdir ~/.ssh
|
68
|
+
vm: chmod 0700 ~/.ssh
|
69
|
+
vm: cat /vbox/ssh/id_rsa.pub >> ~/.ssh/authorized_keys
|
70
|
+
vm: chmod 0600 ~/.ssh/authorized_keys
|
71
|
+
|
72
|
+
Now take a snapshot and setup port forwarding:
|
73
|
+
|
74
|
+
vm: exit
|
75
|
+
ht: VBoxManage snapshot vbox take BASE
|
76
|
+
ht: VBoxManage controlvm vbox poweroff
|
77
|
+
ht: VBoxManage modifyvm vbox --natpf1 'guestssh,tcp,,2222,,22'
|
78
|
+
ht: VBoxManage modifyvm vbox --natpf1 'http,tcp,,8888,,80'
|
79
|
+
ht: VBoxManage -q snapshot vbox restore BASE
|
80
|
+
ht: VBoxManage startvm vbox --type headless
|
81
|
+
|
82
|
+
You can now ssh to the box (from the project dir):
|
83
|
+
|
84
|
+
ht: chmod 0600 vbox/ssh/id_rsa
|
85
|
+
ht: ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i vbox/ssh/id_rsa vbox@localhost
|
86
|
+
|
87
|
+
To cleanup the port forwarding (run later):
|
88
|
+
|
89
|
+
ht: VBoxManage modifyvm vbox --natpf1 delete 'guestssh'
|
90
|
+
ht: VBoxManage modifyvm vbox --natpf1 delete 'http'
|
data/templates/Rakefile
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Gem tasks
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/gempackagetask'
|
9
|
+
|
10
|
+
def gemspec
|
11
|
+
@gemspec ||= eval(File.read('<%= project_name %>.gemspec'), TOPLEVEL_BINDING)
|
12
|
+
end
|
13
|
+
|
14
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
15
|
+
pkg.need_tar = true
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Prints the gemspec manifest.'
|
19
|
+
task :print_manifest do
|
20
|
+
files = gemspec.files.inject({}) do |files, file|
|
21
|
+
files[File.expand_path(file)] = [File.exists?(file), file]
|
22
|
+
files
|
23
|
+
end
|
24
|
+
|
25
|
+
cookbook_files = Dir.glob('{attributes,files,lib,recipes,templates}/**/*')
|
26
|
+
cookbook_file = Dir.glob('*')
|
27
|
+
|
28
|
+
(cookbook_files + cookbook_file).each do |file|
|
29
|
+
next unless File.file?(file)
|
30
|
+
path = File.expand_path(file)
|
31
|
+
files[path] = ['', file] unless files.has_key?(path)
|
32
|
+
end
|
33
|
+
|
34
|
+
# sort and output the results
|
35
|
+
files.values.sort_by {|exists, file| file }.each do |entry|
|
36
|
+
puts '%-5s %s' % entry
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Documentation tasks
|
42
|
+
#
|
43
|
+
|
44
|
+
desc 'Generate documentation.'
|
45
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
46
|
+
spec = gemspec
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.options.concat(spec.rdoc_options)
|
50
|
+
rdoc.rdoc_files.include(spec.extra_rdoc_files)
|
51
|
+
|
52
|
+
files = spec.files.select {|file| file =~ /^lib.*\.rb$/}
|
53
|
+
rdoc.rdoc_files.include( files )
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Dependency tasks
|
58
|
+
#
|
59
|
+
|
60
|
+
desc 'Bundle dependencies'
|
61
|
+
task :bundle do
|
62
|
+
output = `bundle check 2>&1`
|
63
|
+
|
64
|
+
unless $?.to_i == 0
|
65
|
+
puts output
|
66
|
+
sh "bundle install 2>&1"
|
67
|
+
puts
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Linecook Helpers
|
73
|
+
#
|
74
|
+
|
75
|
+
lib_dir = File.expand_path("../lib", __FILE__)
|
76
|
+
helpers_dir = File.expand_path("../helpers", __FILE__)
|
77
|
+
|
78
|
+
sources = {}
|
79
|
+
helpers = []
|
80
|
+
|
81
|
+
Dir.glob("#{helpers_dir}/**/*").each do |source|
|
82
|
+
next if File.directory?(source)
|
83
|
+
(sources[File.dirname(source)] ||= []) << source
|
84
|
+
end
|
85
|
+
|
86
|
+
sources.each_pair do |dir, sources|
|
87
|
+
name = dir[(helpers_dir.length + 1)..-1]
|
88
|
+
target = File.join(lib_dir, 'linebook', "#{name}.rb")
|
89
|
+
|
90
|
+
file target => sources + [dir] do
|
91
|
+
system "bundle exec linecook helper '#{name}' --force"
|
92
|
+
end
|
93
|
+
|
94
|
+
helpers << target
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "generate helpers"
|
98
|
+
task :helpers => helpers + [:bundle]
|
99
|
+
|
100
|
+
#
|
101
|
+
# Linecook Scripts
|
102
|
+
#
|
103
|
+
|
104
|
+
scripts = Dir.glob("scripts/*.yml")
|
105
|
+
dependencies = Dir.glob('{attributes,files,recipes,templates}/**/*')
|
106
|
+
|
107
|
+
scripts.each do |source|
|
108
|
+
target = source.chomp('.yml')
|
109
|
+
name = File.basename(target)
|
110
|
+
|
111
|
+
namespace :scripts do
|
112
|
+
file target => dependencies + [source] + helpers do
|
113
|
+
sh "bundle exec linecook package '#{source}' '#{target}' --force"
|
114
|
+
end
|
115
|
+
|
116
|
+
desc "generate the script: #{name}"
|
117
|
+
task name => target
|
118
|
+
end
|
119
|
+
|
120
|
+
task :scripts => target
|
121
|
+
end
|
122
|
+
|
123
|
+
desc "generate scripts"
|
124
|
+
task :scripts
|
125
|
+
|
126
|
+
#
|
127
|
+
# Test tasks
|
128
|
+
#
|
129
|
+
|
130
|
+
desc 'Default: Run tests.'
|
131
|
+
task :default => :test
|
132
|
+
|
133
|
+
desc 'Run the tests'
|
134
|
+
task :test => :helpers do
|
135
|
+
tests = Dir.glob('test/**/*_test.rb')
|
136
|
+
|
137
|
+
if ENV['RCOV'] == 'true'
|
138
|
+
FileUtils.rm_rf File.expand_path('../coverage', __FILE__)
|
139
|
+
sh('rcov', '-w', '--text-report', '--exclude', '^/', *tests)
|
140
|
+
else
|
141
|
+
sh('ruby', '-w', '-e', 'ARGV.dup.each {|test| load test}', *tests)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
desc 'Run rcov'
|
146
|
+
task :rcov do
|
147
|
+
ENV['RCOV'] = 'true'
|
148
|
+
Rake::Task["test"].invoke
|
149
|
+
end
|
data/templates/cookbook
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Configure the cookbook here.
|
2
|
+
# Adding this file to a gem marks it as a cookbook gem
|
3
|
+
# (note that in a gem the contents of this file are ignored)
|
4
|
+
|
5
|
+
# Define directories searched for attributes/recipes/etc.
|
6
|
+
# paths: ['.']
|
7
|
+
|
8
|
+
# Name the gems added to path - defaults to all marked gems.
|
9
|
+
# gems: []
|
@@ -0,0 +1 @@
|
|
1
|
+
Contents of an example file.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "<%= project_name %>"
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.authors = "TODO: Write your name"
|
8
|
+
s.email = "TODO: Write your email address"
|
9
|
+
s.homepage = ""
|
10
|
+
s.summary = %q{TODO: Write a gem summary}
|
11
|
+
s.description = %q{TODO: Write a gem description}
|
12
|
+
s.rubyforge_project = ''
|
13
|
+
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.rdoc_options.concat %W{--main README -S -N --title <%= project_name.capitalize %>}
|
16
|
+
|
17
|
+
# add dependencies
|
18
|
+
s.add_dependency('linecook', '~> <%= Linecook::VERSION %>')
|
19
|
+
|
20
|
+
# list extra rdoc files here.
|
21
|
+
s.extra_rdoc_files = %W{
|
22
|
+
cookbook
|
23
|
+
}
|
24
|
+
|
25
|
+
# list the files you want to include here.
|
26
|
+
s.files = %W{
|
27
|
+
}
|
28
|
+
|
29
|
+
s.require_path = 'lib'
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#############################################################################
|
2
|
+
helpers 'linecook/shell'
|
3
|
+
helpers 'linebook/<%= project_name %>'
|
4
|
+
attributes '<%= project_name %>'
|
5
|
+
#############################################################################
|
6
|
+
|
7
|
+
shebang '/bin/bash'
|
8
|
+
|
9
|
+
# Write to the script target using 'script'
|
10
|
+
target.puts '# An example script.'
|
11
|
+
|
12
|
+
# Helpers are now available, as are attributes.
|
13
|
+
echo *attrs['<%= project_name %>']['letters']
|
14
|
+
echo *attrs['<%= project_name %>']['numbers']
|
15
|
+
|
16
|
+
# Use files like this:
|
17
|
+
cat file_path('file.txt')
|
18
|
+
|
19
|
+
# Use templates like this:
|
20
|
+
cat template_path('template.txt', :n => 10)
|