File: BooBindingCompilerServices.boo

package info (click to toggle)
monodevelop-boo 2.4-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 528 kB
  • ctags: 57
  • sloc: makefile: 246; xml: 193; sh: 160
file content (183 lines) | stat: -rw-r--r-- 6,818 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#region license
// Copyright (c) 2005, Peter Johanson (latexer@gentoo.org)
// All rights reserved.
//
// BooBinding is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// BooBinding is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with BooBinding; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion

namespace BooBinding

import System
import System.IO
import System.CodeDom.Compiler
import System.Text

import MonoDevelop.Core
import MonoDevelop.Core.ProgressMonitoring
import MonoDevelop.Projects

[extension] #FIXME: workaround BOO-1167
def GetAllReferences (this as ProjectItemCollection) as ProjectReference*:
	for item in this:
		yield item if item isa ProjectReference

[extension] #FIXME: workaround BOO-1167
def GetAllFiles (this as ProjectItemCollection) as ProjectFile*:
	for item in this:
		yield item if item isa ProjectFile

public class BooBindingCompilerServices:
	
	public def CanCompile (fileName as string):
		return Path.GetExtension (fileName).ToUpper () == ".BOO"
	
	def Compile (projectItems as ProjectItemCollection, configuration as DotNetProjectConfiguration, configurationSelector as ConfigurationSelector, monitor as IProgressMonitor) as BuildResult:
		compilerparameters = cast (BooCompilerParameters, configuration.CompilationParameters)
		if compilerparameters is null:
			compilerparameters = BooCompilerParameters ()
		#we get the compiler target to be used
		compilerTarget as string = "exe"
		
		if configuration.CompileTarget == CompileTarget.Exe:
			compilerTarget = "exe"
		elif configuration.CompileTarget == CompileTarget.Library:
			compilerTarget = "library"
		elif configuration.CompileTarget == CompileTarget.WinExe:
			compilerTarget = "winexe"
		
		parameters as StringBuilder = StringBuilder (
			"-o:${configuration.CompiledOutputName} -t:${compilerTarget}")
		
		#we decide if we want to use ducks
		if 	compilerparameters.Ducky:
			parameters.Append (" -ducky ")
			
		#we decide if we are going to define the debug var
		if configuration.DebugMode:
			parameters.Append (" -debug+ ")
		else:
			parameters.Append (" -debug- ")
			
		if configuration.EnvironmentVariables.Keys.Count > 0:
			parameters.Append (" -define: ")
			
		#we loop through the defines and add them to the list
		for currentDefine in configuration.EnvironmentVariables.Keys:
			defineValue = ""
			if configuration.EnvironmentVariables.TryGetValue (currentDefine, defineValue):
				if not defineValue == String.Empty:
					parameters.Append ("${currentDefine}=${defineValue},")
				else:
					parameters.Append ("${currentDefine},")
				
		#we need to remove the last comma added in the loop
		if configuration.EnvironmentVariables.Keys.Count > 0:
			parameters.Remove (parameters.ToString ().LastIndexOf (","),1)
		
		#we add the different references
		for lib as ProjectReference in projectItems.GetAllReferences ():
			for fileName as string in lib.GetReferencedFileNames (configurationSelector):
				parameters.Append (" -reference:${fileName} ")
				
		for finfo as ProjectFile in projectItems.GetAllFiles ():
			if finfo.Subtype != Subtype.Directory:
				if finfo.BuildAction == BuildAction.Compile:
					parameters.Append (" ${finfo.FilePath} ")
				elif finfo.BuildAction == BuildAction.EmbeddedResource:
					parameters.Append ("  -resource:${finfo.FilePath}[${finfo.ResourceId}]")

		# if the assembly is signed we point to the file
		if configuration.SignAssembly:
			parameters.Append (" -keyfile: ${configuration.AssemblyKeyFile} ")
			
		# we check if the project is going to be using a strong signature and let the 
		# compiler know where to find it
		
		tf = TempFileCollection ()
		compilationOutput = DoCompilation (monitor, parameters.ToString (), configuration.OutputDirectory )
		return ParseOutput (tf, compilationOutput)
		

	private def DoCompilation (monitor as IProgressMonitor, parameters as string, outputDir as string):
		try:
			
			swError = StringWriter ()
			chainedError as LogTextWriter = LogTextWriter ()
			chainedError.ChainWriter (monitor.Log)
			chainedError.ChainWriter (swError);
			
			swLog =  StringWriter ()
			chainedLogs as LogTextWriter = LogTextWriter ()
			chainedLogs.ChainWriter (swLog);
			
			operationMonitor = AggregatedOperationMonitor (monitor)
			monitor.Log.WriteLine (GettextCatalog.GetString ("Starting Boo compilation"))
			monitor.Log.WriteLine ("booc ${parameters}")
			
			#we create a new process that will be used to execute the command line of the compiler
			wrapper =  MonoDevelop.Core.Runtime.ProcessService.StartProcess ("booc",parameters ,
				Path.GetDirectoryName (outputDir),chainedError , chainedLogs, null)
			
			#we take care of cancelation
			operationMonitor.AddOperation (wrapper);
			wrapper.WaitForOutput ();
			exitCode = wrapper.ExitCode
			
			if monitor.IsCancelRequested:
				monitor.Log.WriteLine (GettextCatalog.GetString ("Build cancelled"))
				monitor.ReportError (GettextCatalog.GetString ("Build cancelled"), null)
				if exitCode == 0:
					exitCode = -1
					
			error = swLog.ToString ()
			return error
		ensure:
			#we get rid of this guys
			wrapper.Dispose ()
			swError.Close ()
			chainedError.Close ()
			operationMonitor.Dispose ()
			monitor.EndTask ()
			swLog.Close ()
		
	def ParseOutput (tf as TempFileCollection , errors as string):
		cr = CompilerResults (tf)
		# we read the errors line by line to get them in the monodevelop list
		reader = StringReader (errors);
		nextError as string
		
		while (nextError = reader. ReadLine()) != null:
			error = ParseErrorLine(nextError)
			if not error is null:
				cr.Errors.Insert (0,error)
			
		reader.Close ();
		return BuildResult (cr, null)
	
	private def ParseErrorLine(errorLine as string) as System.CodeDom.Compiler.CompilerError:
		error = System.CodeDom.Compiler.CompilerError()
		#errors are of the form "file(row, column):ErrorNum:Type:message"
		data = @/(?<file>.*\.boo)\s*\((?<row>\d+),\s?(?<column>\d+)\):\s*(?<message>.*)/.Matches (errorLine)
		if data.Count > 0:
			error.ErrorText = data[0].Groups["message"].Value
			error.FileName = data[0].Groups["file"].Value
			error.Line = int.Parse (data[0].Groups["row"].Value)
			error.Column = int.Parse (data[0].Groups["column"].Value)
			if error.ErrorText.Contains ("WARNING"):
				error.IsWarning = true
			return error
		else:
			return null