wizard 0.0.1
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/.gitignore +22 -0
- data/CHANGELOG.md +5 -0
- data/README.md +0 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/lib/wizard.rb +12 -0
- data/lib/wizard/formula.rb +23 -0
- data/lib/wizard/helpers.rb +63 -0
- data/lib/wizard/spells.rb +12 -0
- data/lib/wizard/spells/base.rb +84 -0
- data/lib/wizard/spells/compile_template.rb +27 -0
- data/lib/wizard/spells/execute_shell.rb +22 -0
- data/lib/wizard/spells/make_dir.rb +47 -0
- data/lib/wizard/spells/make_file.rb +69 -0
- data/lib/wizard/spells/update_file.rb +95 -0
- data/spec/helpers_spec.rb +55 -0
- data/spec/spec_helper.rb +71 -0
- data/spec/spells/compile_template_spec.rb +60 -0
- data/spec/spells/execute_shell_spec.rb +58 -0
- data/spec/spells/make_dir_spec.rb +77 -0
- data/spec/spells/make_file_spec.rb +125 -0
- data/spec/spells/update_file_spec.rb +209 -0
- data/spec/spells_spec.rb +142 -0
- metadata +125 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'wizard/spells/make_file'
|
2
|
+
|
3
|
+
module Wizard
|
4
|
+
class Formula
|
5
|
+
|
6
|
+
colorizers.merge!(
|
7
|
+
:missing => :red
|
8
|
+
)
|
9
|
+
|
10
|
+
def update_file(filename, content=nil, options={})
|
11
|
+
spell = Spells::UpdateFile.new(filename, content, options)
|
12
|
+
spell.perform
|
13
|
+
render(spell)
|
14
|
+
end
|
15
|
+
alias_method :update, :update_file
|
16
|
+
|
17
|
+
def append_to_file(filename, content, options={})
|
18
|
+
update_file(filename, content, options.merge(:before => :EOF))
|
19
|
+
end
|
20
|
+
alias_method :append, :append_to_file
|
21
|
+
alias_method :append_to, :append_to_file
|
22
|
+
|
23
|
+
def prepend_to_file(filename, content, options={})
|
24
|
+
update_file(filename, content, options.merge(:after => :BOF))
|
25
|
+
end
|
26
|
+
alias_method :prepend, :prepend_to_file
|
27
|
+
alias_method :prepend_to, :prepend_to_file
|
28
|
+
|
29
|
+
def replace_in_file(filename, content, replace, options={})
|
30
|
+
update_file(filename, content, options.merge(:replace => replace))
|
31
|
+
end
|
32
|
+
alias_method :replace, :replace_in_file
|
33
|
+
alias_method :replace_content, :replace_in_file
|
34
|
+
|
35
|
+
end # Formula
|
36
|
+
|
37
|
+
module Spells
|
38
|
+
class UpdateFile < MakeFile
|
39
|
+
|
40
|
+
attr_reader :filename, :chmod, :content, :before, :after, :replace
|
41
|
+
attr_status :missing
|
42
|
+
|
43
|
+
def initialize(filename, content=nil, options={})
|
44
|
+
super(filename, nil, options)
|
45
|
+
|
46
|
+
@content = content
|
47
|
+
@before = options[:before]
|
48
|
+
@after = options[:after]
|
49
|
+
@replace = options[:replace]
|
50
|
+
end
|
51
|
+
|
52
|
+
def perform_with_content_update
|
53
|
+
if File.exist?(filename)
|
54
|
+
force! and rebuild_content and perform_without_content_update
|
55
|
+
elsif content && !before && !after && !replace
|
56
|
+
perform_without_content_update
|
57
|
+
else
|
58
|
+
missing!
|
59
|
+
end
|
60
|
+
rescue Object
|
61
|
+
error!
|
62
|
+
end
|
63
|
+
|
64
|
+
alias_method :perform_without_content_update, :perform
|
65
|
+
alias_method :perform, :perform_with_content_update
|
66
|
+
|
67
|
+
# Build new content based on original one, including specified update
|
68
|
+
# directives. All directives can't be mixed, which mean that only
|
69
|
+
# one update can ba applied on the file at one time. If none directive
|
70
|
+
# is specified, then whole file content will be replaced with specified
|
71
|
+
# in constructor.
|
72
|
+
def rebuild_content
|
73
|
+
if (before || after) && !replace
|
74
|
+
content = File.read(filename)
|
75
|
+
|
76
|
+
return @content = [@content, content].join("\n") if after == :BOF
|
77
|
+
return @content = [content, @content].join("\n") if before == :EOF
|
78
|
+
|
79
|
+
content = content.sub(/\r\n/, "\n").sub(/\r/, "\n").split(/\n/)
|
80
|
+
content.each_with_index do |line, id|
|
81
|
+
content[id] = [@content, line].join("\n") if !after && before && line =~ before
|
82
|
+
content[id] = [line, @content].join("\n") if !before && after && line =~ after
|
83
|
+
end
|
84
|
+
|
85
|
+
@content = content.join("\n")
|
86
|
+
elsif replace
|
87
|
+
@content = File.read(filename).sub(replace, @content)
|
88
|
+
else
|
89
|
+
@content
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end # UpdateFile
|
94
|
+
end # Spells
|
95
|
+
end # Wizard
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Wizard::Helpers do
|
4
|
+
subject do
|
5
|
+
Wizard
|
6
|
+
end
|
7
|
+
|
8
|
+
context "#say!" do
|
9
|
+
Wizard::Helpers::COLORS.each do |color, code|
|
10
|
+
[false, true].each do |bold|
|
11
|
+
it "should properly display #{bold ? "bold and" : ""}#{color.to_s} text on screen" do
|
12
|
+
capture { Wizard.say!(color.to_s, color, bold) }
|
13
|
+
last_stdout.should == "\e[#{bold ? 1 : 0};#{code}m#{color.to_s}\n\e[0m"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#print" do
|
20
|
+
it "should properly print given text to stdout" do
|
21
|
+
capture { subject.print "This is SPARTA!" }
|
22
|
+
last_stdout.should == "This is SPARTA!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#colorize" do
|
27
|
+
it "should colorize given text" do
|
28
|
+
subject.colorize("foo", :red).should == "\e[0;31mfoo\e[0m"
|
29
|
+
subject.colorize("bar", :red, true).should == "\e[1;31mbar\e[0m"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#console_width" do
|
34
|
+
it "should return actual console width" do
|
35
|
+
# tested manualy...
|
36
|
+
subject.console_width
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#adjust" do
|
41
|
+
context "when size given" do
|
42
|
+
it "should adjust text to given size" do
|
43
|
+
subject.adjust("foo", 8).should == "foo \e[0;30m....\e[0m"
|
44
|
+
subject.adjust("foo", 8, '-').should == "foo \e[0;30m----\e[0m"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when no size given" do
|
49
|
+
it "should adjust text to console size" do
|
50
|
+
subject.expects(:console_width).returns(10)
|
51
|
+
subject.adjust("foo").should == "foo \e[0;30m......\e[0m"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'stringio'
|
6
|
+
require 'ostruct'
|
7
|
+
require 'rspec'
|
8
|
+
require 'mocha'
|
9
|
+
require 'wizard'
|
10
|
+
|
11
|
+
module Helpers
|
12
|
+
# Capture and silence output streams (stdout, stderr), and return it values.
|
13
|
+
#
|
14
|
+
# capture { puts "This is sparta!" }
|
15
|
+
# last_stdout # => "This is sparta!"
|
16
|
+
# last_stderr # => ""
|
17
|
+
def capture
|
18
|
+
@last_stdout = StringIO.new
|
19
|
+
@last_stderr = StringIO.new
|
20
|
+
begin
|
21
|
+
$stdout = @last_stdout
|
22
|
+
$stderr = @last_stderr
|
23
|
+
yield
|
24
|
+
ensure
|
25
|
+
$stdout = STDERR
|
26
|
+
$stderr = STDOUT
|
27
|
+
end
|
28
|
+
[@last_stdout.string, @last_stderr.string]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Replace standard input with faked one StringIO.
|
32
|
+
def fake_stdin(text)
|
33
|
+
begin
|
34
|
+
$stdin = StringIO.new
|
35
|
+
$stdin.puts(text)
|
36
|
+
$stdin.rewind
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
$stdin = STDIN
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns last string written to captured output stream.
|
44
|
+
def last_stdout
|
45
|
+
@last_stdout.string if @last_stdout
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns last string written to captured error stream.
|
49
|
+
def last_stderr
|
50
|
+
@last_stdout.string if @last_stdout
|
51
|
+
end
|
52
|
+
|
53
|
+
# Executes code within given temp directory context.
|
54
|
+
def within_tmp(&block)
|
55
|
+
FileUtils.mkdir(dirname = File.join(File.dirname(__FILE__), 'tmp'))
|
56
|
+
yield(File.expand_path(dirname))
|
57
|
+
ensure
|
58
|
+
FileUtils.rm_rf(dirname)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns mock generator.
|
62
|
+
def mock_gen(opts={})
|
63
|
+
Ryori::Generator.new(File.dirname(__FILE__)+"/tmp", opts)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
RSpec.configure do |config|
|
68
|
+
config.mock_with :mocha
|
69
|
+
config.include Helpers
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Wizard::Spells::CompileTemplate do
|
4
|
+
subject do
|
5
|
+
Wizard::Spells::CompileTemplate
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should set given filename" do
|
10
|
+
subject.new("/path/to/file", "/path/to/tpl").filename.should == "/path/to/file"
|
11
|
+
end
|
12
|
+
|
13
|
+
context "given template name" do
|
14
|
+
it "should be set" do
|
15
|
+
subject.new("/path/to/file", "/path/to/tpl").template.should == "/path/to/tpl"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set default chmod" do
|
20
|
+
subject.new("/path/to/file", "/path/to/tpl").chmod.should == 644
|
21
|
+
end
|
22
|
+
|
23
|
+
context "given :mode option" do
|
24
|
+
it "should set it" do
|
25
|
+
subject.new("/path/to/file", "/path/to/tpl", :mode => 755).chmod.should == 755
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "given :force option" do
|
30
|
+
it "should run in force mode" do
|
31
|
+
subject.new("/path/to/file", "/path/to/tpl", :force => true).should be_forced
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "#perform" do
|
37
|
+
subject do
|
38
|
+
Wizard::Spells::CompileTemplate.new("/path/to/file", "/path/to/tpl")
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when specified template causes errors" do
|
42
|
+
it "should set :error state" do
|
43
|
+
File.expects(:read).with("/path/to/tpl").raises(Exception)
|
44
|
+
spell = subject
|
45
|
+
spell.perform.should == :error
|
46
|
+
spell.should be_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when specified template is ok" do
|
51
|
+
it "should compile it and invoke make_file" do
|
52
|
+
File.expects(:read).with("/path/to/tpl").returns("<%='test'%>")
|
53
|
+
spell = subject
|
54
|
+
spell.expects(:perform_without_template_compilation).returns(:created)
|
55
|
+
spell.perform.should == :created
|
56
|
+
spell.content.should == 'test'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Wizard::Spells::ExecuteShell do
|
4
|
+
subject do
|
5
|
+
Wizard::Spells::ExecuteShell
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should set given command" do
|
10
|
+
subject.new("echo 'test'").command.should == "echo 'test'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#perform" do
|
15
|
+
context "when given command is valid" do
|
16
|
+
subject do
|
17
|
+
Wizard::Spells::ExecuteShell.new("echo 'test'")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should execute command and set :executed status" do
|
21
|
+
spell = subject
|
22
|
+
spell.perform == :executed
|
23
|
+
spell.should be_executed
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should set it output to instance variable" do
|
27
|
+
spell = subject
|
28
|
+
spell.perform
|
29
|
+
spell.output.should == "test\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when given command causes errors" do
|
34
|
+
subject do
|
35
|
+
Wizard::Spells::ExecuteShell.new("some-error")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should execute command and set :executed status" do
|
39
|
+
spell = subject
|
40
|
+
spell.expects(:failed!).raises(Exception)
|
41
|
+
spell.perform == :error
|
42
|
+
spell.should be_error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when given command can't be executed" do
|
47
|
+
subject do
|
48
|
+
Wizard::Spells::ExecuteShell.new("no-such-command")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should execute command and set :executed status" do
|
52
|
+
spell = subject
|
53
|
+
spell.perform == :failed
|
54
|
+
spell.should be_failed
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Wizard::Spells::MakeDir do
|
4
|
+
subject do
|
5
|
+
Wizard::Spells::MakeDir
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should set given dirname" do
|
10
|
+
subject.new("/path/to/dir").dirname.should == "/path/to/dir"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have empty chmod by default" do
|
14
|
+
subject.new("/path/to/dir").chmod.should == nil
|
15
|
+
end
|
16
|
+
|
17
|
+
context "given :mode" do
|
18
|
+
it "should set it" do
|
19
|
+
subject.new("/path/to/dir", :mode => 755).chmod.should == 755
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#perform" do
|
25
|
+
subject do
|
26
|
+
Wizard::Spells::MakeDir.new("/path/to/dir")
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when specified directory exists" do
|
30
|
+
it "should set :exist status" do
|
31
|
+
File.expects(:exist?).returns(true)
|
32
|
+
spell = subject
|
33
|
+
spell.perform.should == :exist
|
34
|
+
spell.should be_exist
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when specified directory doesn't exist" do
|
39
|
+
context "and user have access to create it" do
|
40
|
+
it "should set :created status" do
|
41
|
+
FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).returns("/path/to/dir")
|
42
|
+
spell = subject
|
43
|
+
spell.perform.should == :created
|
44
|
+
spell.should be_created
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "and user don't have access to create it" do
|
49
|
+
it "should set :noaccess status" do
|
50
|
+
FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).raises(Errno::EACCES)
|
51
|
+
spell = subject
|
52
|
+
spell.perform.should == :noaccess
|
53
|
+
spell.should be_noaccess
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when unknown error raised while creating directory" do
|
59
|
+
it "shouldn't create it and set :noaccess status" do
|
60
|
+
FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).raises(Exception)
|
61
|
+
spell = subject
|
62
|
+
spell.perform.should == :error
|
63
|
+
spell.should be_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when directory can't been created" do
|
68
|
+
it "shouldn't create it and set :error status" do
|
69
|
+
FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).returns(false)
|
70
|
+
spell = subject
|
71
|
+
spell.perform.should == :error
|
72
|
+
spell.should be_error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe Wizard::Spells::MakeFile do
|
4
|
+
subject do
|
5
|
+
Wizard::Spells::MakeFile
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should set given filename" do
|
10
|
+
subject.new("/path/to/file").filename.should == "/path/to/file"
|
11
|
+
end
|
12
|
+
|
13
|
+
context "given content" do
|
14
|
+
it "should be set" do
|
15
|
+
subject.new("/path/to/file", "hello world!").content.should == "hello world!"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have empty chmod by default" do
|
20
|
+
subject.new("/path/to/file").chmod.should == nil
|
21
|
+
end
|
22
|
+
|
23
|
+
context "given :mode option" do
|
24
|
+
it "should set it" do
|
25
|
+
subject.new("/path/to/file", nil, :mode => 755).chmod.should == 755
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "given :force option" do
|
30
|
+
it "should run in force mode" do
|
31
|
+
subject.new("/path/to/file", nil, :force => true).should be_forced
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#perform" do
|
37
|
+
subject do
|
38
|
+
Wizard::Spells::MakeFile.new("/path/to/file")
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when specified file exists" do
|
42
|
+
subject do
|
43
|
+
Wizard::Spells::MakeFile.new("/path/to/file", "testing")
|
44
|
+
end
|
45
|
+
|
46
|
+
context "and it content is identical as given one" do
|
47
|
+
it "should set :identical status" do
|
48
|
+
File.expects(:exist?).returns(true)
|
49
|
+
File.expects(:read).with("/path/to/file").returns("testing")
|
50
|
+
spell = subject
|
51
|
+
spell.perform.should == :identical
|
52
|
+
spell.should be_identical
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "and it content is different than given one" do
|
57
|
+
subject do
|
58
|
+
Wizard::Spells::MakeFile.new("/path/to/file", "testing")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should set :conflict status" do
|
62
|
+
File.expects(:exist?).returns(true)
|
63
|
+
File.expects(:read).with("/path/to/file").returns("not-testing")
|
64
|
+
spell = subject
|
65
|
+
spell.perform.should == :conflict
|
66
|
+
spell.should be_conflict
|
67
|
+
end
|
68
|
+
|
69
|
+
context "and force mode is on" do
|
70
|
+
subject do
|
71
|
+
Wizard::Spells::MakeFile.new("/path/to/file", "testing", :force => true)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should overwrite current file" do
|
75
|
+
File.expects(:exist?).returns(true)
|
76
|
+
File.expects(:read).with("/path/to/file").returns("not-testing")
|
77
|
+
spell = subject
|
78
|
+
spell.expects(:create_file!).returns(true)
|
79
|
+
spell.perform.should == :updated
|
80
|
+
spell.should be_updated
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when specified file doesn't exist" do
|
87
|
+
context "and user have access to create it" do
|
88
|
+
it "should set :created status" do
|
89
|
+
File.expects(:open).with("/path/to/file", "w+").returns(true)
|
90
|
+
FileUtils.expects(:chmod).with(644, "/path/to/file").returns(true)
|
91
|
+
spell = subject
|
92
|
+
spell.perform.should == :created
|
93
|
+
spell.should be_created
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "and user don't have access to create it" do
|
98
|
+
it "should set :noaccess status" do
|
99
|
+
File.expects(:open).with("/path/to/file", "w+").raises(Errno::EACCES)
|
100
|
+
spell = subject
|
101
|
+
spell.perform.should == :noaccess
|
102
|
+
spell.should be_noaccess
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when unknown error raised while creating file" do
|
108
|
+
it "shouldn't create it and set :noaccess status" do
|
109
|
+
File.expects(:open).with("/path/to/file", "w+").raises(Exception)
|
110
|
+
spell = subject
|
111
|
+
spell.perform.should == :error
|
112
|
+
spell.should be_error
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when file can't be created or chmod not set" do
|
117
|
+
it "shouldn't create it and set :error status" do
|
118
|
+
File.expects(:open).with("/path/to/file", "w+").returns(false)
|
119
|
+
spell = subject
|
120
|
+
spell.perform.should == :error
|
121
|
+
spell.should be_error
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|