ironbuildrake 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -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,8 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ class Test::Unit::TestCase
8
+ end
@@ -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
@@ -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