ironbuildrake 0.1.1-ironruby

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 ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,74 @@
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.platform = "ironruby"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/test_*.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+
47
+ task :default => :test
48
+
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "ironbuildrake #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
58
+
59
+ # task :default => [:test_units]
60
+
61
+ desc "this is just a quick smoke test"
62
+ task :test do
63
+ msbuild = tasks_from_module(Microsoft::Build::Tasks)
64
+ msbuild.Message :text => "This is a text message"
65
+ msbuild.Warning :text => "This is a warning"
66
+ end
67
+
68
+ desc "Run unit tests"
69
+ Rake::TestTask.new("test_units") do |t|
70
+ t.libs << "test"
71
+ t.pattern = 'test/tests_*.rb'
72
+ t.verbose = true
73
+ t.warning = true
74
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,56 @@
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.1"
9
+ s.platform = %q{ironruby}
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.authors = ["Bruno Lopes"]
13
+ s.date = %q{2009-12-26}
14
+ s.description = %q{}
15
+ s.email = %q{brunomlopes@gmail.com}
16
+ s.extra_rdoc_files = [
17
+ "README"
18
+ ]
19
+ s.files = [
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "ironbuildrake.gemspec",
24
+ "lib/Microsoft.Build.Tasks.rb",
25
+ "lib/assembly_loader.rb",
26
+ "lib/build_engine.rb",
27
+ "lib/namespace_node.rb",
28
+ "lib/task_item.rb",
29
+ "lib/task_library.rb",
30
+ "lib/tasks_file.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/brunomlopes/ironbuildrake}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.5}
36
+ s.summary = %q{Adds support for using msbuild tasks in ironruby with rake}
37
+ s.test_files = [
38
+ "test/helper.rb",
39
+ "test/tests_namespace_node.rb",
40
+ "test/tests_other_libraries.rb",
41
+ "test/tests_targets_file.rb",
42
+ "test/tests_tasks.rb",
43
+ "test/tests_task_library.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
56
+
@@ -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.1
5
+ platform: ironruby
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