ironbuildrake 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -0
- data/Rakefile +73 -0
- data/VERSION +1 -0
- data/ironbuildrake.gemspec +55 -0
- data/lib/Microsoft.Build.Tasks.rb +6 -0
- data/lib/assembly_loader.rb +23 -0
- data/lib/build_engine.rb +105 -0
- data/lib/namespace_node.rb +49 -0
- data/lib/task_item.rb +56 -0
- data/lib/task_library.rb +124 -0
- data/lib/tasks_file.rb +104 -0
- data/test/helper.rb +8 -0
- data/test/tests_namespace_node.rb +46 -0
- data/test/tests_other_libraries.rb +53 -0
- data/test/tests_targets_file.rb +210 -0
- data/test/tests_task_library.rb +94 -0
- data/test/tests_tasks.rb +127 -0
- metadata +64 -0
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
$: << "lib"
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require "build_engine.rb"
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'jeweler'
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = "ironbuildrake"
|
11
|
+
gem.summary = %Q{Adds support for using msbuild tasks in ironruby with rake }
|
12
|
+
gem.description = %Q{}
|
13
|
+
gem.email = "brunomlopes@gmail.com"
|
14
|
+
gem.homepage = "http://github.com/brunomlopes/ironbuildrake"
|
15
|
+
gem.authors = ["Bruno Lopes"]
|
16
|
+
gem.files = FileList["[A-Z]*", "{lib, test}/**/*" ]
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
+
end
|
19
|
+
Jeweler::GemcutterTasks.new
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
Rake::TestTask.new(:test) do |test|
|
26
|
+
test.libs << 'lib' << 'test'
|
27
|
+
test.pattern = 'test/**/test_*.rb'
|
28
|
+
test.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'rcov/rcovtask'
|
33
|
+
Rcov::RcovTask.new do |test|
|
34
|
+
test.libs << 'test'
|
35
|
+
test.pattern = 'test/**/test_*.rb'
|
36
|
+
test.verbose = true
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
task :rcov do
|
40
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
task :test => :check_dependencies
|
45
|
+
|
46
|
+
task :default => :test
|
47
|
+
|
48
|
+
require 'rake/rdoctask'
|
49
|
+
Rake::RDocTask.new do |rdoc|
|
50
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
51
|
+
|
52
|
+
rdoc.rdoc_dir = 'rdoc'
|
53
|
+
rdoc.title = "ironbuildrake #{version}"
|
54
|
+
rdoc.rdoc_files.include('README*')
|
55
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
56
|
+
end
|
57
|
+
|
58
|
+
# task :default => [:test_units]
|
59
|
+
|
60
|
+
desc "this is just a quick smoke test"
|
61
|
+
task :test do
|
62
|
+
msbuild = tasks_from_module(Microsoft::Build::Tasks)
|
63
|
+
msbuild.Message :text => "This is a text message"
|
64
|
+
msbuild.Warning :text => "This is a warning"
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Run unit tests"
|
68
|
+
Rake::TestTask.new("test_units") do |t|
|
69
|
+
t.libs << "test"
|
70
|
+
t.pattern = 'test/tests_*.rb'
|
71
|
+
t.verbose = true
|
72
|
+
t.warning = true
|
73
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ironbuildrake}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Bruno Lopes"]
|
12
|
+
s.date = %q{2009-12-26}
|
13
|
+
s.description = %q{}
|
14
|
+
s.email = %q{brunomlopes@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"README",
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION",
|
22
|
+
"ironbuildrake.gemspec",
|
23
|
+
"lib/Microsoft.Build.Tasks.rb",
|
24
|
+
"lib/assembly_loader.rb",
|
25
|
+
"lib/build_engine.rb",
|
26
|
+
"lib/namespace_node.rb",
|
27
|
+
"lib/task_item.rb",
|
28
|
+
"lib/task_library.rb",
|
29
|
+
"lib/tasks_file.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/brunomlopes/ironbuildrake}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.5}
|
35
|
+
s.summary = %q{Adds support for using msbuild tasks in ironruby with rake}
|
36
|
+
s.test_files = [
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/tests_namespace_node.rb",
|
39
|
+
"test/tests_other_libraries.rb",
|
40
|
+
"test/tests_targets_file.rb",
|
41
|
+
"test/tests_tasks.rb",
|
42
|
+
"test/tests_task_library.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
50
|
+
else
|
51
|
+
end
|
52
|
+
else
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require "Microsoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
|
2
|
+
require "Microsoft.Build.Utilities, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
|
3
|
+
require "Microsoft.Build.Framework, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
|
4
|
+
|
5
|
+
#require 'Microsoft.Build.Framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
|
6
|
+
#require 'Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
class AssemblyLoader
|
4
|
+
@@assembly_paths = Set.new
|
5
|
+
|
6
|
+
def self.add_path(path)
|
7
|
+
raise Exception.new("Path cannot be nil") if path == nil
|
8
|
+
@@assembly_paths.add(path) if path != nil
|
9
|
+
end
|
10
|
+
|
11
|
+
System::AppDomain.current_domain.assembly_resolve do |sender, event|
|
12
|
+
found_path = nil
|
13
|
+
@@assembly_paths.each do |path|
|
14
|
+
assembly_path = System::IO::Path.get_full_path(System::IO::Path.combine(path,event.name))
|
15
|
+
if System::IO::File.exists(assembly_path)
|
16
|
+
found_path = assembly_path
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
throw System::IO::FileNotFoundException.new(event.name) unless found_path
|
21
|
+
System::Reflection::Assembly.LoadFile(found_path)
|
22
|
+
end
|
23
|
+
end
|
data/lib/build_engine.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'Microsoft.Build.Tasks'
|
2
|
+
require 'logger'
|
3
|
+
require 'tasks_file'
|
4
|
+
require 'task_library'
|
5
|
+
|
6
|
+
class RubyBuildEngine
|
7
|
+
include Microsoft::Build::Framework::IBuildEngine
|
8
|
+
# include Microsoft::Build::Framework::IBuildEngine2
|
9
|
+
attr_reader :column_number_of_task_node, :continue_on_error, :line_number_of_task_node,
|
10
|
+
:project_file_of_task_node, :is_running_multiple_nodes
|
11
|
+
|
12
|
+
def initialize(logger)
|
13
|
+
@logger = logger
|
14
|
+
@column_number_of_task_node = 1
|
15
|
+
@continue_on_error = true
|
16
|
+
@line_number_of_task_node = 2
|
17
|
+
@project_file_of_task_node = "project.file"
|
18
|
+
@is_running_multiple_nodes = false
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
def build_project_file(project_file_name, # string
|
24
|
+
target_names, # string[]
|
25
|
+
global_properties, # IDictionary
|
26
|
+
target_outputs, #IDictionary
|
27
|
+
tools_version #string
|
28
|
+
)
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
def BuildProjectFilesInParallel(project_file_names, #string[]
|
33
|
+
target_names, #string[],
|
34
|
+
global_properties, #IDictionary[]
|
35
|
+
target_outputs_per_project, #IDictionary[]
|
36
|
+
tools_version, #string[]
|
37
|
+
use_results_cache, #bool
|
38
|
+
unload_projects_on_completion) #bool
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_project_file(project_file_name, # string
|
43
|
+
target_names, # string[]
|
44
|
+
global_properties, # IDictionary
|
45
|
+
target_outputs #IDictionary
|
46
|
+
)
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
|
+
def log_event(e)
|
51
|
+
@logger.debug("#{e.Timestamp}:#{e.ThreadId}:#{e.SenderName}:#{e.Message}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def log_custom_event(e) # CustomBuildEventArgs
|
55
|
+
log_event(e)
|
56
|
+
@logger.debug("Custom event: " + e.to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
def log_error_event(e) #BuildErrorEventArgs
|
60
|
+
log_event(e)
|
61
|
+
@logger.error("#{e.Code}:#{e.ColumnNumber}:#{e.EndColumnNumber}:#{e.EndLineNumber}:#{e.File}:#{e.LineNumber}:#{e.Subcategory}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_message_event(e) #BuildMessageEventArgs
|
65
|
+
log_event(e)
|
66
|
+
# TODO: implement importance (dunno how)
|
67
|
+
@logger.info(e.Message)
|
68
|
+
end
|
69
|
+
|
70
|
+
def log_warning_event(e) #BuildWarningEventArgs
|
71
|
+
log_event(e)
|
72
|
+
@logger.warn(e.Message)
|
73
|
+
@logger.debug("#{e.Code}:#{e.ColumnNumber}:#{e.EndColumnNumber}:#{e.EndLineNumber}:#{e.File}:#{e.LineNumber}:#{e.Subcategory}")
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
logger = Logger.new(STDOUT)
|
79
|
+
logger.level = Logger::INFO
|
80
|
+
$build_engine = RubyBuildEngine.new(logger)
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
def tasks_from_module(mod)
|
85
|
+
TaskLibrary.from_modules($build_engine, mod)
|
86
|
+
end
|
87
|
+
|
88
|
+
def tasks_from_file(tasks_file)
|
89
|
+
TaskLibrary.from_tasks_file($build_engine, tasks_file)
|
90
|
+
end
|
91
|
+
|
92
|
+
def tasks_from_msbuild_2_0()
|
93
|
+
load_assembly 'Microsoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
|
94
|
+
#directory = System::Runtime::InteropServices::RuntimeEnvironment.get_runtime_directory
|
95
|
+
#file_name = "Microsoft.Common.Tasks"
|
96
|
+
#full_path = System::IO::Path.combine(directory, file_name)
|
97
|
+
return TaskLibrary.from_modules($build_engine, Microsoft::Build::Tasks)
|
98
|
+
end
|
99
|
+
|
100
|
+
def tasks_from_msbuild_3_5()
|
101
|
+
directory = System::Environment.expand_environment_variables('%WINDIR%\Microsoft.NET\Framework\v3.5')
|
102
|
+
file_name = "Microsoft.Common.Tasks"
|
103
|
+
full_path = System::IO::Path.combine(directory, file_name)
|
104
|
+
return TaskLibrary.from_tasks_file($build_engine, full_path)
|
105
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class NamespaceNode
|
2
|
+
attr_reader :name, :children
|
3
|
+
def initialize(name)
|
4
|
+
@name = name
|
5
|
+
@children = { }
|
6
|
+
@objects = { }
|
7
|
+
end
|
8
|
+
|
9
|
+
def << (name)
|
10
|
+
add_child(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_child(name)
|
14
|
+
if @objects.has_key? name
|
15
|
+
raise Exception.new("Node #{@name} already has object with name #{name}")
|
16
|
+
end
|
17
|
+
if not @children.has_key? name
|
18
|
+
@children[name] = NamespaceNode.new(name)
|
19
|
+
self.metaclass.send :define_method, name do
|
20
|
+
@children[name]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@children[name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_object(name, object, *namespaces)
|
27
|
+
raise Exception.new("Node #{@name} already has child node with name #{name}") if @children.has_key? name
|
28
|
+
raise Exception.new("Node #{@name} already has object with name #{name}") if @objects.has_key? name
|
29
|
+
|
30
|
+
if namespaces.length > 0
|
31
|
+
next_namespace = namespaces.shift.to_s
|
32
|
+
raise Exception.new("No namespace with name #{next_namespace} found") if not @children.has_key?(next_namespace)
|
33
|
+
@children[next_namespace].add_object(name, object, *namespaces)
|
34
|
+
else
|
35
|
+
@objects[name] = object
|
36
|
+
self.metaclass.send :define_method, name do
|
37
|
+
@objects[name]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def metaclass
|
45
|
+
class << self
|
46
|
+
self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/task_item.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'Microsoft.Build.Tasks'
|
2
|
+
|
3
|
+
class TaskItem
|
4
|
+
include Microsoft::Build::Framework::ITaskItem
|
5
|
+
attr_accessor :item_spec
|
6
|
+
|
7
|
+
def initialize(str)
|
8
|
+
@item_spec = str
|
9
|
+
@metadata = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def metadata_count
|
13
|
+
return @metadata.length
|
14
|
+
end
|
15
|
+
|
16
|
+
def metadata_names
|
17
|
+
return @metadata.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
return @item_spec
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_metadata(metadata_name) # string => string
|
25
|
+
if @metadata.has_key?(metadata_name)
|
26
|
+
return @metadata[metadata_name]
|
27
|
+
else
|
28
|
+
return ""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_metadata(metadata_name, metadata_value) # string,string => void
|
33
|
+
@metadata[metadata_name] = metadata_value
|
34
|
+
end
|
35
|
+
|
36
|
+
def remove_metadata(metadata_name) # string => void
|
37
|
+
@metadata.delete(metadata_name) if @metadata.has_key?(metadata_name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def copy_metadata_to(destination_item) #itaskitem => void
|
41
|
+
@metadata.each_pair do |key, value|
|
42
|
+
original_metadata = destination_item.get_metadata(key)
|
43
|
+
if original_metadata == nil or original_metadata == ""
|
44
|
+
destination_item.set_metadata(key, value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
original_item_spec = destination_item.get_metadata("OriginalItemSpec")
|
48
|
+
if original_item_spec == nil or original_item_spec == ""
|
49
|
+
destination_item.set_metadata("OriginalItemSpec", @item_spec)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def clone_custom_metadata()# void => IDictionary
|
54
|
+
return Hash.new().merge(@metadata)
|
55
|
+
end
|
56
|
+
end
|
data/lib/task_library.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'task_item'
|
2
|
+
require 'assembly_loader'
|
3
|
+
require 'namespace_node'
|
4
|
+
|
5
|
+
class TaskLibrary
|
6
|
+
attr_reader :tasks
|
7
|
+
|
8
|
+
def self.from_modules(build_engine, *modules)
|
9
|
+
tasks = self.tasks_in_modules(modules)
|
10
|
+
return TaskLibrary.new(build_engine, tasks)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_tasks_file(build_engine, task_file_path)
|
14
|
+
targets = TasksFile.from_file(task_file_path)
|
15
|
+
targets.load_assemblies()
|
16
|
+
|
17
|
+
tasks = targets.task_class_names.map do |class_name|
|
18
|
+
begin
|
19
|
+
ruby_class_name = class_name.gsub(/\./,"::")
|
20
|
+
eval(ruby_class_name)
|
21
|
+
rescue NameError
|
22
|
+
puts "Error loading task class #{ruby_class_name}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
tasks = tasks.delete_if{ |task| task == nil}
|
26
|
+
return TaskLibrary.new(build_engine, tasks)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(build_engine, tasks)
|
30
|
+
@root_namespace = NamespaceNode.new("")
|
31
|
+
@tasks = tasks
|
32
|
+
namespaces = Set.new(@tasks.map{ |cls| cls.to_clr_type.namespace })
|
33
|
+
|
34
|
+
namespaces.each do |namespace|
|
35
|
+
next if namespace.strip.size == 0
|
36
|
+
|
37
|
+
split_namespaces = String.new(namespace).split(".")
|
38
|
+
define_root_namespace_method(split_namespaces[0])
|
39
|
+
|
40
|
+
node = @root_namespace
|
41
|
+
while split_namespaces.size > 0
|
42
|
+
node = node.add_child(split_namespaces.shift)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
@tasks.each do |cls|
|
47
|
+
method_name = cls.to_clr_type.name.to_sym
|
48
|
+
task_namespace = cls.to_clr_type.namespace.split(".")
|
49
|
+
define_execute_method(method_name, build_engine, cls)
|
50
|
+
@root_namespace.add_object(method_name, lambda {|args| execute_method(build_engine, cls, args) }, *task_namespace)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def define_root_namespace_method(namespace)
|
55
|
+
self.metaclass.send :define_method, namespace do
|
56
|
+
@root_namespace.send namespace
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def define_execute_method(method_name, build_engine, cls)
|
61
|
+
self.metaclass.send :define_method, method_name do |args|
|
62
|
+
execute_method(build_engine, cls, args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def execute_method(build_engine, cls, args)
|
67
|
+
args ||= {}
|
68
|
+
instance = cls.new
|
69
|
+
instance.BuildEngine = build_engine
|
70
|
+
|
71
|
+
properties = instance.class.to_clr_type.get_properties
|
72
|
+
|
73
|
+
args.each_pair do |k, v|
|
74
|
+
property = properties.find {|prop| prop.name.downcase == k.to_s.downcase}
|
75
|
+
if property == nil
|
76
|
+
return
|
77
|
+
end
|
78
|
+
value = value_for_property(property, v)
|
79
|
+
|
80
|
+
property.set_value(instance, value, nil)
|
81
|
+
end
|
82
|
+
instance.Execute
|
83
|
+
end
|
84
|
+
|
85
|
+
def value_for_property(property, original_value)
|
86
|
+
itaskitem = Microsoft::Build::Framework::ITaskItem
|
87
|
+
value = original_value
|
88
|
+
if value.kind_of?(Array)
|
89
|
+
value = System::Array.of(itaskitem).new(original_value.map{|item| TaskItem.new(item)})
|
90
|
+
elsif value.kind_of?(String)
|
91
|
+
return_type_name = property.get_get_method.return_type.full_name
|
92
|
+
if return_type_name == "System.String"
|
93
|
+
value = value.to_clr_string
|
94
|
+
else
|
95
|
+
value = System::Array.of(itaskitem).new([value].map{|item| TaskItem.new(item)})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return value
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.tasks_in_modules(modules)
|
102
|
+
itask_interface = Microsoft::Build::Framework::ITask.to_clr_type
|
103
|
+
tasks = []
|
104
|
+
modules.each do |mod|
|
105
|
+
classes = mod.constants.map { |c| mod.class_eval(c) }
|
106
|
+
classes = classes.select do |cls|
|
107
|
+
if !cls.respond_to?(:to_clr_type) || !cls.to_clr_type.respond_to?(:get_interfaces)
|
108
|
+
interfaces = []
|
109
|
+
else
|
110
|
+
interfaces = cls.to_clr_type.get_interfaces
|
111
|
+
end
|
112
|
+
interfaces.include?(itask_interface)
|
113
|
+
end
|
114
|
+
tasks.concat(classes)
|
115
|
+
end
|
116
|
+
return tasks
|
117
|
+
end
|
118
|
+
|
119
|
+
def metaclass
|
120
|
+
class << self
|
121
|
+
self
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/tasks_file.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
require "assembly_loader"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
include REXML
|
6
|
+
|
7
|
+
class TasksFile
|
8
|
+
attr_reader :task_infos, :assembly_file_names, :assembly_names, :task_class_names
|
9
|
+
|
10
|
+
def self.from_xml(xml, file_path = nil)
|
11
|
+
document = Document.new(xml)
|
12
|
+
properties = PropertyGroups.from_xml(xml)
|
13
|
+
|
14
|
+
tasks = document.elements.to_a("Project/UsingTask").map do |element|
|
15
|
+
assembly_file = properties.replace_variables_in(element.attributes["AssemblyFile"])
|
16
|
+
assembly_name = properties.replace_variables_in(element.attributes["AssemblyName"])
|
17
|
+
task_name = properties.replace_variables_in(element.attributes["TaskName"])
|
18
|
+
TaskInfo.new(task_name, assembly_file, assembly_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
return TasksFile.new(tasks, file_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_file(file_path)
|
25
|
+
return self.from_xml(File.read(file_path), file_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(tasks, file_path = nil)
|
29
|
+
@task_infos = tasks
|
30
|
+
@assembly_file_names = Set.new(@task_infos.map {|task| task.assembly_file }).delete(nil)
|
31
|
+
@assembly_names = Set.new(@task_infos.map {|task| task.assembly_name }).delete(nil)
|
32
|
+
@task_class_names = Set.new(@task_infos.map {|task| task.task_name}).delete(nil)
|
33
|
+
@file_path = file_path
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_assemblies()
|
37
|
+
AssemblyLoader.add_path(System::IO::Path.get_directory_name(@file_path)) if @file_path != nil
|
38
|
+
|
39
|
+
@assembly_file_names.each do |assembly_file_name|
|
40
|
+
task_file_directory = System::IO::Path.get_directory_name(assembly_file_name)
|
41
|
+
AssemblyLoader.add_path(task_file_directory)
|
42
|
+
|
43
|
+
assembly_file = System::IO::Path.get_file_name(assembly_file_name)
|
44
|
+
load_assembly(assembly_file)
|
45
|
+
end
|
46
|
+
|
47
|
+
@assembly_names.each do |assembly_name|
|
48
|
+
load_assembly(assembly_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class TaskInfo
|
54
|
+
attr_reader :task_name, :assembly_file, :assembly_name
|
55
|
+
|
56
|
+
def initialize(task_name, assembly_file, assembly_name)
|
57
|
+
@task_name = task_name
|
58
|
+
while assembly_file =~ /\\\\/
|
59
|
+
assembly_file.gsub!(/\\\\/,"\\")
|
60
|
+
end
|
61
|
+
@assembly_file = assembly_file
|
62
|
+
@assembly_name = assembly_name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class PropertyGroups
|
67
|
+
attr_reader :elements
|
68
|
+
|
69
|
+
def self.from_xml(xml)
|
70
|
+
document = Document.new(xml)
|
71
|
+
properties = Hash.new
|
72
|
+
document.elements.each("Project/PropertyGroup/*") do |element|
|
73
|
+
properties[element.name] = element.text.strip
|
74
|
+
end
|
75
|
+
return PropertyGroups.new(properties)
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize(elements)
|
79
|
+
@variable_regexp = /\$\([\w]+\)/
|
80
|
+
@elements = elements
|
81
|
+
elements.each_pair do |key, value|
|
82
|
+
PropertyGroups.class_eval do
|
83
|
+
define_method key.to_sym do ||
|
84
|
+
return replace_variables_in(value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def replace_variables_in(str)
|
91
|
+
replaced_value = str
|
92
|
+
while @variable_regexp.match(replaced_value)
|
93
|
+
match = @variable_regexp.match(replaced_value)
|
94
|
+
full_var = match[0]
|
95
|
+
var_name = full_var[2..-2]
|
96
|
+
if elements.key? var_name
|
97
|
+
replaced_value = replaced_value.sub(full_var, @elements[var_name])
|
98
|
+
else
|
99
|
+
replaced_value = replaced_value.sub(full_var, "")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
return replaced_value
|
103
|
+
end
|
104
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'namespace_node'
|
4
|
+
require 'helper'
|
5
|
+
|
6
|
+
class TestNamespaceNodes < Test::Unit::TestCase
|
7
|
+
def test_node_can_add_children
|
8
|
+
node = NamespaceNode.new "root"
|
9
|
+
node << "child"
|
10
|
+
assert_respond_to node, :child
|
11
|
+
assert_equal node.child.name, "child"
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_node_can_add_sub_children
|
15
|
+
node = NamespaceNode.new "root"
|
16
|
+
node << "child" << "subchild"
|
17
|
+
assert_respond_to node, :child
|
18
|
+
assert_respond_to node.child, :subchild
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_name_can_add_object
|
22
|
+
node = NamespaceNode.new "root"
|
23
|
+
obj = Object.new
|
24
|
+
node.add_object("object", obj)
|
25
|
+
assert_respond_to node, :object
|
26
|
+
assert_equal node.object, obj
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_add_task_to_namespace
|
30
|
+
node = NamespaceNode.new "root"
|
31
|
+
node << "child"
|
32
|
+
obj = Object.new
|
33
|
+
node.add_object("object", obj, "child")
|
34
|
+
|
35
|
+
assert_respond_to node.child, :object
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_add_task_to_subnamespace
|
39
|
+
node = NamespaceNode.new "root"
|
40
|
+
node << "child" << "subchild"
|
41
|
+
obj = Object.new
|
42
|
+
node.add_object("object", obj, "child", "subchild")
|
43
|
+
|
44
|
+
assert_respond_to node.child.subchild, :object
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'build_engine'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'mocha'
|
6
|
+
require 'pathname'
|
7
|
+
require 'stringio'
|
8
|
+
require 'helper'
|
9
|
+
|
10
|
+
module TaskLibraryMixin
|
11
|
+
def build_engine
|
12
|
+
@output = StringIO.new
|
13
|
+
@output = STDOUT
|
14
|
+
@output_logger = Logger.new(@output)
|
15
|
+
return RubyBuildEngine.new(@output_logger)
|
16
|
+
end
|
17
|
+
|
18
|
+
def task_library
|
19
|
+
TaskLibrary.from_tasks_file(build_engine, @tasks_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_has_task (task)
|
23
|
+
assert_respond_to task_library, task
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MSBuildCommunityTasks < Test::Unit::TestCase
|
28
|
+
include TaskLibraryMixin
|
29
|
+
|
30
|
+
def test_loads_assembly_info_task
|
31
|
+
assert_has_task :AssemblyInfo
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_loads_vss_get_task
|
35
|
+
assert_has_task :VssGet
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup
|
39
|
+
@tasks_file = "test/test-libraries/MSBuildCommunityTasks/MSBuild.Community.Tasks.Targets"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class SBF #< Test::Unit::TestCase
|
44
|
+
include TaskLibraryMixin
|
45
|
+
|
46
|
+
def test_loads_biztak_2002_configure_task
|
47
|
+
assert_has_task :Configure
|
48
|
+
end
|
49
|
+
|
50
|
+
def setup
|
51
|
+
@tasks_file = "test/test-libraries/sbf/Microsoft.Sdc.Common.tasks"
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "tasks_file"
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class TestTargetsFile < Test::Unit::TestCase
|
6
|
+
def test_tasks
|
7
|
+
text = <<XML
|
8
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
9
|
+
<UsingTask AssemblyFile="Tasks.dll" TaskName="UpdateDependencies" />
|
10
|
+
</Project>
|
11
|
+
XML
|
12
|
+
|
13
|
+
targets = TasksFile.from_xml(text)
|
14
|
+
assert_equal(1, targets.task_infos.size)
|
15
|
+
task = targets.task_infos[0]
|
16
|
+
assert_equal("Tasks.dll", task.assembly_file)
|
17
|
+
assert_equal("UpdateDependencies", task.task_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_assemblies_are_the_same
|
21
|
+
text = <<XML
|
22
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
23
|
+
<UsingTask AssemblyFile="Tasks.dll" TaskName="UpdateDependencies" />
|
24
|
+
<UsingTask AssemblyFile="Tasks.dll" TaskName="OtherTask" />
|
25
|
+
</Project>
|
26
|
+
XML
|
27
|
+
|
28
|
+
targets = TasksFile.from_xml(text)
|
29
|
+
assert_equal(1, targets.assembly_file_names.size)
|
30
|
+
assert(targets.assembly_file_names.include?("Tasks.dll"))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_assemblies_are_diferent
|
34
|
+
text = <<XML
|
35
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
36
|
+
<UsingTask AssemblyFile="Tasks.dll" TaskName="UpdateDependencies" />
|
37
|
+
<UsingTask AssemblyFile="OtherAssembly.dll" TaskName="OtherTask" />
|
38
|
+
</Project>
|
39
|
+
XML
|
40
|
+
|
41
|
+
targets = TasksFile.from_xml(text)
|
42
|
+
assert_equal(2, targets.assembly_file_names.size)
|
43
|
+
assert(targets.assembly_file_names.include?("Tasks.dll"))
|
44
|
+
assert(targets.assembly_file_names.include?("OtherAssembly.dll"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_tasks_from_msbuild_have_correct_assembly_name
|
48
|
+
directory = System::Runtime::InteropServices::RuntimeEnvironment.get_runtime_directory
|
49
|
+
file_name = "Microsoft.Common.Tasks"
|
50
|
+
full_path = System::IO::Path.combine(directory, file_name)
|
51
|
+
targets = TasksFile.from_file(full_path)
|
52
|
+
|
53
|
+
assert_equal(41, targets.task_infos.size)
|
54
|
+
assert_equal(1, targets.assembly_names.size)
|
55
|
+
tasks_assembly_name = "Microsoft.Build.Tasks, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
|
56
|
+
assert(targets.assembly_names.include?(tasks_assembly_name),
|
57
|
+
" #{targets.assembly_names.to_a} does not include #{tasks_assembly_name}")
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def test_tasks_can_load_msbuild_v3_5_tasks_assembly
|
62
|
+
directory = System::Environment.expand_environment_variables('%WINDIR%\Microsoft.NET\Framework\v3.5')
|
63
|
+
file_name = "Microsoft.Common.Tasks"
|
64
|
+
full_path = System::IO::Path.combine(directory, file_name)
|
65
|
+
targets = TasksFile.from_file(full_path)
|
66
|
+
|
67
|
+
targets.load_assemblies()
|
68
|
+
assert_instance_of(Class, Microsoft::Build::Tasks::AssignProjectConfiguration)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_tasks_with_properties
|
72
|
+
text = <<XML
|
73
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
74
|
+
<PropertyGroup>
|
75
|
+
<property>value</property>
|
76
|
+
</PropertyGroup>
|
77
|
+
<UsingTask AssemblyFile="$(property).Tasks.dll" TaskName="UpdateDependencies" />
|
78
|
+
</Project>
|
79
|
+
XML
|
80
|
+
|
81
|
+
targets = TasksFile.from_xml(text)
|
82
|
+
assert_equal(1, targets.task_infos.size)
|
83
|
+
task = targets.task_infos[0]
|
84
|
+
assert_equal("value.Tasks.dll", task.assembly_file)
|
85
|
+
assert_equal("UpdateDependencies", task.task_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_sdc_task_with_properties
|
89
|
+
text = <<XML
|
90
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
91
|
+
<PropertyGroup>
|
92
|
+
<BuildPath Condition="'$(BuildPath)'==''">$(MSBuildProjectDirectory)\\</BuildPath>
|
93
|
+
<TasksPath Condition="Exists('$(BuildPath)\\bin\\Microsoft.Sdc.Tasks.dll')">$(BuildPath)\\bin\\</TasksPath>
|
94
|
+
</PropertyGroup>
|
95
|
+
<UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.ActiveDirectory.Group.AddUser" />
|
96
|
+
</Project>
|
97
|
+
XML
|
98
|
+
targets = TasksFile.from_xml(text)
|
99
|
+
assert_equal(1, targets.task_infos.size)
|
100
|
+
task = targets.task_infos[0]
|
101
|
+
assert_equal("\\bin\\Microsoft.Sdc.Tasks.dll", task.assembly_file)
|
102
|
+
assert_equal("Microsoft.Sdc.Tasks.ActiveDirectory.Group.AddUser", task.task_name)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class TestTaskInfo < Test::Unit::TestCase
|
107
|
+
def test_task_info_fixes_file_with_two_backslashes
|
108
|
+
task_name = "not relevant"
|
109
|
+
assembly_file = "\\\\bin\\AssemblyFile.dll"
|
110
|
+
assembly_name = "AssemblyFile"
|
111
|
+
task_info = TaskInfo.new(task_name, assembly_file, assembly_name)
|
112
|
+
assert_equal("\\bin\\AssemblyFile.dll", task_info.assembly_file)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_task_info_fixes_file_with_way_too_many_backslashes
|
116
|
+
task_name = "not relevant"
|
117
|
+
assembly_file = "\\subdir\\\\dir\\\\\\bin\\\\\\\\AssemblyFile.dll"
|
118
|
+
assembly_name = "AssemblyFile"
|
119
|
+
task_info = TaskInfo.new(task_name, assembly_file, assembly_name)
|
120
|
+
assert_equal("\\subdir\\dir\\bin\\AssemblyFile.dll", task_info.assembly_file)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class TestPropertyGroupParser < Test::Unit::TestCase
|
125
|
+
def test_simple_property
|
126
|
+
text = <<XML
|
127
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
128
|
+
<PropertyGroup>
|
129
|
+
<propertyName>property value</propertyName>
|
130
|
+
</PropertyGroup>
|
131
|
+
</Project>
|
132
|
+
XML
|
133
|
+
|
134
|
+
properties = PropertyGroups.from_xml(text)
|
135
|
+
assert_equal("property value", properties.propertyName)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_property_defined_in_terms_of_another
|
139
|
+
text = <<XML
|
140
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
141
|
+
<PropertyGroup>
|
142
|
+
<variable>value</variable>
|
143
|
+
<propertyName>property $(variable)</propertyName>
|
144
|
+
</PropertyGroup>
|
145
|
+
</Project>
|
146
|
+
XML
|
147
|
+
|
148
|
+
properties = PropertyGroups.from_xml(text)
|
149
|
+
assert_equal("property value", properties.propertyName)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_property_defined_in_terms_of_another_two
|
153
|
+
text = <<XML
|
154
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
155
|
+
<PropertyGroup>
|
156
|
+
<first>value</first>
|
157
|
+
<second>$(first)</second>
|
158
|
+
<propertyName>property $(second)</propertyName>
|
159
|
+
</PropertyGroup>
|
160
|
+
</Project>
|
161
|
+
XML
|
162
|
+
|
163
|
+
properties = PropertyGroups.from_xml(text)
|
164
|
+
assert_equal("property value", properties.propertyName)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_property_defined_in_terms_of_another_two_jumbled
|
168
|
+
text = <<XML
|
169
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
170
|
+
<PropertyGroup>
|
171
|
+
<second>$(first)</second>
|
172
|
+
<propertyName>property $(second)</propertyName>
|
173
|
+
<first>value</first>
|
174
|
+
</PropertyGroup>
|
175
|
+
</Project>
|
176
|
+
XML
|
177
|
+
|
178
|
+
properties = PropertyGroups.from_xml(text)
|
179
|
+
assert_equal("property value", properties.propertyName)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_properties_can_be_loaded
|
183
|
+
text = <<XML
|
184
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
185
|
+
<PropertyGroup>
|
186
|
+
<weListenTasksPath Condition="'$(weListenTasksPath)' == ''">.</weListenTasksPath>
|
187
|
+
<weListenDependenciesTasksLib>$(weListenTasksPath)\\weListen.Dependencies.Tasks.dll</weListenDependenciesTasksLib>
|
188
|
+
</PropertyGroup>
|
189
|
+
</Project>
|
190
|
+
XML
|
191
|
+
|
192
|
+
PropertyGroups.from_xml(text)
|
193
|
+
end
|
194
|
+
|
195
|
+
"regression"
|
196
|
+
def test_properties_from_sdc
|
197
|
+
text = <<XML
|
198
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
199
|
+
<PropertyGroup>
|
200
|
+
<BuildPath Condition="'$(BuildPath)'==''">$(MSBuildProjectDirectory)\\</BuildPath>
|
201
|
+
<TasksPath Condition="Exists('$(BuildPath)\\bin\\Microsoft.Sdc.Tasks.dll')">$(BuildPath)\\bin\\</TasksPath>
|
202
|
+
</PropertyGroup>
|
203
|
+
</Project>
|
204
|
+
XML
|
205
|
+
|
206
|
+
properties = PropertyGroups.from_xml(text)
|
207
|
+
assert_equal("\\", properties.BuildPath)
|
208
|
+
assert_equal("\\\\bin\\", properties.TasksPath)
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'mocha'
|
4
|
+
require 'task_library'
|
5
|
+
require 'helper'
|
6
|
+
|
7
|
+
module TestNamespace
|
8
|
+
class TestTask
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TaskLibraryNamespaces < Test::Unit::TestCase
|
13
|
+
class MockClass
|
14
|
+
class ClrType
|
15
|
+
attr_reader :name, :namespace
|
16
|
+
def initialize(name, namespace)
|
17
|
+
@name = name
|
18
|
+
@namespace = namespace
|
19
|
+
end
|
20
|
+
end
|
21
|
+
def initialize(name, namespace)
|
22
|
+
@name = name
|
23
|
+
@namespace = namespace
|
24
|
+
end
|
25
|
+
def to_clr_type
|
26
|
+
ClrType.new @name, @namespace
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_task_creates_method
|
31
|
+
tasks = [MockClass.new("test","")]
|
32
|
+
library = TaskLibrary.new(create_mock_engine, tasks)
|
33
|
+
assert_respond_to library, :test
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_different_libraries_should_have_different_tasks
|
37
|
+
tasks = [MockClass.new("first","")]
|
38
|
+
TaskLibrary.new(create_mock_engine, tasks)
|
39
|
+
|
40
|
+
tasks = [MockClass.new("second","")]
|
41
|
+
second_library = TaskLibrary.new(create_mock_engine, tasks)
|
42
|
+
assert_does_not_respond_to second_library, :first
|
43
|
+
assert_respond_to second_library, :second
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def test_task_with_namespace_is_accessible_via_namespaces
|
48
|
+
tasks = [MockClass.new("task","name.space")]
|
49
|
+
|
50
|
+
library = TaskLibrary.new(create_mock_engine, tasks)
|
51
|
+
assert_respond_to library.name.space, :task
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def test_library_has_namespaces_for_task
|
56
|
+
tasks = [MockClass.new("task","name.space")]
|
57
|
+
|
58
|
+
library = TaskLibrary.new(create_mock_engine, tasks)
|
59
|
+
assert_respond_to library.name, :space
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_library_has_two_namespaces
|
63
|
+
tasks = [MockClass.new("task","name.space.first"),
|
64
|
+
MockClass.new("other_task","name.space.second")]
|
65
|
+
|
66
|
+
library = TaskLibrary.new(create_mock_engine, tasks)
|
67
|
+
assert_respond_to library.name.space, :first
|
68
|
+
assert_respond_to library.name.space, :second
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_library_has_single_namespace_for_task
|
72
|
+
tasks = [MockClass.new("task","namespace")]
|
73
|
+
|
74
|
+
library = TaskLibrary.new(create_mock_engine, tasks)
|
75
|
+
assert_respond_to library, :namespace
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def create_mock_engine
|
80
|
+
mock()
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def assert_does_not_respond_to(object, method, message="")
|
85
|
+
full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
|
86
|
+
|
87
|
+
assert_block(full_message) do
|
88
|
+
method.kind_of?(Symbol) || method.respond_to?(:to_str)
|
89
|
+
end
|
90
|
+
full_message = build_message(message, "<?>\nof type <?>\n expected to not respond_to\\\\?<?>.\n", object, object.class, method)
|
91
|
+
assert_block(full_message) { not object.respond_to?(method) }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/test/tests_tasks.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'build_engine'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'mocha'
|
6
|
+
require 'pathname'
|
7
|
+
require 'stringio'
|
8
|
+
require 'helper'
|
9
|
+
|
10
|
+
module MSTaskTestUtil
|
11
|
+
def mstask_for_engine(build_engine)
|
12
|
+
TaskLibrary.from_modules(build_engine, Microsoft::Build::Tasks)
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_ruby_build_engine()
|
16
|
+
@output = StringIO.new
|
17
|
+
@output_logger = Logger.new(@output)
|
18
|
+
return RubyBuildEngine.new(@output_logger)
|
19
|
+
end
|
20
|
+
def mstask_library()
|
21
|
+
mstask_for_engine(default_ruby_build_engine())
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Message < Test::Unit::TestCase
|
26
|
+
include MSTaskTestUtil
|
27
|
+
|
28
|
+
def test_send_event_to_build_engine
|
29
|
+
build_engine = default_ruby_build_engine()
|
30
|
+
build_engine.expects(:log_message_event)
|
31
|
+
|
32
|
+
msbuild = mstask_for_engine(build_engine)
|
33
|
+
msbuild.Message :text => "Text"
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_message_appears_on_output
|
37
|
+
msbuild = mstask_for_engine(default_ruby_build_engine())
|
38
|
+
desired_text = "This is the text we'll be looking for"
|
39
|
+
msbuild.Message :text => desired_text
|
40
|
+
assert_not_nil(Regexp.new(desired_text).match(@output.string),
|
41
|
+
"Text not found in output")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class CommonMsbuildTasksAreLoaded < Test::Unit::TestCase
|
46
|
+
include MSTaskTestUtil
|
47
|
+
|
48
|
+
def test_delete
|
49
|
+
library = mstask_library()
|
50
|
+
assert_respond_to library , :Delete
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_message
|
54
|
+
library = mstask_library()
|
55
|
+
assert_respond_to library , :Message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
class Delete < Test::Unit::TestCase
|
61
|
+
include MSTaskTestUtil
|
62
|
+
|
63
|
+
def test_delete_task_deletes_file
|
64
|
+
build_engine = default_ruby_build_engine()
|
65
|
+
msbuild = mstask_for_engine(build_engine)
|
66
|
+
|
67
|
+
filename = random_filepath()
|
68
|
+
FileUtils.touch filename
|
69
|
+
msbuild.Delete :files => filename
|
70
|
+
|
71
|
+
assert !File.exists?(filename)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_delete_task_deletes_two_files
|
75
|
+
build_engine = default_ruby_build_engine()
|
76
|
+
msbuild = mstask_for_engine(build_engine)
|
77
|
+
|
78
|
+
filenames = [random_filepath(), random_filepath()]
|
79
|
+
filenames.each { |filename| FileUtils.touch filename }
|
80
|
+
msbuild.Delete :files => filenames
|
81
|
+
|
82
|
+
filenames.each { |filename| !File.exists?(filename) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def setup
|
86
|
+
@@directory = "temp"
|
87
|
+
@@r = System::Random.new
|
88
|
+
clean_and_remove_directory()
|
89
|
+
Dir.mkdir(@@directory)
|
90
|
+
end
|
91
|
+
|
92
|
+
def teardown
|
93
|
+
clean_and_remove_directory()
|
94
|
+
end
|
95
|
+
|
96
|
+
def clean_and_remove_directory()
|
97
|
+
if File.exists?(@@directory) and File.directory?(@@directory)
|
98
|
+
FileUtils.remove_dir(@@directory)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def random_filepath
|
104
|
+
number_of_random_chars = 8
|
105
|
+
s = @@directory+"/"
|
106
|
+
number_of_random_chars.times { s << (65 + @@r.Next(26)) }
|
107
|
+
s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class TasksFromTargetFile < Test::Unit::TestCase
|
112
|
+
include MSTaskTestUtil
|
113
|
+
|
114
|
+
|
115
|
+
def test_tasks_from_3_5_targets
|
116
|
+
directory = System::Environment.expand_environment_variables('%WINDIR%\Microsoft.NET\Framework\v3.5')
|
117
|
+
file_name = "Microsoft.Common.Tasks"
|
118
|
+
full_path = System::IO::Path.combine(directory, file_name)
|
119
|
+
build_engine = default_ruby_build_engine()
|
120
|
+
|
121
|
+
task_library = TaskLibrary.from_tasks_file(build_engine, full_path)
|
122
|
+
assert(task_library.respond_to?(:AssignProjectConfiguration),
|
123
|
+
"Task library should have 'AssignAssignProjectConfiguration' task")
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ironbuildrake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bruno Lopes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: !timestamp "2009-12-26 00:00:00 "
|
12
|
+
default_executable:
|
13
|
+
dependencies: []
|
14
|
+
description: ""
|
15
|
+
email: brunomlopes@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README
|
20
|
+
files:
|
21
|
+
- README
|
22
|
+
- Rakefile
|
23
|
+
- VERSION
|
24
|
+
- ironbuildrake.gemspec
|
25
|
+
- lib/Microsoft.Build.Tasks.rb
|
26
|
+
- lib/assembly_loader.rb
|
27
|
+
- lib/build_engine.rb
|
28
|
+
- lib/namespace_node.rb
|
29
|
+
- lib/task_item.rb
|
30
|
+
- lib/task_library.rb
|
31
|
+
- lib/tasks_file.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/brunomlopes/ironbuildrake
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --charset=UTF-8
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: !str 0
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: !str 0
|
51
|
+
version:
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.3.5
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Adds support for using msbuild tasks in ironruby with rake
|
58
|
+
test_files:
|
59
|
+
- test/helper.rb
|
60
|
+
- test/tests_namespace_node.rb
|
61
|
+
- test/tests_other_libraries.rb
|
62
|
+
- test/tests_targets_file.rb
|
63
|
+
- test/tests_tasks.rb
|
64
|
+
- test/tests_task_library.rb
|