BuildMaster 0.7.0 → 0.8.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.
- data/README +26 -0
- data/lib/buildmaster.rb +2 -1
- data/lib/buildmaster/build_number_file.rb +27 -0
- data/lib/buildmaster/buildnumber +1 -0
- data/lib/buildmaster/file_processor.rb +114 -25
- data/lib/buildmaster/java_manifest.rb +4 -0
- data/lib/buildmaster/{site.rb → site/site.rb} +11 -46
- data/lib/buildmaster/site/template/buildmaster.css +340 -0
- data/lib/buildmaster/site/template/buildmaster_template.xml +130 -0
- data/lib/buildmaster/site/template_builder.rb +276 -0
- data/lib/buildmaster/site_server.rb +33 -0
- data/lib/buildmaster/site_spec.rb +74 -22
- data/lib/buildmaster/site_tester.rb +14 -2
- data/lib/buildmaster/source_content.rb +11 -0
- data/lib/buildmaster/source_file_handler.rb +7 -2
- data/lib/buildmaster/svn_driver.rb +23 -11
- data/lib/buildmaster/template_exception.rb +8 -0
- data/lib/buildmaster/template_runner.rb +19 -86
- data/lib/buildmaster/templatelets.rb +23 -0
- data/lib/buildmaster/templatelets/attribute.rb +16 -0
- data/lib/buildmaster/templatelets/each.rb +43 -0
- data/lib/buildmaster/templatelets/href.rb +39 -0
- data/lib/buildmaster/templatelets/include.rb +30 -0
- data/lib/buildmaster/templatelets/link.rb +41 -0
- data/lib/buildmaster/templatelets/text.rb +14 -0
- data/lib/buildmaster/templatelets/when.rb +24 -0
- data/lib/buildmaster/tree_to_object.rb +76 -0
- data/lib/buildmaster/xtemplate.rb +10 -11
- data/test/buildmaster/manifest.mf +1 -1
- data/test/buildmaster/{content → site/content}/index.html +0 -0
- data/test/buildmaster/site/content/markdown.markdown +0 -0
- data/test/buildmaster/site/content/textile.textile +0 -0
- data/test/buildmaster/{tc_site.rb → site/tc_site.rb} +1 -1
- data/test/buildmaster/site/tc_template_builder.rb +128 -0
- data/test/buildmaster/tc_build_number_file.rb +31 -0
- data/test/buildmaster/tc_file_processor.rb +81 -14
- data/test/buildmaster/tc_site_spec.rb +26 -42
- data/test/buildmaster/tc_source_file_handler.rb +55 -0
- data/test/buildmaster/tc_template_runner.rb +42 -1
- data/test/buildmaster/tc_tree_to_object.rb +120 -0
- data/test/buildmaster/tc_xtemplate.rb +13 -233
- data/test/buildmaster/templatelets/common_templatelet_test.rb +27 -0
- data/test/buildmaster/templatelets/tc_attribute.rb +57 -0
- data/test/buildmaster/templatelets/tc_each.rb +69 -0
- data/test/buildmaster/templatelets/tc_href.rb +48 -0
- data/test/buildmaster/templatelets/tc_include.rb +34 -0
- data/test/buildmaster/templatelets/tc_link.rb +70 -0
- data/test/buildmaster/templatelets/tc_text.rb +36 -0
- data/test/buildmaster/templatelets/tc_when.rb +59 -0
- data/test/buildmaster/ts_site.rb +4 -0
- data/test/buildmaster/ts_templatelets.rb +10 -0
- data/test/tmp/output/index.html +8 -0
- data/test/tmp/output/markdown.html +8 -0
- data/test/tmp/output/textile.html +8 -0
- data/test/ts_buildmaster.rb +15 -3
- metadata +102 -53
@@ -0,0 +1,14 @@
|
|
1
|
+
module BuildMaster
|
2
|
+
class Text
|
3
|
+
def initialize(properties)
|
4
|
+
@properties = properties
|
5
|
+
end
|
6
|
+
|
7
|
+
def process(target, template, source)
|
8
|
+
property = template.attribute_value!('property')
|
9
|
+
value = @properties[property]
|
10
|
+
raise TemplateException, "property value for '#{property}' not found" unless value
|
11
|
+
target.add(REXML::Text.new(value))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..')
|
2
|
+
|
3
|
+
require 'template_runner'
|
4
|
+
|
5
|
+
module BuildMaster
|
6
|
+
class When
|
7
|
+
def initialize(site_spec, expression_evaluator)
|
8
|
+
@site_spec = site_spec
|
9
|
+
@evaluator = expression_evaluator
|
10
|
+
end
|
11
|
+
|
12
|
+
def process(target, template, source)
|
13
|
+
eval = template.attribute_value!('test')
|
14
|
+
if (not @evaluator.respond_to?(eval))
|
15
|
+
raise TemplateException, "#{@evaluator.class} cannot evaluate expression #{eval}"
|
16
|
+
end
|
17
|
+
if (@evaluator.send(eval, source.path))
|
18
|
+
runner = TemplateRunner.new(target, template, source)
|
19
|
+
runner.templatelets = @site_spec.load_templatelets
|
20
|
+
runner.process
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module BuildMaster
|
4
|
+
|
5
|
+
class PropertyMatchError < StandardError
|
6
|
+
|
7
|
+
attr_reader :property, :type, :target
|
8
|
+
|
9
|
+
def initialize(property, type, target)
|
10
|
+
@property = property
|
11
|
+
@type = type
|
12
|
+
@target = target
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TreeToObject
|
17
|
+
def initialize(tree, object)
|
18
|
+
@tree = tree
|
19
|
+
@object = object
|
20
|
+
end
|
21
|
+
|
22
|
+
def TreeToObject.from_yaml(content, object)
|
23
|
+
tree = {}
|
24
|
+
if (content.chomp!)
|
25
|
+
tree = YAML.load(content)
|
26
|
+
if (not tree.kind_of?(Hash))
|
27
|
+
raise "Format error for content:\n#{content}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return TreeToObject.new(tree, object).convert
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def convert
|
35
|
+
@tree.each_pair do |key, value|
|
36
|
+
if (value.kind_of?(Array))
|
37
|
+
convert_array(key, value)
|
38
|
+
elsif (value.kind_of?(Hash))
|
39
|
+
convert_hash(key, value)
|
40
|
+
else
|
41
|
+
convert_property(key, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return @object
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def convert_hash(field, hash)
|
49
|
+
return TreeToObject.new(hash, property("#{field}", field, 'sub property')).convert
|
50
|
+
end
|
51
|
+
|
52
|
+
def convert_array(field, array)
|
53
|
+
array.each do |item|
|
54
|
+
TreeToObject.new(item, property("add_to_#{field}", field, 'array')).convert
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def convert_property(field, value)
|
59
|
+
method = "#{field}="
|
60
|
+
check_property(method, field, 'string')
|
61
|
+
@object.send("#{field}=", value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def property(method, field, type)
|
65
|
+
check_property(method, field, type)
|
66
|
+
@object.send(method)
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_property(method, field, type)
|
70
|
+
if not @object.respond_to? method
|
71
|
+
message = "#{field} does not exist as #{type} in #{@object}"
|
72
|
+
raise PropertyMatchError.new(field, type, @object), message, caller
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -4,25 +4,24 @@ require 'rexml/document'
|
|
4
4
|
require 'template_runner'
|
5
5
|
|
6
6
|
module BuildMaster
|
7
|
-
class TemplateException < Exception
|
8
|
-
end
|
9
|
-
|
10
7
|
class XTemplate
|
11
|
-
def initialize(template_file)
|
8
|
+
def initialize(template_file, templatelets = Hash.new)
|
12
9
|
@template = REXML::Document.new(template_file)
|
10
|
+
@templatelets = templatelets
|
13
11
|
end
|
14
12
|
|
15
|
-
def process(
|
16
|
-
|
17
|
-
output_xml = process_xml(content_xml, &evaluator)
|
13
|
+
def process(source, &evaluator)
|
14
|
+
output_xml = process_xml(source, &evaluator)
|
18
15
|
return output_xml
|
19
16
|
end
|
20
17
|
|
21
18
|
private
|
22
|
-
def process_xml(
|
23
|
-
|
24
|
-
TemplateRunner.new(
|
25
|
-
|
19
|
+
def process_xml(source, &evaluator)
|
20
|
+
output_xml = REXML::Document.new
|
21
|
+
runner = TemplateRunner.new(output_xml, @template, source, &evaluator)
|
22
|
+
runner.templatelets = @templatelets
|
23
|
+
runner.process
|
24
|
+
return output_xml
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,128 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rexml/xpath'
|
5
|
+
require 'buildmaster/site/template_builder'
|
6
|
+
require 'buildmaster/tree_to_object'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
module BuildMaster
|
10
|
+
class TemplateBuilderTest < Test::Unit::TestCase
|
11
|
+
def test_should_generate_template_document
|
12
|
+
builder = TemplateBuilder.new
|
13
|
+
document = builder.generate
|
14
|
+
assert_equal('include', REXML::XPath.first(document, '/html/head/title/*').name)
|
15
|
+
assert_css_path(document, 'buildmaster.css')
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_update_header_with_title_and_css
|
19
|
+
builder = TemplateBuilder.new
|
20
|
+
builder.title_header = 'Title Header - '
|
21
|
+
builder.css_path = 'mycss.css'
|
22
|
+
document = builder.generate
|
23
|
+
first_child = REXML::XPath.first(document, '/html/head/title').children[0]
|
24
|
+
assert_equal(REXML::Text, first_child.class)
|
25
|
+
assert_equal('Title Header - ', first_child.value)
|
26
|
+
assert_css_path(document, 'mycss.css')
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_have_logo_defaults
|
30
|
+
builder = TemplateBuilder.new
|
31
|
+
assert_equal(nil, builder.logo.path)
|
32
|
+
assert_equal('index.html', builder.logo.link)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_generate_logo_and_link
|
36
|
+
builder = TemplateBuilder.new
|
37
|
+
builder.logo.path = 'gif/logo.gif'
|
38
|
+
builder.logo.link = 'main.html'
|
39
|
+
document = builder.generate
|
40
|
+
header = assert_first(document, '/html/body/div[@class="header"]')
|
41
|
+
anchor_href = assert_first(header, 'a/template:href')
|
42
|
+
assert_equal('main.html', anchor_href.attributes['url'])
|
43
|
+
img_href = assert_first(header, 'a/img/template:href')
|
44
|
+
assert_equal('gif/logo.gif', img_href.attributes['url'])
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_should_build_left_menu
|
48
|
+
builder = TemplateBuilder.new
|
49
|
+
builder.left_bottom_logo.path='http://www.example.com/logo.gif'
|
50
|
+
group = builder.menu_group('Software')
|
51
|
+
group.menu_item('Download', 'download.html')
|
52
|
+
group.menu_item('License', 'license.html')
|
53
|
+
group.more='more.html'
|
54
|
+
group = builder.menu_group('Documentation', 'doc/index.html')
|
55
|
+
group.menu_item('Getting Started', 'doc/getting-started')
|
56
|
+
document = builder.generate
|
57
|
+
groups = REXML::XPath.match(document, '/html/body/div[@class="left"]/div[@class="MenuGroup"]')
|
58
|
+
assert_equal(2, groups.size)
|
59
|
+
first_group = groups[0]
|
60
|
+
header = assert_first(first_group, 'h1')
|
61
|
+
assert_equal('Software', header.text)
|
62
|
+
items = REXML::XPath.match(first_group, 'ul/li')
|
63
|
+
assert_equal(3, items.size)
|
64
|
+
first_item = items[0]
|
65
|
+
anchor = assert_first(first_item, 'template:link')
|
66
|
+
assert_equal('download.html', anchor.attributes['href'])
|
67
|
+
assert_equal('Download', anchor.text)
|
68
|
+
more = items[2]
|
69
|
+
assert_equal('More', more.attributes['class'])
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_should_have_releases_info
|
73
|
+
builder = TemplateBuilder.new
|
74
|
+
releases = builder.releases
|
75
|
+
releases.stable_version = '0.6'
|
76
|
+
releases.pre_release_version = '0.7'
|
77
|
+
releases.snap_shot_version = 'n/a'
|
78
|
+
releases.download_link = 'download.html'
|
79
|
+
releases.versioning_link = 'versioning.html'
|
80
|
+
builder.generate
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_should_read_from_yaml
|
84
|
+
content = <<CONTENT
|
85
|
+
title_header: BuilderMaster -
|
86
|
+
logo:
|
87
|
+
path: logo.gif
|
88
|
+
link: index.html
|
89
|
+
menu_groups:
|
90
|
+
- title: Software
|
91
|
+
menu_items:
|
92
|
+
- title: Download
|
93
|
+
link: download.html
|
94
|
+
- title: Source Repository
|
95
|
+
link: http://rubyforge.org/scm/?group_id=1680
|
96
|
+
- title: Project License
|
97
|
+
link: license.html
|
98
|
+
- title: Documentation...
|
99
|
+
link: document.html
|
100
|
+
menu_items:
|
101
|
+
- title: Getting Started
|
102
|
+
link: getting-started.html
|
103
|
+
- title: Project Release
|
104
|
+
link: release-project.html
|
105
|
+
- title: Site Building
|
106
|
+
link: build-site.html
|
107
|
+
more: doc/index.html
|
108
|
+
CONTENT
|
109
|
+
builder = TreeToObject.from_yaml(content, TemplateBuilder.new)
|
110
|
+
assert_equal('BuilderMaster -', builder.title_header)
|
111
|
+
assert_equal('logo.gif', builder.logo.path)
|
112
|
+
assert_equal('index.html', builder.logo.link)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def assert_css_path(document, expected)
|
117
|
+
href = REXML::XPath.first(document, '/html/head/link/*')
|
118
|
+
assert_equal('href', href.name)
|
119
|
+
assert_equal(expected, href.attributes['url'])
|
120
|
+
end
|
121
|
+
|
122
|
+
def assert_first(xml_model, xpath)
|
123
|
+
first = REXML::XPath.first(xml_model, xpath)
|
124
|
+
assert_not_nil(first)
|
125
|
+
return first
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'buildmaster/build_number_file'
|
6
|
+
|
7
|
+
module BuildMaster
|
8
|
+
class BuildNumberFileTest < Test::Unit::TestCase
|
9
|
+
def test_load_file
|
10
|
+
path = tmp_file(2)
|
11
|
+
build_number = BuildNumberFile.new(path)
|
12
|
+
assert_equal(2, build_number.number)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_increase_build
|
16
|
+
path = tmp_file(3)
|
17
|
+
build_number = BuildNumberFile.new(path)
|
18
|
+
build_number.increase_build
|
19
|
+
assert_equal(4, build_number.number)
|
20
|
+
reloaded = BuildNumberFile.new(path)
|
21
|
+
assert_equal(4, reloaded.number)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def tmp_file(build_number)
|
26
|
+
path = File.join(File.dirname(__FILE__), '..', '..', 'tmp', 'buildnumber')
|
27
|
+
File.open(path, "w") {|file| file.puts build_number}
|
28
|
+
return path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -2,32 +2,99 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "lib")
|
|
2
2
|
|
3
3
|
require 'test/unit'
|
4
4
|
require 'rexml/document'
|
5
|
+
require 'pathname'
|
5
6
|
require 'buildmaster/file_processor'
|
6
7
|
require 'buildmaster/xtemplate'
|
7
8
|
|
8
9
|
module BuildMaster
|
9
10
|
class FileProcessorTest < Test::Unit::TestCase
|
10
|
-
def
|
11
|
-
|
11
|
+
def test_should_know_content_and_target
|
12
|
+
template = XTemplate.new(<<CONTENT
|
12
13
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
13
14
|
xmlns:template="http://buildmaster.rubyforge.org/xtemplate/1.0">
|
14
|
-
<p>
|
15
|
-
<template:attribute name="class" eval="method_one"/>
|
16
|
-
</p>
|
17
15
|
</html>
|
18
16
|
CONTENT
|
19
17
|
)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
site_spec = SiteSpec.new
|
19
|
+
current_dir = File.dirname(__FILE__)
|
20
|
+
site_spec.content_dir = File.join(current_dir, "content")
|
21
|
+
site_spec.output_dir = File.join(current_dir, "output")
|
22
|
+
processor = FileProcessor.new(template, File.join(current_dir, 'content', 'index.html'), site_spec)
|
23
|
+
assert_equal(File.join(current_dir, 'content', 'index.html'), processor.path_to_content_file)
|
24
|
+
assert_equal(true, processor.is_html?)
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
def test_should_know_html_target
|
28
|
+
template = XTemplate.new(<<CONTENT
|
29
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
30
|
+
xmlns:template="http://buildmaster.rubyforge.org/xtemplate/1.0">
|
31
|
+
</html>
|
32
|
+
CONTENT
|
33
|
+
)
|
34
|
+
site_spec = SiteSpec.new
|
35
|
+
current_dir = File.dirname(__FILE__)
|
36
|
+
site_spec.content_dir = File.join(current_dir, "content")
|
37
|
+
site_spec.output_dir = File.join(current_dir, "output")
|
38
|
+
processor = FileProcessor.new(template, File.join(current_dir, 'content', 'index.gif'), site_spec)
|
39
|
+
assert_equal(File.join(current_dir, 'content', 'index.gif'), processor.path_to_content_file)
|
40
|
+
assert_equal(false, processor.is_html?)
|
41
|
+
assert_equal(nil, processor.generate_document)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_load_from_target
|
45
|
+
template_content = <<CONTENT
|
46
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
47
|
+
xmlns:template="http://buildmaster.rubyforge.org/xtemplate/1.0">
|
48
|
+
</html>
|
49
|
+
CONTENT
|
50
|
+
site_spec = SiteSpec.new
|
51
|
+
current_dir = File.dirname(__FILE__)
|
52
|
+
site_spec.template = template_content
|
53
|
+
site_spec.content_dir = File.join(current_dir, 'site', 'content')
|
54
|
+
site_spec.output_dir = File.join(current_dir, "output")
|
55
|
+
processor = FileProcessor.for_request_path('/index.html', site_spec)
|
56
|
+
assert_equal(File.join(site_spec.content_dir, 'index.html'), processor.path_to_content_file)
|
57
|
+
processor = FileProcessor.for_request_path('/index.gif', site_spec)
|
58
|
+
assert_equal(File.join(site_spec.content_dir, 'index.gif'), processor.path_to_content_file)
|
59
|
+
processor = FileProcessor.for_request_path('/textile.html', site_spec)
|
60
|
+
assert_equal(File.join(site_spec.content_dir, 'textile.textile'), processor.path_to_content_file)
|
61
|
+
processor = FileProcessor.for_request_path('/markdown.html', site_spec)
|
62
|
+
assert_equal(File.join(site_spec.content_dir, 'markdown.markdown'), processor.path_to_content_file)
|
63
|
+
end
|
64
|
+
|
65
|
+
def output_dir
|
66
|
+
return 'tmp'
|
67
|
+
end
|
68
|
+
|
69
|
+
def relative_to_root(path)
|
70
|
+
return Pathname.new('tmp')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_mark_down_support
|
74
|
+
template_content = <<CONTENT
|
75
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
76
|
+
xmlns:template="http://buildmaster.rubyforge.org/xtemplate/1.0">
|
77
|
+
<head><title><template:include elements="/html/head/title/text()"/></title></head>
|
78
|
+
<body>
|
79
|
+
<template:include elements="/html/body/*"/>
|
80
|
+
</body>
|
81
|
+
</html>
|
82
|
+
CONTENT
|
83
|
+
hash = {'include' => Include.new(self)}
|
84
|
+
template = XTemplate.new(template_content, hash)
|
85
|
+
|
86
|
+
processor = FileProcessor.new(template, "content_path", self)
|
87
|
+
markdown_content = <<CONTENT
|
88
|
+
--------------------------------------------
|
89
|
+
Title Here
|
90
|
+
--------------------------------------------
|
91
|
+
Header
|
92
|
+
=====================
|
93
|
+
CONTENT
|
94
|
+
document = processor.process_markdown(markdown_content)
|
95
|
+
document = REXML::Document.new(document.to_s)
|
96
|
+
assert_equal('Title Here', REXML::XPath.first(document, '/html/head/title').text)
|
97
|
+
assert_equal('Header', REXML::XPath.first(document, '/html/body/h1').text)
|
31
98
|
end
|
32
99
|
|
33
100
|
end
|