[MonoDevelop] BooBinding patch bug 324223

Manuel de la Pena mandel at themacaque.com
Tue Mar 17 13:40:05 EDT 2009


Hello there,

Here is the patch I have been working on to shell the Boo compilation
allowing to recompile without having problems because the compilation
loaded assemblies to the AppDomain
(https://bugzilla.novell.com/show_bug.cgi?id=324223)

I hope it helps.

Kr,

manuel => mandel

PS: Thanks to Tak and mhutch at IRC... I must have been a pain in the
ass, in my defense is my  first monodevelop patch :P
-------------- next part --------------
Index: BooBindingCompilerServices.boo
===================================================================
--- BooBindingCompilerServices.boo	(revision 129338)
+++ BooBindingCompilerServices.boo	(working copy)
@@ -20,19 +20,15 @@
 namespace BooBinding
 
 import System
-import System.Diagnostics
 import System.IO
 import System.CodeDom.Compiler
 import System.Text
-import System.Reflection
+import System.Text.RegularExpressions
 
-import MonoDevelop.Core.Gui.Components
 import MonoDevelop.Core
+import MonoDevelop.Core.ProgressMonitoring
 import MonoDevelop.Projects
 
-import Boo.Lang.Compiler
-import Boo.Lang.Compiler.Resources
-
 [extension] #FIXME: workaround BOO-1167
 def GetAllReferences (this as ProjectItemCollection) as ProjectReference*:
 	for item in this:
@@ -45,6 +41,14 @@
 
 
 public class BooBindingCompilerServices:
+
+	#region Private variables
+	
+	#we use a static string builder to be able to read the ouput from the compiler process
+	private static _output as StringBuilder = StringBuilder()
+	
+	#endregion
+	
 	public def CanCompile (fileName as string):
 		return Path.GetExtension(fileName).ToUpper() == ".BOO"
 	
@@ -52,77 +56,111 @@
 		compilerparameters = cast(BooCompilerParameters, configuration.CompilationParameters)
 		if compilerparameters is null:
 			compilerparameters = BooCompilerParameters()
+		#we get the compiler target to be used
+		compilerTarget as string = "exe"
 		
-		// FIXME: Use outdir 'configuration.OutputDirectory'
-		compiler = Boo.Lang.Compiler.BooCompiler()
-		compiler.Parameters.Pipeline = Pipelines.CompileToFile()
-
-		compiler.Parameters.Debug = configuration.DebugMode
-		compiler.Parameters.OutputAssembly = configuration.CompiledOutputName
-		compiler.Parameters.Ducky = compilerparameters.Ducky
-
-		# Make sure we don't load the generated assembly at all
-		compiler.Parameters.GenerateInMemory = false
-
+		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(" -define:DEBUG ")
+			
+		#we add the different references
 		for lib as ProjectReference in projectItems.GetAllReferences ():
 			for fileName as string in lib.GetReferencedFileNames (configuration.Id):
-				compiler.Parameters.References.Add(Assembly.LoadFile(fileName))
-
+				parameters.Append(" -reference:${fileName} ")
+				
 		for finfo as ProjectFile in projectItems.GetAllFiles ():
 			if finfo.Subtype != Subtype.Directory:
 				if finfo.BuildAction == BuildAction.Compile:
-					compiler.Parameters.Input.Add(Boo.Lang.Compiler.IO.FileInput(finfo.Name))
+					parameters.Append(" ${finfo.FilePath} ")
 				elif finfo.BuildAction == BuildAction.EmbeddedResource:
-					compiler.Parameters.Resources.Add (EmbeddedFileResource (finfo.Name))
+					parameters.Append("  -resource:${finfo.FilePath}")
 
+		tf = TempFileCollection ()
+		compilationOutput = DoCompilation (monitor, parameters.ToString(), configuration.OutputDirectory )
+		monitor.Log.WriteLine(GettextCatalog.GetString("Parsing output"))
+		return ParseOutput (tf, compilationOutput)
 		
-		if configuration.CompileTarget == CompileTarget.Exe:
-			compiler.Parameters.OutputType = CompilerOutputType.ConsoleApplication
-		elif configuration.CompileTarget == CompileTarget.Library:
-			compiler.Parameters.OutputType = CompilerOutputType.Library
-		elif configuration.CompileTarget == CompileTarget.WinExe:
-			compiler.Parameters.OutputType = CompilerOutputType.WindowsApplication
 
-		tf = TempFileCollection ()
-		context = DoCompilation (monitor, compiler)
-		cr = ParseOutput (tf, context)
-		return cr
-
-	private def DoCompilation (monitor as IProgressMonitor, compiler as Boo.Lang.Compiler.BooCompiler):
+	private def DoCompilation (monitor as IProgressMonitor, parameters as string, outpurDir as string):
 		try:
-			monitor.BeginTask (null, 2)
-			monitor.Log.WriteLine ("Compiling Boo source code ...")
-			context = compiler.Run()
-			monitor.Step (1)
-			return context
+			
+			swError = StringWriter ()
+			chainedError as LogTextWriter = LogTextWriter()
+			chainedError.ChainWriter(monitor.Log)
+			chainedError.ChainWriter(swError);
+			
+			operationMonitor = AggregatedOperationMonitor(monitor)
+			monitor.Log.WriteLine(GettextCatalog.GetString("Starting Boo compilation"))
+			monitor.Log.WriteLine(GettextCatalog.GetString("booc ${parameters}"))
+			
+			#we need to redirect the error output to the stdout to make sure we can use it correctly
+			System.Console.SetError(swError)
+			
+			#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(outpurDir),monitor.Log, chainedError, 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 = swError.ToString()
+			return error
 		ensure:
+			#we get rid of this guys
+			wrapper.Dispose()
+			swError.Close()
+			chainedError.Close ()
+			operationMonitor.Dispose ()
 			monitor.EndTask()
 		
-	def ParseOutput (tf as TempFileCollection , context as CompilerContext) as BuildResult:
+	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
 		
-		for err as Boo.Lang.Compiler.CompilerError in context.Errors:
-			cerror = System.CodeDom.Compiler.CompilerError ()
-			cerror.ErrorText = err.Code + ": " + err.Message
-
-			if err.LexicalInfo is not null:
-				SetErrorLexicalInfo (cerror, err.LexicalInfo)
-
-			cr.Errors.Add(cerror)
-
-		for warning as CompilerWarning in context.Warnings:
-			cerror = System.CodeDom.Compiler.CompilerError ()
-			cerror.ErrorText = warning.Code + ": " + warning.Message
-
-			if warning.LexicalInfo is not null:
-				SetErrorLexicalInfo (cerror, warning.LexicalInfo)
-
-			cerror.IsWarning = true
-			cr.Errors.Add(cerror)
-
+		while (nextError = reader.ReadLine()) != null:
+			error = ParseErrorLine(nextError)
+			if not error is null:
+				cr.Errors.Insert(0,error)
+			
+		reader.Close ();
 		return BuildResult (cr, null)
 	
-	def SetErrorLexicalInfo (error as System.CodeDom.Compiler.CompilerError, lexicalInfo as Boo.Lang.Compiler.Ast.LexicalInfo):
-		error.FileName = lexicalInfo.FileName 
-		error.Column = lexicalInfo.Column
-		error.Line = lexicalInfo.Line
+	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
+	
\ No newline at end of file


More information about the Monodevelop-list mailing list