wizard 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|