BuildMaster 0.5.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.
@@ -0,0 +1,68 @@
1
+
2
+
3
+ require 'webrick'
4
+ require 'file_processor'
5
+
6
+ module BuildMaster
7
+
8
+ class SourceFileHandler < WEBrick::HTTPServlet::AbstractServlet
9
+ # uncomment the following for automatic servlet reloading
10
+ def SourceFileHandler.get_instance config, *options
11
+ load __FILE__
12
+ SourceFileHandler.new config, *options
13
+ end
14
+
15
+ def initialize(server, spec)
16
+ super
17
+ @config = server.config
18
+ @logger = @config[:Logger]
19
+ @spec = spec
20
+ @delegate = WEBrick::HTTPServlet::FileHandler.new(server, spec.content_dir, true)
21
+ end
22
+
23
+ def service(req, res)
24
+ path = req.path_info
25
+ extension = File.extname(path)
26
+ if (extension == '')
27
+ path = "#{path}index.html"
28
+ extension = '.html'
29
+ end
30
+ if (extension.casecmp('.html') == 0)
31
+ begin
32
+ serve_generated_file(path[0, path.length - 5], req, res)
33
+ rescue Exception
34
+ @logger.error("error serving the file #{path}")
35
+ @logger.error($!)
36
+ raise WEBrick::HTTPStatus::InternalServerError,
37
+ "#{$!}", caller
38
+ end
39
+ else
40
+ @delegate.service(req, res)
41
+ end
42
+ end
43
+
44
+ private
45
+ def serve_generated_file(path, req, res)
46
+ file_path = @spec.content_dir + path
47
+ textile_file = "#{file_path}.textile"
48
+ html_file = "#{file_path}.html"
49
+ if File.file? textile_file
50
+ stats = File::stat(textile_file)
51
+ document = FileProcessor.new(@spec.load_template, textile_file, @spec).process_textile()
52
+ elsif File.file? html_file
53
+ stats = File::stat(html_file)
54
+ document = FileProcessor.new(@spec.load_template, html_file, @spec).process_html()
55
+ end
56
+ if (document)
57
+ content = document.to_s
58
+ res['content-type'] = 'text/html'
59
+ res['content-length'] = content.length
60
+ res['last-modified'] = stats.mtime.httpdate
61
+ res.body = content
62
+ else
63
+ @delegate.service(req, res)
64
+ end
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,68 @@
1
+ require 'rexml/document'
2
+
3
+ module BuildMaster
4
+
5
+ class SvnInfo
6
+ attr_reader :path, :repository_root
7
+
8
+ def initialize(path)
9
+ @path = path
10
+ analyze_entry_file(File.join(path, ".svn", "entries"))
11
+ end
12
+
13
+ def analyze_entry_file(file)
14
+ xml = REXML::Document.new(File.open(file))
15
+ xml.root.each_element_with_attribute('name', '', 1) do |element|
16
+ @repository_root = element.attributes['repos']
17
+ end
18
+ end
19
+ end
20
+
21
+ class SvnDriver
22
+ include Shell
23
+
24
+ def SvnDriver::from_path(directory)
25
+ return SvnDriver.new(SvnInfo.new(directory))
26
+ end
27
+
28
+ def initialize(svn_info, &command_runner)
29
+ @svn_info = svn_info
30
+ if (command_runner)
31
+ @command_runner = command_runner
32
+ else
33
+ @command_runner = Proc.new {|command| run(command)}
34
+ end
35
+ end
36
+
37
+ def status
38
+ command_for_path('status')
39
+ end
40
+
41
+ def update
42
+ command_for_path('update')
43
+ end
44
+
45
+ def commit(comment)
46
+ command_for_path('commit', " -m \"#{comment}\"")
47
+ end
48
+
49
+ def tag(tag_name)
50
+ run_command("svn copy #{@svn_info.repository_root}/trunk #{@svn_info.repository_root}/tags/#{tag_name} -m \"ruby buildmaster\"")
51
+ end
52
+
53
+ def checkout(output)
54
+ run_command("svn checkout #{@svn_info.repository_root}/trunk #{output}")
55
+ end
56
+
57
+ def command(command)
58
+ command_for_path(command)
59
+ end
60
+
61
+ private
62
+
63
+ def command_for_path(svn_command, argument='')
64
+ run_command("svn #{svn_command} #{@svn_info.path}#{argument}")
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,128 @@
1
+ module BuildMaster
2
+ class TemplateRunner
3
+ NAMESPACE = "http://buildmaster.rubyforge.org/xtemplate/1.0"
4
+
5
+ def initialize(result, template, source, &evaluator)
6
+ @result = result
7
+ @template = template
8
+ @source = source
9
+ @evaluator = evaluator
10
+ end
11
+
12
+ def process
13
+ process_children(@result, @template)
14
+ end
15
+
16
+ private
17
+ def process_children(target, template)
18
+ template.each do |element|
19
+ if (element.kind_of? REXML::Element)
20
+ process_element(target, element)
21
+ else
22
+ target.add(deep_clone(element))
23
+ end
24
+ end
25
+ end
26
+
27
+ def process_element(target, element)
28
+ if (template_directive?(element))
29
+ process_directive(target, element)
30
+ else
31
+ output_element = clone_element(element)
32
+ target.add(output_element)
33
+ process_children(output_element, element)
34
+ end
35
+ end
36
+
37
+ def template_directive?(element)
38
+ element.namespace == NAMESPACE
39
+ end
40
+
41
+ def process_directive(target, template_element)
42
+ begin
43
+ action = method("process_#{template_element.name}_directive")
44
+ action.call(target, template_element)
45
+ rescue NameError
46
+ raise TemplateException,
47
+ "unable to process template:#{template_element.name}: #{$!}" ,
48
+ caller
49
+ end
50
+ end
51
+
52
+ def clone_element( template_element )
53
+ cloned_element = REXML::Element.new( template_element.expanded_name )
54
+ copy_attributes( template_element, cloned_element )
55
+ cloned_element
56
+ end
57
+
58
+ def copy_attributes( template_element, expanded_element )
59
+ template_element.attributes.each_attribute do |attribute|
60
+ expanded_element.attributes.add( attribute.clone )
61
+ end
62
+ end
63
+
64
+ def deep_clone( node )
65
+ if node.kind_of? REXML::Parent
66
+ node.deep_clone
67
+ else
68
+ node.clone
69
+ end
70
+ end
71
+
72
+ def process_include_directive(target_element, template_element)
73
+ elements_attribute = template_element.attributes["elements"]
74
+ if (elements_attribute)
75
+ REXML::XPath.match(@source, elements_attribute).each do |matched|
76
+ target_element.add(deep_clone(matched))
77
+ end
78
+ return
79
+ end
80
+ end
81
+
82
+ def process_when_directive(target_element, template_element)
83
+ if evaluate(template_element, 'test')
84
+ process_children(target_element, template_element)
85
+ end
86
+ end
87
+
88
+ def process_attribute_directive(target_element, template_element)
89
+ name = template_element.attributes['name']
90
+ target_element.attributes[name]=evaluate(template_element, 'eval')
91
+ end
92
+
93
+ def process_text_directive(target_element, template_element)
94
+ target_element.add(REXML::Text.new(evaluate(template_element, 'eval')))
95
+ end
96
+
97
+ def process_each_directive(target_element, template_element)
98
+ source_xml = evaluate!(template_element, 'source')
99
+ matched_element = REXML::XPath.match(REXML::Document.new(source_xml), template_element.attributes['select'])
100
+ count = attribute!(template_element, 'count')
101
+ count.to_i.times do |i|
102
+ TemplateRunner.new(target_element, template_element, matched_element[i], &@evaluator).process
103
+ end
104
+ end
105
+
106
+ def evaluate!(xml_element, attribute_name)
107
+ value = evaluate(xml_element, attribute_name)
108
+ message = xml_element.attributes[attribute_name]
109
+ if (not value)
110
+ raise TemplateException, "#{message} from attribute #{attribute_name} cannot be nil"
111
+ end
112
+ return value
113
+ end
114
+
115
+ def evaluate(xml_element, attribute_name)
116
+ message = attribute!(xml_element, attribute_name)
117
+ return @evaluator.call(message)
118
+ end
119
+
120
+ def attribute!(xml_element, attribute_name)
121
+ value = xml_element.attributes[attribute_name]
122
+ if (not value)
123
+ raise TemplateException, "attribute #{attribute_name} not found in #{xml_element}"
124
+ end
125
+ return value
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ # puts global_variables
2
+ puts ENV["path"]
3
+ puts nil.split(' ')
@@ -0,0 +1,28 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'rexml/document'
4
+ require 'template_runner'
5
+
6
+ module BuildMaster
7
+ class TemplateException < Exception
8
+ end
9
+
10
+ class XTemplate
11
+ def initialize(template_file)
12
+ @template = REXML::Document.new(template_file)
13
+ end
14
+
15
+ def process(content, &evaluator)
16
+ content_xml = REXML::Document.new(content)
17
+ output_xml = process_xml(content_xml, &evaluator)
18
+ return output_xml
19
+ end
20
+
21
+ private
22
+ def process_xml(content_xml, &evaluator)
23
+ result_xml = REXML::Document.new
24
+ TemplateRunner.new(result_xml, @template, content_xml, &evaluator).process
25
+ return result_xml
26
+ end
27
+ end
28
+ end
data/lib/mock.rb ADDED
@@ -0,0 +1,3 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'mock/mock_base.rb'
@@ -0,0 +1,24 @@
1
+ require 'set'
2
+ require 'test/unit'
3
+
4
+ class Mock
5
+ def initialize(class_to_mock=nil)
6
+ @class_to_mock = class_to_mock
7
+ @expectations = Set.new
8
+ end
9
+
10
+ def expects(message)
11
+ @expectations.add(message)
12
+ end
13
+
14
+ def verify
15
+
16
+ end
17
+
18
+ def method_missing(method, *args)
19
+ if (not @expectations.include? method)
20
+ raise "Unexpected extra call to #{method}"
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,8 @@
1
+ <project name="ant-test">
2
+ <target name="passing" description="A target that passes">
3
+ <echo message="invoked"/>
4
+ </target>
5
+ <target name="failing" description="A target that fails">
6
+ <fail message="failure message"/>
7
+ </target>
8
+ </project>
@@ -0,0 +1,7 @@
1
+ <!DOCTYPE html
2
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml">
5
+ <body><h1>Text</h1>
6
+ </body>
7
+ </html>
@@ -0,0 +1,27 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
2
+
3
+ require 'test/unit'
4
+ require 'buildmaster'
5
+
6
+ class AntTest < Test::Unit::TestCase
7
+ protected
8
+ def setup
9
+ super
10
+ build_file = File.join(File.dirname(__FILE__), "build.xml")
11
+ @ant = Ant.new(build_file)
12
+ end
13
+
14
+ public
15
+
16
+ def test_run
17
+ @ant.project_help
18
+ end
19
+
20
+ def test_pass
21
+ @ant.target('passing')
22
+ end
23
+
24
+ def test_fail
25
+ assert_raise(RuntimeError) {@ant.target('failing')}
26
+ end
27
+ end
@@ -0,0 +1,62 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
2
+
3
+ require 'test/unit'
4
+ require 'buildmaster'
5
+
6
+ class CvsClientTest < Test::Unit::TestCase
7
+ protected
8
+ def setUp()
9
+ super
10
+ end
11
+
12
+ private
13
+ def ensure_folder_exists(path)
14
+ if (not File.exists? path)
15
+ Dir.mkdir(path)
16
+ end
17
+ end
18
+
19
+ public
20
+ def test_load_CvsInfo
21
+ folder = 'tmp'
22
+ ensure_folder_exists(folder);
23
+ root = ':ext:wolfdancer@cvsserver.com:/cvs/root'
24
+ repository = 'xpe'
25
+ write("#{folder}/ROOT", root)
26
+ write("#{folder}/Repository", repository)
27
+ cvs = CvsInfo.load(folder)
28
+ assert_equal(root, cvs.root)
29
+ assert_equal(repository, cvs.repository)
30
+ end
31
+
32
+ def tes_checkout
33
+ log = ''
34
+ client = CvsClient.new(CvsInfo.new('root', 'module'), 'working') {|command| log = command}
35
+ client.checkout
36
+ assert_equal('cvs -d root co -d working module', log)
37
+ end
38
+
39
+ def test_update
40
+ log = ''
41
+ client = CvsClient.new(CvsInfo.new('root', 'module'), 'working') {|command| log = command}
42
+ client.update
43
+ assert_equal('cvs -d root update working', log)
44
+ client.update('-PAd')
45
+ assert_equal('cvs -d root update -PAd working', log)
46
+ end
47
+
48
+ def test_command
49
+ log = ''
50
+ client = CvsClient.new(CvsInfo.new('root', 'module'), 'working') {|command| log = command}
51
+ client.command('command -option argument')
52
+ assert_equal('cvs -d root command -option argument working', log)
53
+ end
54
+
55
+ private
56
+ def write(fileName, content)
57
+ File.open(fileName, "w") do |file|
58
+ file.puts content
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,23 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
2
+
3
+ require 'test/unit'
4
+ require 'buildmaster'
5
+ require 'mock'
6
+
7
+ class ReleaseTest < Test::Unit::TestCase
8
+ def testRelease
9
+ cvs_mock = Mock.new(CvsClient)
10
+ cvs_mock.expects(:checkout)
11
+ cvs_mock.expects(:tag)
12
+ cvs_mock.expects(:commit)
13
+
14
+ builder_mock = Mock.new
15
+ builder_mock.expects(:build)
16
+
17
+ release = Release.new(cvs_mock, builder_mock)
18
+ release.release_candidate('tag')
19
+
20
+ cvs_mock.verify
21
+ builder_mock.verify
22
+ end
23
+ end